Substreams offers two Solana endpoints: - Standard Block: index transactions and instructions. - Account Changes: index historical account changes.
In this example, you will be able to index data from BondingCurve
Anchor accounts in the Pump.Fun platform. Therefore, you will be using the Account Changes endpoint.
To get standard Block
data, use this Substreams.
- Build the Substreams
substreams build
- Run the Substreams:
substreams gui ./substreams.yaml map_my_data --start-block=333000025 -e accounts.mainnet.sol.streamingfast.io:443 --stop-block=+10
In the previous command, you are running the Substreams against the accounts.mainnet.sol.streamingfast.io:443
(account changes) endpoint.
...
imports:
solana: https://spkg.io/v1/packages/solana_accounts_foundational/v0.1.1 # 1.
...
modules:
- name: filtered_accounts # 2.
use: solana:filtered_accounts
- name: map_my_data # 3.
kind: map
inputs:
- map: filtered_accounts
output:
type: proto:mydata.v1.MyData
params:
filtered_accounts: account:EA8ALG67fSLWDJwUmDyj38x45UkmG4pPYDNmfWbE6NMA # 4.
- Import the Solana Accounts foundational modules. These modules allow you to get filtered Solana accounts. The modules are imported with the
solana
alias (solana: ...
). - Define a new module
filtered_accounts
, which uses thefiltered_accounts
module from the Solana Accounts foundational modules previously imported. This modules expects one or several modules to be filtered as input. - Define a new module,
map_my_data
, which receives the filtered accounts as input, and outputs aMyData
object (defined in theproto/mydata.proto
file). Here, you will make the decoding of the Pump Fun accounts. - The parameters passed to the
filtered_accounts
module. In this case, it is the address of a Pump Fun Bonding Curve account.
#[substreams::handlers::map]
fn map_my_data(accounts: FilteredAccounts) -> mydata::MyData {
let mut bonding_curve_list: Vec<BondingCurve> = Vec::new(); // 1.
accounts.accounts.iter().for_each(|account| { // 2.
let slice_u8: &[u8] = &account.data[..];
if &slice_u8[0..8] == idl::idl::program::accounts::BondingCurve::DISCRIMINATOR { // 3.
if let Ok(acct) =
idl::idl::program::accounts::BondingCurve::deserialize(&mut &slice_u8[8..]) // 4.
{
bonding_curve_list.push(
BondingCurve {
virtual_token_reserves: acct.virtual_token_reserves,
virtual_sol_reserves: acct.virtual_sol_reserves,
real_token_reserves: acct.real_token_reserves,
real_sol_reserves: acct.real_sol_reserves,
token_total_supply: acct.token_total_supply,
complete: acct.complete
})
}
}
});
MyData {
bonding_curve_list
}
}
- Initialize the output array of
BondingCurve
Protobuf objects, defined inproto/mydata.proto
. - Iterate over the filtered account. In this example, we will only get changes related to the
EA8ALG67fSLWDJwUmDyj38x45UkmG4pPYDNmfWbE6NMA
account, which is aBondigCurve
account. - Every account change contains a
data
field, which is the raw data written in the blockchain. The first 8 bytes are used as discriminator (i.e. the identifier of the account). - If the account data matches the discriminator, it is deserialized.