2022-02-20 20:49:05 +01:00
|
|
|
// ignore_for_file: avoid_print
|
|
|
|
|
2022-02-19 23:51:12 +01:00
|
|
|
import 'package:crypto/crypto.dart';
|
|
|
|
import 'package:fast_base58/fast_base58.dart';
|
2022-02-18 00:20:21 +01:00
|
|
|
import 'package:flutter/material.dart';
|
2022-02-18 18:57:03 +01:00
|
|
|
import 'package:flutter/services.dart';
|
2022-02-18 02:19:08 +01:00
|
|
|
import 'package:polkawallet_sdk/api/apiKeyring.dart';
|
2022-02-18 00:20:21 +01:00
|
|
|
import 'package:polkawallet_sdk/api/types/networkParams.dart';
|
2022-02-19 23:51:12 +01:00
|
|
|
import 'package:polkawallet_sdk/api/types/txInfoData.dart';
|
2022-02-18 00:20:21 +01:00
|
|
|
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
|
|
|
|
import 'package:polkawallet_sdk/storage/keyring.dart';
|
2022-05-04 19:00:09 +02:00
|
|
|
import 'package:polkawallet_sdk/storage/types/keyPairData.dart';
|
2022-02-19 23:51:12 +01:00
|
|
|
import 'package:truncate/truncate.dart';
|
2022-02-18 00:20:21 +01:00
|
|
|
|
|
|
|
class SubstrateSdk with ChangeNotifier {
|
2022-05-04 19:00:09 +02:00
|
|
|
final List subNode = ['192.168.1.72:9944'];
|
2022-02-18 00:20:21 +01:00
|
|
|
final bool isSsl = false;
|
2022-02-19 23:51:12 +01:00
|
|
|
final int ss58 = 42;
|
2022-02-18 00:20:21 +01:00
|
|
|
|
|
|
|
final WalletSDK sdk = WalletSDK();
|
|
|
|
final Keyring keyring = Keyring();
|
2022-02-18 19:49:37 +01:00
|
|
|
String generatedMnemonic = '';
|
2022-02-18 00:20:21 +01:00
|
|
|
bool sdkReady = false;
|
2022-02-18 18:57:03 +01:00
|
|
|
bool sdkLoading = false;
|
2022-02-18 00:20:21 +01:00
|
|
|
bool nodeConnected = false;
|
2022-02-18 19:49:37 +01:00
|
|
|
bool importIsLoading = false;
|
2022-02-18 00:20:21 +01:00
|
|
|
int blocNumber = 0;
|
|
|
|
|
2022-02-18 02:19:08 +01:00
|
|
|
TextEditingController jsonKeystore = TextEditingController();
|
|
|
|
TextEditingController keystorePassword = TextEditingController();
|
|
|
|
|
2022-02-18 00:20:21 +01:00
|
|
|
Future<void> initApi() async {
|
2022-02-18 18:57:03 +01:00
|
|
|
sdkLoading = true;
|
2022-02-19 23:51:12 +01:00
|
|
|
await keyring.init([ss58]);
|
|
|
|
keyring.setSS58(ss58);
|
2022-02-18 00:20:21 +01:00
|
|
|
|
|
|
|
await sdk.init(keyring);
|
|
|
|
sdkReady = true;
|
2022-02-18 18:57:03 +01:00
|
|
|
sdkLoading = false;
|
2022-02-18 00:20:21 +01:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> connectNode() async {
|
|
|
|
final String socketKind = isSsl ? 'wss' : 'ws';
|
2022-02-19 23:51:12 +01:00
|
|
|
List<NetworkParams> node = [];
|
|
|
|
for (final sn in subNode) {
|
|
|
|
final n = NetworkParams();
|
|
|
|
n.name = 'duniter';
|
|
|
|
n.endpoint = '$socketKind://$sn';
|
|
|
|
n.ss58 = ss58;
|
|
|
|
node.add(n);
|
|
|
|
}
|
|
|
|
final res = await sdk.api.connectNode(keyring, node).timeout(
|
|
|
|
const Duration(seconds: 10),
|
|
|
|
onTimeout: () => null,
|
|
|
|
);
|
2022-02-18 00:20:21 +01:00
|
|
|
if (res != null) {
|
|
|
|
nodeConnected = true;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Subscribe bloc number
|
|
|
|
sdk.api.setting.subscribeBestNumber((res) {
|
|
|
|
blocNumber = int.parse(res.toString());
|
|
|
|
notifyListeners();
|
|
|
|
});
|
|
|
|
}
|
2022-02-18 02:19:08 +01:00
|
|
|
|
2022-05-04 19:00:09 +02:00
|
|
|
Future<String> importAccount(
|
|
|
|
{String mnemonic = '',
|
|
|
|
bool fromMnemonic = false,
|
|
|
|
String derivePath = ''}) async {
|
2022-02-22 10:39:45 +01:00
|
|
|
// toy exercise immense month enter answer table prefer speed cycle gold phone
|
|
|
|
final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
|
2022-05-04 19:00:09 +02:00
|
|
|
if (mnemonic != '') {
|
|
|
|
fromMnemonic = true;
|
|
|
|
generatedMnemonic = mnemonic;
|
|
|
|
} else if (clipboardData!.text!.split(' ').length == 12) {
|
2022-02-22 10:39:45 +01:00
|
|
|
fromMnemonic = true;
|
|
|
|
generatedMnemonic = clipboardData.text!;
|
|
|
|
}
|
|
|
|
|
2022-02-19 23:51:12 +01:00
|
|
|
final KeyType keytype;
|
|
|
|
final String keyToImport;
|
|
|
|
if (fromMnemonic) {
|
|
|
|
keytype = KeyType.mnemonic;
|
|
|
|
keyToImport = generatedMnemonic;
|
|
|
|
} else {
|
|
|
|
keytype = KeyType.keystore;
|
|
|
|
keyToImport = jsonKeystore.text.replaceAll("'", "\\'");
|
|
|
|
}
|
|
|
|
|
2022-02-18 19:49:37 +01:00
|
|
|
importIsLoading = true;
|
|
|
|
notifyListeners();
|
2022-05-04 19:00:09 +02:00
|
|
|
if (clipboardData?.text != null) jsonKeystore.text = clipboardData!.text!;
|
2022-02-20 20:49:05 +01:00
|
|
|
var json = await sdk.api.keyring
|
|
|
|
.importAccount(keyring,
|
|
|
|
keyType: keytype,
|
|
|
|
key: keyToImport,
|
|
|
|
name: 'testKey',
|
|
|
|
password: keystorePassword.text,
|
2022-03-02 21:33:50 +01:00
|
|
|
derivePath: derivePath,
|
|
|
|
cryptoType: CryptoType.sr25519)
|
2022-02-18 19:49:37 +01:00
|
|
|
.catchError((e) {
|
|
|
|
importIsLoading = false;
|
|
|
|
notifyListeners();
|
|
|
|
});
|
2022-05-04 19:00:09 +02:00
|
|
|
if (json == null) return '';
|
2022-02-20 20:49:05 +01:00
|
|
|
print(json);
|
2022-05-04 19:00:09 +02:00
|
|
|
late KeyPairData? keyPairData;
|
2022-02-19 23:51:12 +01:00
|
|
|
try {
|
2022-05-04 19:00:09 +02:00
|
|
|
keyPairData = await sdk.api.keyring.addAccount(
|
2022-02-19 23:51:12 +01:00
|
|
|
keyring,
|
2022-02-22 10:39:45 +01:00
|
|
|
keyType: keytype,
|
2022-02-19 23:51:12 +01:00
|
|
|
acc: json,
|
|
|
|
password: keystorePassword.text,
|
|
|
|
);
|
2022-02-22 10:39:45 +01:00
|
|
|
// Clipboard.setData(ClipboardData(text: jsonEncode(acc.toJson())));
|
2022-02-19 23:51:12 +01:00
|
|
|
} catch (e) {
|
2022-02-18 19:49:37 +01:00
|
|
|
importIsLoading = false;
|
|
|
|
notifyListeners();
|
2022-02-19 23:51:12 +01:00
|
|
|
}
|
2022-02-18 02:19:08 +01:00
|
|
|
|
2022-02-18 19:49:37 +01:00
|
|
|
importIsLoading = false;
|
2022-02-19 23:51:12 +01:00
|
|
|
await Future.delayed(const Duration(milliseconds: 20));
|
2022-02-18 02:19:08 +01:00
|
|
|
notifyListeners();
|
2022-05-04 19:00:09 +02:00
|
|
|
return keyPairData!.address!;
|
2022-02-18 02:19:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void reload() {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
2022-02-18 18:57:03 +01:00
|
|
|
|
2022-02-19 23:51:12 +01:00
|
|
|
Future<List<AddressInfo>> getKeyStoreAddress() async {
|
|
|
|
List<AddressInfo> result = [];
|
2022-02-18 18:57:03 +01:00
|
|
|
|
2022-02-19 23:51:12 +01:00
|
|
|
// sdk.api.account.unsubscribeBalance();
|
|
|
|
for (var element in keyring.allAccounts) {
|
2022-02-18 18:57:03 +01:00
|
|
|
// Clipboard.setData(ClipboardData(text: jsonEncode(element)));
|
2022-02-19 23:51:12 +01:00
|
|
|
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();
|
|
|
|
if (nodeConnected) {
|
|
|
|
final brutBalance = await sdk.api.account.queryBalance(element.address);
|
|
|
|
account.balance = int.parse(brutBalance!.freeBalance) / 100;
|
|
|
|
}
|
|
|
|
result.add(account);
|
2022-02-18 18:57:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-02-19 23:51:12 +01:00
|
|
|
Future<void> deleteAllAccounts() async {
|
|
|
|
for (var account in keyring.allAccounts) {
|
|
|
|
await sdk.api.keyring.deleteAccount(keyring, account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-04 19:00:09 +02:00
|
|
|
Future<String> generateMnemonic({String lang = 'english'}) async {
|
2022-02-19 23:51:12 +01:00
|
|
|
final gen = await sdk.api.keyring.generateMnemonic(ss58);
|
2022-02-18 19:49:37 +01:00
|
|
|
generatedMnemonic = gen.mnemonic!;
|
2022-02-19 23:51:12 +01:00
|
|
|
|
2022-02-22 10:39:45 +01:00
|
|
|
// final res = await importAccount(fromMnemonic: true);
|
|
|
|
await Clipboard.setData(ClipboardData(text: generatedMnemonic));
|
|
|
|
return gen.mnemonic!;
|
2022-02-18 18:57:03 +01:00
|
|
|
}
|
2022-02-19 23:51:12 +01:00
|
|
|
|
|
|
|
pay(BuildContext context, String address, double amount,
|
|
|
|
String password) async {
|
|
|
|
final sender = TxSenderData(
|
|
|
|
keyring.current.address,
|
|
|
|
keyring.current.pubKey,
|
|
|
|
);
|
|
|
|
final txInfo = TxInfoData('balances', 'transfer', sender);
|
|
|
|
try {
|
|
|
|
final hash = await sdk.api.tx.signAndSend(
|
|
|
|
txInfo,
|
|
|
|
[address, amount * 100],
|
|
|
|
password,
|
|
|
|
onStatusChange: (status) {
|
|
|
|
print('status: ' + status);
|
|
|
|
if (status == 'Ready') {
|
2022-03-02 21:33:50 +01:00
|
|
|
snack(context, 'Transaction terminé');
|
2022-02-19 23:51:12 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
print(hash.toString());
|
|
|
|
} catch (err) {
|
|
|
|
print(err.toString());
|
|
|
|
}
|
|
|
|
}
|
2022-02-20 20:49:05 +01:00
|
|
|
|
2022-02-22 10:39:45 +01:00
|
|
|
derive(
|
|
|
|
BuildContext context, String address, int number, String password) async {
|
2022-02-20 20:49:05 +01:00
|
|
|
final keypair =
|
|
|
|
keyring.keyPairs.firstWhere((element) => element.address == address);
|
|
|
|
|
2022-02-22 10:39:45 +01:00
|
|
|
final seedMap =
|
|
|
|
await keyring.store.getDecryptedSeed(keypair.pubKey, password);
|
|
|
|
print(seedMap);
|
2022-03-02 21:33:50 +01:00
|
|
|
if (seedMap!['type'] != 'mnemonic') return;
|
|
|
|
final List seedList = seedMap['seed'].split('/');
|
|
|
|
generatedMnemonic = seedList[0];
|
|
|
|
int sourceDerivation = -1; // To get derivation number of this account
|
|
|
|
if (seedList.length > 1) {
|
|
|
|
sourceDerivation = int.parse(seedMap['seed'].split('/')[1]);
|
|
|
|
}
|
|
|
|
print(generatedMnemonic);
|
|
|
|
print(sourceDerivation);
|
2022-02-20 20:49:05 +01:00
|
|
|
|
2022-02-22 10:39:45 +01:00
|
|
|
importAccount(fromMnemonic: true, derivePath: '/$number');
|
2022-02-20 20:49:05 +01:00
|
|
|
}
|
2022-02-19 23:51:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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});
|
|
|
|
}
|
|
|
|
|
|
|
|
String getShortPubkey(String pubkey) {
|
|
|
|
List<int> pubkeyByte = Base58Decode(pubkey);
|
|
|
|
Digest pubkeyS256 = sha256.convert(sha256.convert(pubkeyByte).bytes);
|
|
|
|
String pubkeyCheksum = Base58Encode(pubkeyS256.bytes);
|
|
|
|
String pubkeyChecksumShort =
|
|
|
|
truncate(pubkeyCheksum, 3, omission: "", position: TruncatePosition.end);
|
|
|
|
|
|
|
|
String pubkeyShort = truncate(pubkey, 5,
|
|
|
|
omission: String.fromCharCode(0x2026),
|
|
|
|
position: TruncatePosition.end) +
|
|
|
|
truncate(pubkey, 4, omission: "", position: TruncatePosition.start) +
|
|
|
|
':$pubkeyChecksumShort';
|
|
|
|
|
|
|
|
return pubkeyShort;
|
2022-02-18 00:20:21 +01:00
|
|
|
}
|