Solana DEV #02: Retrieve all Deposit transactions of your wallet
Tin Chung
Posted on August 29, 2022
If you use Phantom wallet to pay for transactions on Solana blockchain, you may recognize that every time you send SOL or SPL tokens to another address, that transaction will be recorded and listed on Phantom wallet interface.
At first, I thought that it is just similar to any other data fetched by using getProgramAccounts
with filtering stuffs. However, it does not work that way.
Fetching signatures and transactions
To fetch all deposit transactions of one address, you must get all signatures of that address by using the method getSignaturesForAddress
const signatureInfos = await connection.getSignaturesForAddress(vaultAddress);
And then map the info to get only transaction signatures
const signatures = signatureInfos.map(sig => sig.signature);
const transactions = await connection.getParsedTransactions(signatures);
This approach has a very big problem. It does not allow you to filter out fetched signatures like what you usually do with getProgramAccounts
. And in that way, it will just fetch a bulk load of transactions from your address as your address have other wallet interaction beside receive and send coins. To make it more efficient, I try to filter out success signatures from the return data
const filteredSignatureInfos = signatureInfos.filter(sig => !sig.err && !sig.memo);
But unlucky, if your wallet has around 300 or more transactions, the RPC won't allow you to fetch as there's a rate limit. I don't know if there are any other better approaches but this is the one that I found.
How to improve the approach?
This might not be an acceptable answer but there's a few ways that you can improve the case.
- Trying to separate a vault from a wallet. A vault will be a PDA that use the wallet address as a seed. In that way, all transactions that the vault includes will be related to tokens and native SOL only. Even the most traffic vault can only have around 50-100 transactions.
- Using cache database, partition and event listener: This technique is commonly used in tradition backend development. If you have around 300 transactions for an address, try to partition those into smaller parts: 50 transactions per each. Cache those data and then only update the database if there is a new data coming (use
onAccountChange
).
Filtering transactions
There will be two types of transactions that you may want to fetch to display a similar result from Phantom: Native SOL deposit transactions and SPL tokens deposit transactions. If you use getParsedTransactions
like what I did above, all the data is already converted into human readable language. The raw transactions using getTransactions
return only hexadecimal data. I wrote these two methods so that you can reuse it, it's quite simple because all data is parsed already.
// Filter SPL token deposit transaction
isSplTokenDepositTx(tx: any): boolean {
const ixs = tx.transaction.message.instructions;
const ix: any = ixs[ixs.length - 1];
return (
ix.programId.equals(TOKEN_PROGRAM_ID) &&
(ix.parsed.type === 'transfer' || ix.parsed.type === 'transferChecked')
);
}
// Filter Native SOL deposit transaction
isSolDepositTx(tx: any): boolean {
const ix: any = tx.transaction.message.instructions[0];
return ix.programId.equals(SYSTEM_PROGRAM_ID) && ix.parsed.type === 'transfer';
}
Posted on August 29, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.