Skip to content
Snippets Groups Projects
substrate_sdk.dart 22.4 KiB
Newer Older
// ignore_for_file: avoid_print

Hugo Trentesaux's avatar
Hugo Trentesaux committed
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
poka's avatar
poka committed
import 'package:flutter/services.dart';
import 'package:gecko/globals.dart';
poka's avatar
poka committed
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';
poka's avatar
poka committed
import 'package:polkawallet_sdk/api/apiKeyring.dart';
import 'package:polkawallet_sdk/api/types/networkParams.dart';
poka's avatar
poka committed
import 'package:polkawallet_sdk/api/types/txInfoData.dart';
import 'package:polkawallet_sdk/polkawallet_sdk.dart';
import 'package:polkawallet_sdk/storage/keyring.dart';
poka's avatar
poka committed
import 'package:polkawallet_sdk/storage/types/keyPairData.dart';
import 'package:provider/provider.dart';
poka's avatar
poka committed
import 'package:truncate/truncate.dart';
// import 'package:web_socket_channel/io.dart';

class SubstrateSdk with ChangeNotifier {
poka's avatar
poka committed
  final int ss58 = 42;

  final WalletSDK sdk = WalletSDK();
  final Keyring keyring = Keyring();
poka's avatar
poka committed
  String generatedMnemonic = '';
poka's avatar
poka committed
  bool sdkLoading = false;
poka's avatar
poka committed
  bool importIsLoading = false;
  bool isLoadingEndpoint = false;
poka's avatar
poka committed
  String debugConnection = '';
  String transactionStatus = '';
poka's avatar
poka committed
  TextEditingController jsonKeystore = TextEditingController();
  TextEditingController keystorePassword = TextEditingController();

poka's avatar
poka committed
    sdkLoading = true;
poka's avatar
poka committed
    await keyring.init([ss58]);
    keyring.setSS58(ss58);

    await sdk.init(keyring);
    sdkReady = true;
poka's avatar
poka committed
    sdkLoading = false;
  Future<void> connectNode(BuildContext ctx) async {
poka's avatar
poka committed
    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;
    // }
Hugo Trentesaux's avatar
Hugo Trentesaux committed
    _homeProvider.changeMessage("connectionPending".tr(), 0);
poka's avatar
poka committed

    for (String _endpoint in configBox.get('endpoint')) {
      final n = NetworkParams();
      n.name = currencyName;
      n.endpoint = _endpoint;
      n.ss58 = ss58;
      node.add(n);
    }
poka's avatar
poka committed
    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();
poka's avatar
poka committed
    }

    isLoadingEndpoint = true;
    notifyListeners();
poka's avatar
poka committed
    final res = await sdk.api.connectNode(keyring, node).timeout(
          Duration(milliseconds: timeout),
poka's avatar
poka committed
          onTimeout: () => null,
        );
    isLoadingEndpoint = false;
    notifyListeners();
    if (res != null) {
      nodeConnected = true;
poka's avatar
poka committed

      // Subscribe bloc number
      sdk.api.setting.subscribeBestNumber((res) {
        blocNumber = int.parse(res.toString());
        // log.d(sdk.api.connectedNode?.endpoint);
poka's avatar
poka committed
        if (sdk.api.connectedNode?.endpoint == null) {
Hugo Trentesaux's avatar
Hugo Trentesaux committed
          _homeProvider.changeMessage("networkLost".tr(), 0);
poka's avatar
poka committed
        }
poka's avatar
poka committed
        notifyListeners();
      });
poka's avatar
poka committed
      // currencyName = await getCurencyName();
poka's avatar
poka committed
      _homeProvider.changeMessage(
poka's avatar
poka committed
          "wellConnectedToNode"
              .tr(args: [getConnectedEndpoint()!.split('/')[2]]),
poka's avatar
poka committed
          5);
      // snackNode(ctx, true);
    } else {
      nodeConnected = false;
poka's avatar
poka committed
      debugConnection = res.toString();
      notifyListeners();
Hugo Trentesaux's avatar
Hugo Trentesaux committed
      _homeProvider.changeMessage("noDuniterEndointAvailable".tr(), 0);
      // snackNode(ctx, false);
    log.d(sdk.api.connectedNode?.endpoint);
poka's avatar
poka committed

poka's avatar
poka committed
  Future<String> importAccount(
      {String mnemonic = '',
      bool fromMnemonic = false,
      String derivePath = '',
      String password = ''}) async {
poka's avatar
poka committed
    // toy exercise immense month enter answer table prefer speed cycle gold phone
    final clipboardData = await Clipboard.getData(Clipboard.kTextPlain);
poka's avatar
poka committed
    if (mnemonic != '') {
      fromMnemonic = true;
      generatedMnemonic = mnemonic;
    } else if (clipboardData!.text!.split(' ').length == 12) {
poka's avatar
poka committed
      fromMnemonic = true;
      generatedMnemonic = clipboardData.text!;
    }

    if (password == '') {
      password = keystorePassword.text;
    }

poka's avatar
poka committed
    final KeyType keytype;
    final String keyToImport;
    if (fromMnemonic) {
      keytype = KeyType.mnemonic;
      keyToImport = generatedMnemonic;
    } else {
      keytype = KeyType.keystore;
      keyToImport = jsonKeystore.text.replaceAll("'", "\\'");
    }

poka's avatar
poka committed
    importIsLoading = true;
    notifyListeners();
poka's avatar
poka committed
    if (clipboardData?.text != null) jsonKeystore.text = clipboardData!.text!;
    var json = await sdk.api.keyring
        .importAccount(keyring,
            keyType: keytype,
            key: keyToImport,
            name: derivePath,
            password: password,
poka's avatar
poka committed
            derivePath: derivePath,
            cryptoType: CryptoType.sr25519)
poka's avatar
poka committed
        .catchError((e) {
      importIsLoading = false;
      notifyListeners();
    });
poka's avatar
poka committed
    if (json == null) return '';
poka's avatar
poka committed
    try {
      await sdk.api.keyring.addAccount(
poka's avatar
poka committed
        keyring,
poka's avatar
poka committed
        keyType: keytype,
poka's avatar
poka committed
        acc: json,
        password: password,
poka's avatar
poka committed
      );
poka's avatar
poka committed
      // Clipboard.setData(ClipboardData(text: jsonEncode(acc.toJson())));
poka's avatar
poka committed
    } catch (e) {
poka's avatar
poka committed
      importIsLoading = false;
      notifyListeners();
poka's avatar
poka committed
    }
poka's avatar
poka committed

poka's avatar
poka committed
    importIsLoading = false;
poka's avatar
poka committed
    notifyListeners();
    return keyring.allAccounts.last.address!;
poka's avatar
poka committed
  }

  void reload() {
    notifyListeners();
  }
poka's avatar
poka committed

poka's avatar
poka committed
  Future<List<AddressInfo>> getKeyStoreAddress() async {
    List<AddressInfo> result = [];
poka's avatar
poka committed

poka's avatar
poka committed
    // sdk.api.account.unsubscribeBalance();
    for (var element in keyring.allAccounts) {
poka's avatar
poka committed
      // Clipboard.setData(ClipboardData(text: jsonEncode(element)));
poka's avatar
poka committed
      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!);
poka's avatar
poka committed
      result.add(account);
poka's avatar
poka committed
    }

    return result;
  }

poka's avatar
poka committed
  Future<List<int>> getCerts(String address) async {
    final idtyIndex = await sdk.webView!
        .evalJavascript('api.query.identity.identityIndexOf("$address")');
poka's avatar
poka committed
    // log.d('u32: ' + idtyIndex.toString());
poka's avatar
poka committed

    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 {};

poka's avatar
poka committed
    // log.d(_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;
poka's avatar
poka committed
  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);
    return await sdk.api.keyring.checkPassword(account, pass);
  }

poka's avatar
poka committed
  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);
  }

poka's avatar
poka committed
  Future<void> deleteAllAccounts() async {
    for (var account in keyring.allAccounts) {
      await sdk.api.keyring.deleteAccount(keyring, account);
    }
  }

poka's avatar
poka committed
  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 {
poka's avatar
poka committed
    final gen = await sdk.api.keyring.generateMnemonic(ss58);
poka's avatar
poka committed
    generatedMnemonic = gen.mnemonic!;
poka's avatar
poka committed

poka's avatar
poka committed
    // final res = await importAccount(fromMnemonic: true);
poka's avatar
poka committed
    // await Clipboard.setData(ClipboardData(text: generatedMnemonic));
poka's avatar
poka committed
    return gen.mnemonic!;
poka's avatar
poka committed
  }
poka's avatar
poka committed

poka's avatar
poka committed
  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);

poka's avatar
poka committed
    try {
poka's avatar
poka committed
      final acc = getKeypair(_wallet.address!);
poka's avatar
poka committed
      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(
poka's avatar
poka committed
      {required String fromAddress,
      required String destAddress,
      required double amount,
      required String password}) async {
    transactionStatus = '';

poka's avatar
poka committed
    // setCurrentWallet(fromAddress);
poka's avatar
poka committed

poka's avatar
poka committed
    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);
poka's avatar
poka committed
    final sender = TxSenderData(
poka's avatar
poka committed
    );
    final txInfo = TxInfoData(
        'balances', amount == -1 ? 'transferAll' : 'transferKeepAlive', sender);

    final int amountUnit = (amount * 100).toInt();
poka's avatar
poka committed
    try {
      final hash = await sdk.api.tx.signAndSend(
        txInfo,
        [destAddress, amount == -1 ? false : amountUnit],
poka's avatar
poka committed
        password,
        onStatusChange: (status) {
          log.d('Transaction status: ' + status);
poka's avatar
poka committed
          transactionStatus = status;
          notifyListeners();
poka's avatar
poka committed
        },
      ).timeout(
        const Duration(seconds: 12),
        onTimeout: () => {},
poka's avatar
poka committed
      );
      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 = '';

poka's avatar
poka committed
    // 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();
      }
poka's avatar
poka committed
    } catch (e) {
      transactionStatus = e.toString();
      notifyListeners();
poka's avatar
poka committed
      return e.toString();
poka's avatar
poka committed
    }
  }
poka's avatar
poka committed
  Future<String> idtyStatus(String address, [bool smooth = true]) async {
poka's avatar
poka committed
    //   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'];
poka's avatar
poka committed
      log.d('Status $address: $_status');
poka's avatar
poka committed
      return (_status);
    } else {
      return 'expired';
    }
  }

  Future<String> confirmIdentity(
      String fromAddress, String name, String password) async {
poka's avatar
poka committed
    // Confirm identity
poka's avatar
poka committed
    // setCurrentWallet(fromAddress);
    log.d('me: ' + keyring.current.address!);
poka's avatar
poka committed

    final sender = TxSenderData(
      keyring.current.address,
      keyring.current.pubKey,
    );

    final txInfo = TxInfoData(
      'identity',
      'confirmIdentity',
      sender,
    );

    try {
poka's avatar
poka committed
      final hash = await sdk.api.tx.signAndSend(
poka's avatar
poka committed
        txInfo,
        [name],
        password,
poka's avatar
poka committed
        onStatusChange: (status) {
          log.d('Transaction status: ' + status);
          transactionStatus = status;
          notifyListeners();
        },
      ).timeout(
        const Duration(seconds: 12),
        onTimeout: () => {},
poka's avatar
poka committed
      );
poka's avatar
poka committed
      log.d(hash);
      if (hash.isEmpty) {
        transactionStatus = 'timeout';
        notifyListeners();

        return 'timeout';
      } else {
        transactionStatus = hash.toString();
        notifyListeners();
        return hash.toString();
      }
poka's avatar
poka committed
    } on Exception catch (e) {
      log.e(e);
poka's avatar
poka committed
      transactionStatus = e.toString();
      notifyListeners();
poka's avatar
poka committed
      return e.toString();
    }
  }

  Future<bool> isMember(String address) async {
    return await idtyStatus(address) == 'Validated';
  }

poka's avatar
poka committed
  Future<String> getMemberAddress() async {
    // TODOO: Continue digging memberAddress detection
poka's avatar
poka committed
    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;
  }

poka's avatar
poka committed
  Future<Map<String, int>> certState(String from, String to) async {
poka's avatar
poka committed
    // String from = await getMemberAddress();
    if (from != to && await isMember(from)) {
poka's avatar
poka committed
      Map<String, int> _result = {};
      final _certData = await getCertData(from, to);
      final _certMeta = await getCertMeta(from);
      final int _removableOn = _certData['removableOn'] ?? 0;
poka's avatar
poka committed
      final int _renewableOn = _certData['renewableOn'] ?? 0;
      final int _nextIssuableOn = _certMeta['nextIssuableOn'] ?? 0;
      //TODO: use _removableOn instead of _renewableOn
poka's avatar
poka committed
      log.d(_renewableOn.toString() +
          '\n' +
          _removableOn.toString() +
          '\n' +
          _nextIssuableOn.toString());
poka's avatar
poka committed
        final certRenewDuration = (_renewableOn - blocNumber) * 6;
        _result.putIfAbsent('certRenewable', () => certRenewDuration);
        return _result;
      } else if (_nextIssuableOn > blocNumber) {
        final certDelayDuration = (_nextIssuableOn - blocNumber) * 6;
        _result.putIfAbsent('certDelay', () => certDelayDuration);
        return _result;
poka's avatar
poka committed
      } else {
        _result.putIfAbsent('canCert', () => 0);
        return _result;
poka's avatar
poka committed
    return {};
poka's avatar
poka committed
  // Future<String> certState(String from, String to) async {
  //   return '';
  // }

  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;
  }

poka's avatar
poka committed
  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();
    }
  }

poka's avatar
poka committed
  Future getCurencyName() async {}

  Future<String> derive(
poka's avatar
poka committed
      BuildContext context, String address, int number, String password) async {
    final keypair = getKeypair(address);
poka's avatar
poka committed
    final seedMap =
        await keyring.store.getDecryptedSeed(keypair.pubKey, password);

    if (seedMap?['type'] != 'mnemonic') return '';
    final List seedList = seedMap!['seed'].split('//');
poka's avatar
poka committed
    generatedMnemonic = seedList[0];
poka's avatar
poka committed
    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);
poka's avatar
poka committed

  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;
  }
poka's avatar
poka committed
}

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) {
Hugo Trentesaux's avatar
Hugo Trentesaux committed
    _message = "noDuniterNodeAvailableTryLater".tr() +
        ":\n${configBox.get('endpoint').first}";
    SubstrateSdk _sub = Provider.of<SubstrateSdk>(context, listen: false);

Hugo Trentesaux's avatar
Hugo Trentesaux committed
    _message = "youAreConnectedToNode".tr() +
        "\n${_sub.getConnectedEndpoint()!.split('//')[1]}";
poka's avatar
poka committed
  final snackBar = SnackBar(
      padding: const EdgeInsets.all(20),
      content: Text(_message, style: const TextStyle(fontSize: 16)),
poka's avatar
poka committed
      duration: const Duration(seconds: 4));
  ScaffoldMessenger.of(context).showSnackBar(snackBar);
}

poka's avatar
poka committed
String getShortPubkey(String pubkey) {
poka's avatar
poka committed
  String pubkeyShort = truncate(pubkey, 7,
poka's avatar
poka committed
          omission: String.fromCharCode(0x2026),
          position: TruncatePosition.end) +
poka's avatar
poka committed
      truncate(pubkey, 6, omission: "", position: TruncatePosition.start);
poka's avatar
poka committed
  return pubkeyShort;
poka's avatar
poka committed

class PasswordException implements Exception {
  String cause;
  PasswordException(this.cause);
}