leonardocustodio / polkadart

Polkadart provides developers the ability to query a node and interact with the Polkadot based chains using Dart.
https://polkadart.dev
Apache License 2.0
39 stars 16 forks source link

How subscribe to balance changes? #385

Closed raqeta closed 11 months ago

raqeta commented 11 months ago

Hi, I want to subscribe to balance changes. I want to receive the balance in an event or trigger an event about a change, increase or decrease in the balance. Could you tell me how I can do this? I didn't find this in the documentation. Thanks.

leonardocustodio commented 11 months ago

Hello, I believe you can subscribe to the storage key system.accounts, let me know if it works out.

raqeta commented 11 months ago

I've tried to do it like in code below. Should I add System and Account? Is it right launch point to subscribe? And also I didn't get any updates and I suppose I have some mistakes with address encoding.

Future startBalanceListening(String address, Function(BalanceData) onUpdate) async {
// address for example == '5GTCTWCBQ797s8cf9KFBgAGQgpwdAHnoy37aTT1PgC37PEEN'
final account = Address.decode(address);
_subscription = await _myDot.rpc.state.subscribeStorage(
[account.pubkey], // should I add ['System', 'Account'] here and how ?
(set) async {
// do something after changing
}, ); }

leonardocustodio commented 11 months ago

system.account is the storage key, it will subscribe to all balance changes of every account. If you want a specific account would be system.account(the account). I'm not in the computer right now so can't write a sample for you but I can do it in a few hours.

raqeta commented 11 months ago

thanks, I'll try :)

raqeta commented 11 months ago

Thanks to your help, chatGpt and official Polkadot.js documentation I find out everything work correct with this code :)

  final MyChainDot _myChainDot;
  final Map<String, StreamSubscription<StorageChangeSet>> _addressSubscriptionMap = {};

  @override
  Future<void> startBalanceListening(String? address, Function(BalanceData) onUpdate) async {
    if (address == null || address.isEmpty || _addressSubscriptionMap[address] != null) return;
    final accountPubKey = Address.decode(address).pubkey;
    final storageAccountKeyQuery = [_myChainDot.query.system.accountKey(accountPubKey)];
    _addressSubscriptionMap[address] = await _myChainDot.rpc.state.subscribeStorage(
      storageAccountKeyQuery,
      (storageChangeSet) async {
        final accountInfo = await _myChainDot.query.system.account(accountPubKey);
        onUpdate.call(
          BalanceData(
            accountId: address,
            accountNonce: accountInfo.nonce,
            availableBalance: (accountInfo.data.free + accountInfo.data.reserved + accountInfo.data.frozen),
          ),
        );
      },
    );
  }

  @override
  Future<void> stopBalancesListening(String? address) async {
    if (address == null || address.isEmpty || _addressSubscriptionMap[address] == null) return;
    final subscription = _addressSubscriptionMap[address];
    if (subscription == null) return;
    _addressSubscriptionMap.remove(address);
    await subscription.cancel();
  }
leonardocustodio commented 11 months ago

Great, glad it helped