This code uses the eth_getLogs method to retrieve logs. Logs are generated when an event is emitted from a smart contract. We look at the transfer
event from ERC-20 contracts in this case.
Here is how logs work:
The transfer event in the ERC-20 contract looks like this:
event Transfer(address indexed from, address indexed to, uint value);
The indexed parameters will be part of the topics
, while the non-indexed (value in this case) will be part of data
. When a transfer happens, the contract emits the event with the following:
- The address that made the transfer
- The address that received the transfer
- The amount transferred
We create a logs filter object in the Python code using the ERC-20 contract address, the range of blocks to get the logs from, and the topics.
The topics essentially define what we want to retrieve.
The first element of the topics is always the event signature, which is the keccak hash of the event name and the kind of parameter. In this case, it is the following:
Transfer(address,address,uint256)
Which becomes:
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
The other element of the topic is the first indexed parameter (the from address in this case), and it has to be encoded as a 32 bytes element. That's why all of the zeros are in front.
We can talk more about how to encode the elements if you want, but the TL;DR is that this filter tracks all of the USDT transfers made by this address 0x8c8d7c46219d9205f056f28fee5950ad564d7465.
I added some code to make the response more legible so that I can explain. The response will look like this:
address: 0xdAC17F958D2ee523a2206206994597C13D831ec7
topics: [HexBytes('0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'), HexBytes('0x0000000000000000000000008c8d7c46219d9205f056f28fee5950ad564d7465'), HexBytes('0x000000000000000000000000c1e076085fdfca8e7faee36be340b7335330a685')]
data: 0x000000000000000000000000000000000000000000000000000000000ec481a6
blockNumber: 16878247
transactionHash: b'\xb1\x03\xfak6\xe5C\xac\x1a\x05\xc9\xeb\xdd\xc8\xceS\xd9\xf0\xe4+J \xa4\xd3\xfc\xcd\xc9\xc0\x8b\xbd\xbd6'
transactionIndex: 149
blockHash: b'\xb43~\xdd\xc7\x81\xfd\xcf\xd9?\x0e\xc6\xd8\x8d\xc6q^\x03\xdc\xb9=\xee\xab\x80\x112x\x08\xf2\xd6\xd1z'
logIndex: 336
removed: False
The data that interest you is in the topics and data field.
As we said, topics tell you the kind of event and indexed parameters. So, in this case, it shows that address 0x8c8d7c46219d9205f056f28fee5950ad564d7465 sent some USDT to address 0xc1e076085fdfca8e7faee36be340b7335330a685. The amount of tokens is emitted by the event is and is not indexed, so it will be in the data field. This follows the same principle; it's a 32-byte element, so you must remove the zeros before the data. In this case, the amount transferred is ec481a6, which equals 247759270. USDT has 6 decimals, so that becomes 247.759270 USDT.
You can also see the log emitted on Etherscan: https://etherscan.io/tx/0xb103fa6b36e543ac1a05c9ebddc8ce53d9f0e42b4a20a4d3fccdc9c08bbdbd36#eventlog
You can edit the erc_20_contract variable to the smart contract you need to track and the second topic for the specific address. The chain will also have all of the previous transfers saved, but I recommend querying a max of 2000/3000 blocks at the time.