forked from axiom-team/gecko
779 lines
22 KiB
Dart
779 lines
22 KiB
Dart
// ignore_for_file: avoid_print
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:gecko/globals.dart';
|
|
import 'package:gecko/models/chest_data.dart';
|
|
import 'package:gecko/models/wallet_data.dart';
|
|
import 'package:gecko/providers/home.dart';
|
|
import 'package:gecko/providers/my_wallets.dart';
|
|
import 'package:polkawallet_sdk/api/apiKeyring.dart';
|
|
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
|
import 'package:polkawallet_sdk/api/types/txInfoData.dart';
|
|
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
|
|
import 'package:polkawallet_sdk/storage/keyring.dart';
|
|
import 'package:polkawallet_sdk/storage/types/keyPairData.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:truncate/truncate.dart';
|
|
// import 'package:web_socket_channel/io.dart';
|
|
|
|
class SubstrateSdk with ChangeNotifier {
|
|
final int ss58 = 42;
|
|
|
|
final WalletSDK sdk = WalletSDK();
|
|
final Keyring keyring = Keyring();
|
|
String generatedMnemonic = '';
|
|
bool sdkReady = false;
|
|
bool sdkLoading = false;
|
|
bool nodeConnected = false;
|
|
bool importIsLoading = false;
|
|
int blocNumber = 0;
|
|
bool isLoadingEndpoint = false;
|
|
String debugConnection = '';
|
|
String transactionStatus = '';
|
|
|
|
TextEditingController jsonKeystore = TextEditingController();
|
|
TextEditingController keystorePassword = TextEditingController();
|
|
|
|
Future<void> initApi() async {
|
|
sdkLoading = true;
|
|
await keyring.init([ss58]);
|
|
keyring.setSS58(ss58);
|
|
|
|
await sdk.init(keyring);
|
|
sdkReady = true;
|
|
sdkLoading = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<void> connectNode(BuildContext ctx) async {
|
|
List<NetworkParams> node = [];
|
|
HomeProvider _homeProvider = Provider.of<HomeProvider>(ctx, listen: false);
|
|
|
|
// var connectivityResult = await (Connectivity().checkConnectivity());
|
|
// if (connectivityResult == ConnectivityResult.mobile ||
|
|
// connectivityResult == ConnectivityResult.wifi) {
|
|
// _homeProvider.changeMessage("Vous n'êtes pas connecté à internet", 0);
|
|
// return;
|
|
// }
|
|
_homeProvider.changeMessage("connectionPending".tr(), 0);
|
|
|
|
for (String _endpoint in configBox.get('endpoint')) {
|
|
final n = NetworkParams();
|
|
n.name = currencyName;
|
|
n.endpoint = _endpoint;
|
|
n.ss58 = ss58;
|
|
node.add(n);
|
|
}
|
|
int timeout = 10000;
|
|
|
|
// if (n.endpoint!.startsWith('ws://')) {
|
|
// timeout = 5000;
|
|
// }
|
|
|
|
//// Check websocket conenction - only for wss
|
|
// final channel = IOWebSocketChannel.connect(
|
|
// Uri.parse('wss://192.168.1.72:9944'),
|
|
// );
|
|
|
|
// channel.stream.listen(
|
|
// (dynamic message) {
|
|
// log.d('message $message');
|
|
// },
|
|
// onDone: () {
|
|
// log.d('ws channel closed');
|
|
// },
|
|
// onError: (error) {
|
|
// log.d('ws error $error');
|
|
// },
|
|
// );
|
|
|
|
if (sdk.api.connectedNode?.endpoint != null) {
|
|
await sdk.api.setting.unsubscribeBestNumber();
|
|
}
|
|
|
|
isLoadingEndpoint = true;
|
|
notifyListeners();
|
|
final res = await sdk.api.connectNode(keyring, node).timeout(
|
|
Duration(milliseconds: timeout),
|
|
onTimeout: () => null,
|
|
);
|
|
isLoadingEndpoint = false;
|
|
notifyListeners();
|
|
if (res != null) {
|
|
nodeConnected = true;
|
|
|
|
// Subscribe bloc number
|
|
sdk.api.setting.subscribeBestNumber((res) {
|
|
blocNumber = int.parse(res.toString());
|
|
// log.d(sdk.api.connectedNode?.endpoint);
|
|
if (sdk.api.connectedNode?.endpoint == null) {
|
|
nodeConnected = false;
|
|
_homeProvider.changeMessage("networkLost".tr(), 0);
|
|
} else {
|
|
nodeConnected = true;
|
|
}
|
|
notifyListeners();
|
|
});
|
|
|
|
// currencyName = await getCurencyName();
|
|
notifyListeners();
|
|
_homeProvider.changeMessage(
|
|
"wellConnectedToNode"
|
|
.tr(args: [getConnectedEndpoint()!.split('/')[2]]),
|
|
5);
|
|
// snackNode(ctx, true);
|
|
} else {
|
|
nodeConnected = false;
|
|
debugConnection = res.toString();
|
|
notifyListeners();
|
|
_homeProvider.changeMessage("noDuniterEndointAvailable".tr(), 0);
|
|
// snackNode(ctx, false);
|
|
}
|
|
|
|
log.d(sdk.api.connectedNode?.endpoint);
|
|
}
|
|
|
|
Future<String> importAccount(
|
|
{String mnemonic = '',
|
|
bool fromMnemonic = false,
|
|
String derivePath = '',
|
|
String password = ''}) async {
|
|
// toy exercise immense month enter answer table prefer speed cycle gold phone
|
|
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
|
|
if (mnemonic != '') {
|
|
fromMnemonic = true;
|
|
generatedMnemonic = mnemonic;
|
|
} else if (clipboardData!.text!.split(' ').length == 12) {
|
|
fromMnemonic = true;
|
|
generatedMnemonic = clipboardData.text!;
|
|
}
|
|
|
|
if (password == '') {
|
|
password = keystorePassword.text;
|
|
}
|
|
|
|
final KeyType keytype;
|
|
final String keyToImport;
|
|
if (fromMnemonic) {
|
|
keytype = KeyType.mnemonic;
|
|
keyToImport = generatedMnemonic;
|
|
} else {
|
|
keytype = KeyType.keystore;
|
|
keyToImport = jsonKeystore.text.replaceAll("'", "\\'");
|
|
}
|
|
|
|
importIsLoading = true;
|
|
notifyListeners();
|
|
if (clipboardData?.text != null) jsonKeystore.text = clipboardData!.text!;
|
|
var json = await sdk.api.keyring
|
|
.importAccount(keyring,
|
|
keyType: keytype,
|
|
key: keyToImport,
|
|
name: derivePath,
|
|
password: password,
|
|
derivePath: derivePath,
|
|
cryptoType: CryptoType.sr25519)
|
|
.catchError((e) {
|
|
importIsLoading = false;
|
|
notifyListeners();
|
|
});
|
|
if (json == null) return '';
|
|
print(json);
|
|
try {
|
|
await sdk.api.keyring.addAccount(
|
|
keyring,
|
|
keyType: keytype,
|
|
acc: json,
|
|
password: password,
|
|
);
|
|
// Clipboard.setData(ClipboardData(text: jsonEncode(acc.toJson())));
|
|
} catch (e) {
|
|
print(e);
|
|
importIsLoading = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
importIsLoading = false;
|
|
|
|
notifyListeners();
|
|
return keyring.allAccounts.last.address!;
|
|
}
|
|
|
|
void reload() {
|
|
notifyListeners();
|
|
}
|
|
|
|
Future<List<AddressInfo>> getKeyStoreAddress() async {
|
|
List<AddressInfo> result = [];
|
|
|
|
// sdk.api.account.unsubscribeBalance();
|
|
for (var element in keyring.allAccounts) {
|
|
// Clipboard.setData(ClipboardData(text: jsonEncode(element)));
|
|
final account = AddressInfo(address: element.address);
|
|
// await sdk.api.account.subscribeBalance(element.address, (p0) {
|
|
// account.balance = int.parse(p0.freeBalance) / 100;
|
|
// });
|
|
// sdk.api.setting.unsubscribeBestNumber();
|
|
account.balance = await getBalance(element.address!);
|
|
result.add(account);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Future<List<int>> getCerts(String address) async {
|
|
final idtyIndex = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$address")');
|
|
// log.d('u32: ' + idtyIndex.toString());
|
|
|
|
final _certsReceiver = await sdk.webView!
|
|
.evalJavascript('api.query.cert.storageIdtyCertMeta($idtyIndex)') ??
|
|
[];
|
|
|
|
return [_certsReceiver['receivedCount'], _certsReceiver['issuedCount']];
|
|
}
|
|
|
|
Future<Map> getCertData(String from, String to) async {
|
|
final idtyIndexFrom = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$from")');
|
|
|
|
final idtyIndexTo = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$to")');
|
|
|
|
final _certData = await sdk.webView!.evalJavascript(
|
|
'api.query.cert.storageCertsByIssuer($idtyIndexFrom, $idtyIndexTo)') ??
|
|
'';
|
|
|
|
if (_certData == '') return {};
|
|
|
|
// log.d(_certData);
|
|
return _certData;
|
|
}
|
|
|
|
Future<bool> hasAccountConsumers(String address) async {
|
|
final _accountInfo = await sdk.webView!
|
|
.evalJavascript('api.query.system.account("$address")');
|
|
final _consumers = _accountInfo['consumers'];
|
|
// log.d('Consumers: $_consumers');
|
|
return _consumers == 0 ? false : true;
|
|
}
|
|
|
|
Future<double> getBalance(String address, {bool isUd = false}) async {
|
|
double balance = 0.0;
|
|
// log.d('nodeConnected: ' + nodeConnected.toString());
|
|
if (nodeConnected) {
|
|
final brutBalance = await sdk.api.account.queryBalance(address);
|
|
balance = int.parse(brutBalance!.freeBalance) / 100;
|
|
} else {
|
|
balance = -1;
|
|
}
|
|
return balance;
|
|
}
|
|
|
|
Future<double> subscribeBalance(String address, {bool isUd = false}) async {
|
|
double balance = 0.0;
|
|
if (nodeConnected) {
|
|
await sdk.api.account.subscribeBalance(address, (_balance) {
|
|
balance = int.parse(_balance.freeBalance) / 100;
|
|
notifyListeners();
|
|
});
|
|
}
|
|
|
|
return balance;
|
|
}
|
|
|
|
KeyPairData getKeypair(String address) {
|
|
return keyring.keyPairs.firstWhere((kp) => kp.address == address,
|
|
orElse: (() => KeyPairData()));
|
|
}
|
|
|
|
Future<bool> checkPassword(String address, String pass) async {
|
|
final account = getKeypair(address);
|
|
// log.d(account.address);
|
|
|
|
return await sdk.api.keyring.checkPassword(account, pass);
|
|
}
|
|
|
|
Future<String> getSeed(String address, String _pin) async {
|
|
final account = getKeypair(address);
|
|
keyring.setCurrent(account);
|
|
|
|
final _seed = await sdk.api.keyring.getDecryptedSeed(keyring, _pin);
|
|
|
|
String _seedText;
|
|
if (_seed == null) {
|
|
_seedText = '';
|
|
} else {
|
|
_seedText = _seed.seed!.split('//')[0];
|
|
}
|
|
|
|
log.d(_seedText);
|
|
return _seedText;
|
|
}
|
|
|
|
int getDerivationNumber(String address) {
|
|
final account = getKeypair(address);
|
|
final deriveNbr = account.name!.split('//')[1];
|
|
return int.parse(deriveNbr);
|
|
}
|
|
|
|
Future<KeyPairData?> changePassword(BuildContext context, String address,
|
|
String passOld, String? passNew) async {
|
|
final account = getKeypair(address);
|
|
MyWalletsProvider _myWalletProvider =
|
|
Provider.of<MyWalletsProvider>(context, listen: false);
|
|
keyring.setCurrent(account);
|
|
_myWalletProvider.resetPinCode();
|
|
|
|
return await sdk.api.keyring.changePassword(keyring, passOld, passNew);
|
|
}
|
|
|
|
Future<void> deleteAllAccounts() async {
|
|
for (var account in keyring.allAccounts) {
|
|
await sdk.api.keyring.deleteAccount(keyring, account);
|
|
}
|
|
}
|
|
|
|
Future<void> deleteAccounts(List<String> address) async {
|
|
for (var a in address) {
|
|
final account = getKeypair(a);
|
|
await sdk.api.keyring.deleteAccount(keyring, account);
|
|
}
|
|
}
|
|
|
|
Future<String> generateMnemonic({String lang = appLang}) async {
|
|
final gen = await sdk.api.keyring.generateMnemonic(ss58);
|
|
generatedMnemonic = gen.mnemonic!;
|
|
|
|
// final res = await importAccount(fromMnemonic: true);
|
|
// await Clipboard.setData(ClipboardData(text: generatedMnemonic));
|
|
return gen.mnemonic!;
|
|
}
|
|
|
|
Future<String> setCurrentWallet(WalletData _wallet) async {
|
|
final currentChestNumber = configBox.get('currentChest');
|
|
ChestData _newChestData = chestBox.get(currentChestNumber)!;
|
|
_newChestData.defaultWallet = _wallet.number;
|
|
await chestBox.put(currentChestNumber, _newChestData);
|
|
|
|
try {
|
|
final acc = getKeypair(_wallet.address!);
|
|
keyring.setCurrent(acc);
|
|
return acc.address!;
|
|
} catch (e) {
|
|
return (e.toString());
|
|
}
|
|
}
|
|
|
|
KeyPairData getCurrentWallet() {
|
|
try {
|
|
final acc = keyring.current;
|
|
return acc;
|
|
} catch (e) {
|
|
return KeyPairData();
|
|
}
|
|
}
|
|
|
|
Future<String> pay(
|
|
{required String fromAddress,
|
|
required String destAddress,
|
|
required double amount,
|
|
required String password}) async {
|
|
transactionStatus = '';
|
|
|
|
// setCurrentWallet(fromAddress);
|
|
|
|
log.d(keyring.current.address);
|
|
log.d(fromAddress);
|
|
log.d(password);
|
|
// log.d(await checkPassword(fromAddress, password));
|
|
|
|
final fromPubkey = await sdk.api.account.decodeAddress([fromAddress]);
|
|
log.d(fromPubkey!.keys.first);
|
|
final sender = TxSenderData(
|
|
fromAddress,
|
|
fromPubkey.keys.first,
|
|
);
|
|
final txInfo = TxInfoData(
|
|
'balances', amount == -1 ? 'transferAll' : 'transferKeepAlive', sender);
|
|
|
|
final int amountUnit = (amount * 100).toInt();
|
|
try {
|
|
final hash = await sdk.api.tx.signAndSend(
|
|
txInfo,
|
|
[destAddress, amount == -1 ? false : amountUnit],
|
|
password,
|
|
onStatusChange: (status) {
|
|
log.d('Transaction status: ' + status);
|
|
transactionStatus = status;
|
|
notifyListeners();
|
|
},
|
|
).timeout(
|
|
const Duration(seconds: 12),
|
|
onTimeout: () => {},
|
|
);
|
|
log.d(hash.toString());
|
|
if (hash.isEmpty) {
|
|
transactionStatus = 'timeout';
|
|
notifyListeners();
|
|
|
|
return 'timeout';
|
|
} else {
|
|
transactionStatus = hash.toString();
|
|
notifyListeners();
|
|
return hash.toString();
|
|
}
|
|
} catch (e) {
|
|
transactionStatus = e.toString();
|
|
notifyListeners();
|
|
return e.toString();
|
|
}
|
|
}
|
|
|
|
Future<String> certify(
|
|
String fromAddress, String password, String toAddress) async {
|
|
transactionStatus = '';
|
|
|
|
// setCurrentWallet(fromAddress);
|
|
log.d('me: ' + fromAddress);
|
|
log.d('to: ' + toAddress);
|
|
|
|
final _myIdtyStatus = await idtyStatus(fromAddress);
|
|
final _toIdtyStatus = await idtyStatus(toAddress);
|
|
|
|
log.d(_myIdtyStatus);
|
|
log.d(_toIdtyStatus);
|
|
|
|
if (_myIdtyStatus != 'Validated') {
|
|
transactionStatus = 'notMember';
|
|
notifyListeners();
|
|
return 'notMember';
|
|
}
|
|
|
|
final sender = TxSenderData(
|
|
keyring.current.address,
|
|
keyring.current.pubKey,
|
|
);
|
|
TxInfoData txInfo;
|
|
|
|
if (_toIdtyStatus == 'noid') {
|
|
txInfo = TxInfoData(
|
|
'identity',
|
|
'createIdentity',
|
|
sender,
|
|
);
|
|
} else if (_toIdtyStatus == 'Validated' ||
|
|
_toIdtyStatus == 'ConfirmedByOwner') {
|
|
txInfo = TxInfoData(
|
|
'cert',
|
|
'addCert',
|
|
sender,
|
|
);
|
|
} else {
|
|
transactionStatus = 'cantBeCert';
|
|
notifyListeners();
|
|
return 'cantBeCert';
|
|
}
|
|
|
|
log.d('Cert action: ' + txInfo.call!);
|
|
|
|
try {
|
|
final hash = await sdk.api.tx
|
|
.signAndSend(
|
|
txInfo,
|
|
[toAddress],
|
|
password,
|
|
)
|
|
.timeout(
|
|
const Duration(seconds: 12),
|
|
onTimeout: () => {},
|
|
);
|
|
log.d(hash);
|
|
if (hash.isEmpty) {
|
|
transactionStatus = 'timeout';
|
|
notifyListeners();
|
|
|
|
return 'timeout';
|
|
} else {
|
|
transactionStatus = hash.toString();
|
|
notifyListeners();
|
|
return hash.toString();
|
|
}
|
|
} catch (e) {
|
|
transactionStatus = e.toString();
|
|
notifyListeners();
|
|
return e.toString();
|
|
}
|
|
}
|
|
|
|
Future<String> idtyStatus(String address, [bool smooth = true]) async {
|
|
// var tata = await sdk.webView!
|
|
// .evalJavascript('api.query.system.account("$address")');
|
|
|
|
var idtyIndex = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$address")');
|
|
|
|
if (idtyIndex == null) {
|
|
return 'noid';
|
|
}
|
|
|
|
final idtyStatus = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identities($idtyIndex)');
|
|
|
|
if (idtyStatus != null) {
|
|
final String _status = idtyStatus['status'];
|
|
// log.d('Status $address: $_status');
|
|
return (_status);
|
|
} else {
|
|
return 'expired';
|
|
}
|
|
}
|
|
|
|
Future<String> confirmIdentity(
|
|
String fromAddress, String name, String password) async {
|
|
// Confirm identity
|
|
// setCurrentWallet(fromAddress);
|
|
log.d('me: ' + keyring.current.address!);
|
|
|
|
final sender = TxSenderData(
|
|
keyring.current.address,
|
|
keyring.current.pubKey,
|
|
);
|
|
|
|
final txInfo = TxInfoData(
|
|
'identity',
|
|
'confirmIdentity',
|
|
sender,
|
|
);
|
|
|
|
try {
|
|
final hash = await sdk.api.tx.signAndSend(
|
|
txInfo,
|
|
[name],
|
|
password,
|
|
onStatusChange: (status) {
|
|
log.d('Transaction status: ' + status);
|
|
transactionStatus = status;
|
|
notifyListeners();
|
|
},
|
|
).timeout(
|
|
const Duration(seconds: 12),
|
|
onTimeout: () => {},
|
|
);
|
|
log.d(hash);
|
|
if (hash.isEmpty) {
|
|
transactionStatus = 'timeout';
|
|
notifyListeners();
|
|
|
|
return 'timeout';
|
|
} else {
|
|
transactionStatus = hash.toString();
|
|
notifyListeners();
|
|
return hash.toString();
|
|
}
|
|
} on Exception catch (e) {
|
|
log.e(e);
|
|
transactionStatus = e.toString();
|
|
notifyListeners();
|
|
return e.toString();
|
|
}
|
|
}
|
|
|
|
Future<bool> isMember(String address) async {
|
|
return await idtyStatus(address) == 'Validated';
|
|
}
|
|
|
|
Future<String> getMemberAddress() async {
|
|
// TODOO: Continue digging memberAddress detection
|
|
String memberAddress = '';
|
|
walletBox.toMap().forEach((key, value) async {
|
|
final bool _isMember = await isMember(value.address!);
|
|
log.d(_isMember);
|
|
if (_isMember) {
|
|
final currentChestNumber = configBox.get('currentChest');
|
|
ChestData _newChestData = chestBox.get(currentChestNumber)!;
|
|
_newChestData.memberWallet = value.number;
|
|
await chestBox.put(currentChestNumber, _newChestData);
|
|
memberAddress = value.address!;
|
|
return;
|
|
}
|
|
});
|
|
log.d(memberAddress);
|
|
return memberAddress;
|
|
}
|
|
|
|
Future<Map<String, int>> certState(String from, String to) async {
|
|
Map<String, int> _result = {};
|
|
if (from != to && await isMember(from)) {
|
|
final _certData = await getCertData(from, to);
|
|
final _certMeta = await getCertMeta(from);
|
|
final int _removableOn = _certData['removableOn'] ?? 0;
|
|
final int _nextIssuableOn = _certMeta['nextIssuableOn'] ?? 0;
|
|
final certRemovableDuration = (_removableOn - blocNumber) * 6;
|
|
const int renewDelay = 2 * 30 * 24 * 3600; // 2 months
|
|
|
|
if (certRemovableDuration >= renewDelay) {
|
|
final certRenewDuration = certRemovableDuration - renewDelay;
|
|
_result.putIfAbsent('certRenewable', () => certRenewDuration);
|
|
} else if (_nextIssuableOn > blocNumber) {
|
|
final certDelayDuration = (_nextIssuableOn - blocNumber) * 6;
|
|
_result.putIfAbsent('certDelay', () => certDelayDuration);
|
|
} else {
|
|
_result.putIfAbsent('canCert', () => 0);
|
|
}
|
|
}
|
|
return _result;
|
|
}
|
|
|
|
Future<Map> getCertMeta(String address) async {
|
|
var idtyIndex = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$address")');
|
|
|
|
final _certMeta = await sdk.webView!
|
|
.evalJavascript('api.query.cert.storageIdtyCertMeta($idtyIndex)') ??
|
|
'';
|
|
// if (_certMeta['nextIssuableOn'] != 0) return {};
|
|
|
|
// log.d(_certMeta);
|
|
return _certMeta;
|
|
}
|
|
|
|
Future revokeIdentity(String address, String password) async {
|
|
final idtyIndex = await sdk.webView!
|
|
.evalJavascript('api.query.identity.identityIndexOf("$address")');
|
|
|
|
final sender = TxSenderData(
|
|
keyring.current.address,
|
|
keyring.current.pubKey,
|
|
);
|
|
|
|
log.d(sender.address);
|
|
TxInfoData txInfo;
|
|
|
|
txInfo = TxInfoData(
|
|
'membership',
|
|
'revokeMembership',
|
|
sender,
|
|
);
|
|
|
|
try {
|
|
final hash = await sdk.api.tx
|
|
.signAndSend(
|
|
txInfo,
|
|
[idtyIndex],
|
|
password,
|
|
)
|
|
.timeout(
|
|
const Duration(seconds: 12),
|
|
onTimeout: () => {},
|
|
);
|
|
log.d(hash);
|
|
if (hash.isEmpty) {
|
|
transactionStatus = 'timeout';
|
|
notifyListeners();
|
|
|
|
return 'timeout';
|
|
} else {
|
|
transactionStatus = hash.toString();
|
|
notifyListeners();
|
|
return hash.toString();
|
|
}
|
|
} catch (e) {
|
|
transactionStatus = e.toString();
|
|
notifyListeners();
|
|
return e.toString();
|
|
}
|
|
}
|
|
|
|
Future getCurencyName() async {}
|
|
|
|
Future<String> derive(
|
|
BuildContext context, String address, int number, String password) async {
|
|
final keypair = getKeypair(address);
|
|
|
|
final seedMap =
|
|
await keyring.store.getDecryptedSeed(keypair.pubKey, password);
|
|
|
|
if (seedMap?['type'] != 'mnemonic') return '';
|
|
final List seedList = seedMap!['seed'].split('//');
|
|
generatedMnemonic = seedList[0];
|
|
|
|
return await importAccount(
|
|
mnemonic: generatedMnemonic,
|
|
fromMnemonic: true,
|
|
derivePath: '//$number',
|
|
password: password);
|
|
}
|
|
|
|
Future<String> generateRootKeypair(String address, String password) async {
|
|
final keypair = getKeypair(address);
|
|
|
|
final seedMap =
|
|
await keyring.store.getDecryptedSeed(keypair.pubKey, password);
|
|
|
|
if (seedMap?['type'] != 'mnemonic') return '';
|
|
final List seedList = seedMap!['seed'].split('//');
|
|
generatedMnemonic = seedList[0];
|
|
|
|
return await importAccount(fromMnemonic: true, password: password);
|
|
}
|
|
|
|
Future<bool> isMnemonicValid(String mnemonic) async {
|
|
// Needed for bad encoding of UTF-8
|
|
mnemonic = mnemonic.replaceAll('é', 'é');
|
|
mnemonic = mnemonic.replaceAll('è', 'è');
|
|
|
|
return await sdk.api.keyring.checkMnemonicValid(mnemonic);
|
|
}
|
|
|
|
String? getConnectedEndpoint() {
|
|
return sdk.api.connectedNode?.endpoint;
|
|
}
|
|
}
|
|
|
|
void snack(BuildContext context, String message, {int duration = 2}) {
|
|
final snackBar =
|
|
SnackBar(content: Text(message), duration: Duration(seconds: duration));
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
class AddressInfo {
|
|
final String? address;
|
|
double balance;
|
|
|
|
AddressInfo({@required this.address, this.balance = 0});
|
|
}
|
|
|
|
void snackNode(BuildContext context, bool isConnected) {
|
|
String _message;
|
|
if (!isConnected) {
|
|
_message = "noDuniterNodeAvailableTryLater".tr() +
|
|
":\n${configBox.get('endpoint').first}";
|
|
} else {
|
|
SubstrateSdk _sub = Provider.of<SubstrateSdk>(context, listen: false);
|
|
|
|
_message = "youAreConnectedToNode".tr() +
|
|
"\n${_sub.getConnectedEndpoint()!.split('//')[1]}";
|
|
}
|
|
final snackBar = SnackBar(
|
|
padding: const EdgeInsets.all(20),
|
|
content: Text(_message, style: const TextStyle(fontSize: 16)),
|
|
duration: const Duration(seconds: 4));
|
|
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
|
}
|
|
|
|
String getShortPubkey(String pubkey) {
|
|
String pubkeyShort = truncate(pubkey, 7,
|
|
omission: String.fromCharCode(0x2026),
|
|
position: TruncatePosition.end) +
|
|
truncate(pubkey, 6, omission: "", position: TruncatePosition.start);
|
|
return pubkeyShort;
|
|
}
|
|
|
|
class PasswordException implements Exception {
|
|
String cause;
|
|
PasswordException(this.cause);
|
|
}
|