You can now use Amazon Managed Blockchain Query to easily retrieve a full list of token balances for a given EOA at finality (2 epochs on Ethereum) or from history (based on a timestamp). I've included some sample Node.js code to show you how to do this.
To run the sample code, the following prerequisites apply:
You must have node version manager (nvm) and Node.js installed on your machine. You can find installation instruction for your OS here.
Use the node - -version command and confirm that you are using Node version 14 or higher. If required, you can use the nvm install 14 command, followed by the nvm use 14 command to install version 14. NOTE: Node 14, 15, 16 are now at end of life.
The environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY must contain the credentials that are associated with the AWS account and user with IAM permissions to access Amazon Managed Blockchain Query.
const axios = require('axios').default;
const SHA256 = require('@aws-crypto/sha256-js').Sha256
const defaultProvider = require('@aws-sdk/credential-provider-node').defaultProvider
const HttpRequest = require('@aws-sdk/protocol-http').HttpRequest
const SignatureV4 = require('@aws-sdk/signature-v4').SignatureV4
// define a signer object with AWS service name, credentials, and region
const signer = new SignatureV4({
credentials: defaultProvider(),
service: 'managedblockchain-query',
region: 'us-east-1',
sha256: SHA256,
});
const queryRequest = async (path, data) => {
//query endpoint
let queryEndpoint = `https://managedblockchain-query.us-east-1.amazonaws.com/${path}`;
// parse the URL into its component parts (e.g. host, path)
const url = new URL(queryEndpoint);
// create an HTTP Request object
const req = new HttpRequest({
hostname: url.hostname.toString(),
path: url.pathname.toString(),
body: JSON.stringify(data),
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept-Encoding': 'gzip',
host: url.hostname,
}
});
// use AWS SignatureV4 utility to sign the request, extract headers and body
const signedRequest = await signer.sign(req, { signingDate: new Date() });
try {
//make the request using axios
const response = await axios({...signedRequest, url: queryEndpoint, data: data})
console.log(response.data)
} catch (error) {
console.error('Something went wrong: ', error)
throw error
}
}
let methodArg = 'list-token-balances';
let dataArg = {
"ownerFilter": {"address":"<externally owned account address here"},
"tokenFilter":{"network":"ETHEREUM_MAINNET"}
}
//Run the query request.
queryRequest(methodArg, dataArg);
The response will follow this format, paginating results listing tokens (ERC20, native ETH, ERC721/1155 NFTs) for an EOA:
{
"nextToken": "string", // pagination
"tokenBalances": [
{
"atBlockchainInstant": {
"time": number //timestamp
},
"balance": "string", // balance for a token as a string
"lastUpdatedTime": {
"time": number // timestamp of when data was last updated
},
"ownerIdentifier": {
"address": "string" // EOA address
},
"tokenIdentifier": {
"contractAddress": "string", // contract address for token
"network": "string", // network (e.g. Ethereum mainnet)
"tokenId": "string" // token ID if it's an NFT
}
}
]
}