1

I am adding substrate based payment mechanism to my web app. App would provide substrate address to end user, where he/she will send required funds by some external means. Now I want my app to find out if payment is done and confirmed. To identify transactions from end user, I will ask him/her to provide address from where he/she plans to send funds from.

App would know destination substrate address balance before and after transaction, but how to confirm how many funds came from which address? One crude way would be to go through each transactions of new block(since transaction is kicked on) and check if funds came from end user's address. But that would be exhaustive. Any simple and elegant way to find fund transfers from specific address?

1 Answer 1

2

You should listen for chain events, which would announce the transfer has occurred between the two accounts, and the amount.

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config<I>, I: 'static = ()> {
    // -- snip --
    /// Transfer succeeded.
    Transfer { from: T::AccountId, to: T::AccountId, amount: T::Balance },
    // -- snip --
}

You'd only need to search on the block where the receiving account's balance has changed to confirm the funds came from where you expected.

If you are using Polkadot JS API in particular, there are even better options like Transaction Subscriptions, which even includes hooks specific for events.


EDIT

Scanning all blocks is the only solution here. The chain does not store live metadata about each user and when all transfers happened. This would be a complete waste of on-chain data.

This is exactly what indexing services and block explorers are for.

In the case where a block explorer is not set up for your network, you should consider setting one up using the open source projects like:

In the case you want to do some short term JS solution, you can query the balance of a user at all blocks like so:

const provider = new WsProvider(endpoint);
const api = await ApiPromise.create({ provider });

for (let i = 0; i < last_block; i++) {
    // Get the api in the context of the current block.
    const blockHash = await api.rpc.chain.getBlockHash(i);
    const block = await api.derive.chain.getBlock(blockHash);
    const aa = await api.at(blockHash);

    // Get the account's balance.
    const balance = await aa.query.system.account(address);
    let free = balance.data.free;
    let reserved = balance.data.reserved;

    // Do stuff...
}

You can find similar logic in projects like:

https://github.com/shawntabrizi/substrate-balance-graph/

12
  • Thanks friend. I can not subscribe to transaction events as I am not the one who performed the transaction. My customer is going perform transaction. And I have to confirm it at my end (knowing his source address and time window when he initiated the transaction). and I am looking at Polkadot JS API solution. Thanks.
    – pravin k
    May 23, 2022 at 5:59
  • If you know the time window, then you can just look at the events for each block in that time window. Otherwise, why not just use a block explorer like subscan.io
    – Shawn Tabrizi
    May 23, 2022 at 14:07
  • yes, But that would be exhaustive. Any simple and elegant way to find fund transfers from specific address? Thanks.
    – pravin k
    May 23, 2022 at 17:27
  • A block explorer is the elegant way. This is true for any blockchain that exists today.
    – Shawn Tabrizi
    May 23, 2022 at 18:05
  • Thanks Shawn, will look for JS APIs to scan blocks. If you know any sample code for filtering transactions for transactions between A and B addresses, please do share. I am not accepting above as solution, because I can not 'subscribe' APIs as I am not the one who is generating the fund transfer transaction.
    – pravin k
    May 24, 2022 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.