How to get historical transactions on Polygon?
Ethereum Layer 2 scaling solutions, like Polygon, have allowed developers to take advantage of low transaction costs and far faster confirmation times. However, this introduces a new challenge for devs: how to process and store large swaths of blockchain data. Traditionally, developers had to spin up, manage, and index across their own nodes to build databases. This left developers constrained by an expensive and slow solution that ultimately limits their apps’ feature sets regardless of whether they are deployed on Layer 1 or Layer 2 solutions.
While building historical queries into dApps has traditionally been complicated and time-consuming, the Alchemy Transfers API on Polygon allows for developers to get Polygon transaction details, dating back to the very beginning, in a single request.
In this tutorial, we’ll look at an example of how, with just a few lines of code, your Polygon dApp can integrate historical transactions.
Code sneak peek 👀
import json
from web3 import Web3
import requests
try:
ALCHEMY_KEY = "Rt4_MeHEE8mQWVi-uSppHNSDmOG"
except:
print("Please insert your Alchemy API Key!")
w3 = Web3(Web3.HTTPProvider("https://polygon-mainnet.g.alchemy.com/v2/"+ALCHEMY_KEY))
# includes the standard ERC20 ABI info
ERC20_ABI = json.loads('[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],......{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]') # noqa: 501
# configures web3 to point towards the USDT token address
# make sure that these addresses are Ethereum-checksummed! (use this tool: https://ethsum.netlify.app/ to make sure)
USDT_ADDRESS = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F'
FROM_ADDRESS = '0x5350E1068f0E138ff306990B16fA4910d970c692'
TO_ADDRESS = '0x9d2b758E3ffd2569c6956676fAE7f8B71A53Ffb5'
from_Block = '0x16C5376'
to_Block = '0x16C537A'
usdt = w3.eth.contract(address=USDT_ADDRESS, abi=ERC20_ABI)
transfer_json = requests.post('https://polygon-mainnet.g.alchemy.com/v2/'+ALCHEMY_KEY, json={"jsonrpc": "2.0","id": 0,"method": "alchemy_getAssetTransfers","params": [{"fromBlock": from_Block,"toBlock": to_Block,"fromAddress": FROM_ADDRESS,"toAddress": TO_ADDRESS,"contractAddresses": [USDT_ADDRESS],"category": ["erc20"]}]})
json_response = transfer_json.json()
#print(json_response)
transfer_val = (json_response['result']['transfers'][0]['rawContract']['value'])
# convert hexadecimal make to decimal format
val = (int(transfer_val, 16))
print("USDT TRANSFERED:")
print("--> FROM: " + FROM_ADDRESS)
print("--> TO: " + TO_ADDRESS)
# unit conversion!
print(val/1000000)
Before diving into the Alchemy Transfers API on Polygon, let’s clarify the 3 types of transfers we see on-chain (note - the Polygon Transfers API only supports token transfers)
Types of Transfers:
1. External MATIC Transfers
These are top-level Polygon transactions that occur with a from address being an external (user-created) address. External addresses have private keys and are accessed by users.
* External transfers are not currently supported by the Alchemy Transfers API on Polygon
2. Token Transfers
Event logs for ERC20 (fungible tokens), ERC721 (NFTs), and ERC1155 (hybrid fungible and non-fungible tokens) transfers.
3. Internal Eth Transfers
These are transfers that occur where the fromAddress is an internal (smart contract) address. (ex: a smart contract calling another smart contract or smart contract calling another external address).
* Internal transfers are not currently supported by the Alchemy Transfers API on Polygon
For more information on API parameters and JSON responses, read the Alchemy Transfers API.
Understanding Alchemy Transfers API on Polygon
In this example, we are trying to query and find the transfer of this transaction. We can see from Polyscan that ~12,000 USDT was transferred from 0x5350e1068f0e138ff306990b16fa4910d970c692 to 0x9d2b758e3ffd2569c6956676fae7f8b71a53ffb5.
(If you want to skip ahead to the code, fork the starter script [https://github.com/pileofscraps/historical_transactions_polygon_scripts] and follow along)
To use the Transfers API to track the USDT transfer, we need a few pieces of key information that help narrow down our search. We format this request information into a JSON object as follows:
{
"jsonrpc":"2.0",
"id":0,
"method":"alchemy_getAssetTransfers",
"params":[
{
"fromBlock":"from_Block",
"toBlock":"to_Block",
"fromAddress":"FROM_ADDRESS",
"toAddress":"TO_ADDRESS",
"contractAddresses":[
"USDT_ADDRESS"
],
"category":[
"erc20"
]
}
]
})
1. From Block & To Block
We can reduce the amount of time it takes for the API to return our JSON response by constraining the start and end block numbers that we are attempting to search.
Our transaction takes place in block 23876472 so we adjust our search to a small buffer around this block number.
The JSON object allows us to either use a hexadecimal string or for block number inputs. In this case, we use hexadecimals, so we input 0x16C5376 for afromBlock
of 23876470 and 0x16C537A for a toBlock
2. To & From Addresses
The To & From addresses represent where the transaction was sent and where it originated from respectively.
In our example, To Address is 0x9d2b758e3ffd2569c6956676fae7f8b71a53ffb5 and From Address is 0x5350e1068f0e138ff306990b16fa4910d970c692.
3. Contract Address
The contract address is the address denoting the specific ERC20, ERC721, or ERC1155 contract that we seek to find.In our example, the ERC20 contract for Polygon USDT is 0xc2132d05d31c914a87c6611c10748aeb04b58e8f.
Putting together this information, we can now use Alchemy’s Composer tool to return results that include our target transaction.
Visit this Alchemy Composer Example!
Trying out Alchemy Transfers API on Polygon via Python
Now, to try out the Alchemy Transfers API we query for the same transfer; this time, however, we use code! If you want to follow along, fork the starter script.
1. Import Statements:
To try out Alchemy Transfers API, we start off with a few import statements to import modules we’ll use later.
import json
from web3 import Web3
import requests
If you don’t have any of these modules around installed in your python environment, be sure to run the following pip commands in your python environment.
pip install web3
pip install requests
2. Insert Alchemy Key for API access:
If you don’t already have one, you’ll first need to create an account on Alchemy. The free version will work fine for getting started!
Replace the string “ALCHEMY KEY” with your own private API key.
ALCHEMY_KEY = “ALCHEMY KEY”
w3 = Web3(Web3.HTTPProvider('https://polygon-mainnet.alchemyapi.io/v2/'+ALCHEMY_KEY))
3. Configure Web3.py to handle ERC20 contracts
Since we are working with USDT, an ERC20 contract, we need an additional piece of code on top of what we would normally call in Web3 to interact with our contract correctly. Note that we include the ERC20 ABI in this code snippet in order to properly read the USDT contract.
(The Contract Application Binary Interface (ABI) is the standard way to interact with contracts in the Ethereum ecosystem and we use the ERC20 ABI to interact with ERC20 contracts such as the USDT contract)
ERC20_ABI = json.loads('[{"constant":true,"inputs":[],"name":"name","outputs"......{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]')
(For readability, the entire ERC20 ABI is not included in the above code snippet. To find the full ABI, visit this Github Gist)
4. Set variables.
As described above, we configure our variables to point towards the right addresses and block numbers. In addition, we use the w3.eth.contract method so that we can read data via the USDT contract.
USDT_ADDRESS = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F'
FROM_ADDRESS = '0x5350E1068f0E138ff306990B16fA4910d970c692'
TO_ADDRESS = '0x9d2b758E3ffd2569c6956676fAE7f8B71A53Ffb5'
from_Block = '0x16C5376'
to_Block = '0x16C537A'
usdt = w3.eth.contract(address=USDT_ADDRESS, abi=ERC20_ABI)
5. Query via the Alchemy Transfers API
Here, we POST a request to the Alchemy Transfers API. Embedded in our request is the specific alchemy_getAssetTransfers method that we call and all the previous parameters [From Block & To Block, To & From Addresses, and Contract Address]
Note that we also process the JSON result and parse it to give us the exact USDT value that was transferred within the transaction that our query returns.
transfer_json = requests.post('https://polygon-mainnet.g.alchemy.com/v2/'+ALCHEMY_KEY, json={"jsonrpc": "2.0","id": 0,"method": "alchemy_getAssetTransfers","params": [{"fromBlock": from_Block,"toBlock": to_Block,"fromAddress": FROM_ADDRESS,"toAddress": TO_ADDRESS,"contractAddresses": [USDT_ADDRESS],"category": ["erc20"]}]})
json_response = transfer_json.json()
transfer_val = (json_response['result']['transfers'][0]['rawContract']['value'])
6. Convert units for readability!
After receiving and parsing the USDT value from the JSON response, we then convert the hexadecimal string into decimal format and do a unit conversion!
# convert hexadecimal make to decimal format
val = (int(transfer_val, 16))
print("USDT TRANSFERED:")
print("--> FROM: " + FROM_ADDRESS)
print("--> TO: " + TO_ADDRESS)
# unit conversion!
print(val/1000000)
Final command line output:
Congratulations! You have now successfully queried from the Alchemy Transfers API on Polygon. As a next project, try querying for other types of token transfers!
With Alchemy Transfers API, you can build historical queries into Polygon dApps to populate historical wallet activity and token transfers, allowing you to develop more user-friendly UI and create more detailed on-chain analytics. Take advantage of Layer 2 cheap fees and keep your users informed about their plethora of on-chain transaction activity both in the present and the past!
Related articles
Preparing for the Agave 2.0 Upgrade
ERC-1271 Signature Replay Vulnerability
On October 27th 2023, Alchemy discovered a ERC1271 contract signature replay vulnerability that affected a large number of smart contract accounts (SCA), and led to risks when interacting with several applications.
What is RIP-7212? Precompile for secp256r1 Curve Support
RIP-7212 is a core change in the Ethereum protocol that opens up a way to have cheap, secure, and fast P256 curve verification with a precompiled contract.