15

I'm trying to obtain all the transactions of a contract, but in all cases I only obtained [] or undefined.

I'm following this posts:

And I read others posts too, but i can't solve my problem.

I try to use this:

var filter=web3.eth.filter({fromBlock: 866705, toBlock: 909023, address: contractAddress});
filter.get(function(error, log) {
  console.log(JSON.stringify(log));
});
filter.stopWatching(); 

With different values of fromblock, to block and the others options ('latest',fromblock: 0 , ...). But i don't obtain any result.

I'm trying to do this :

var filter = web3.eth.filter({fromBlock:9000, toBlock: 'latest', address: contractAddress});
filter.get(function(error, result) {
  if(!error){
    var info = web3.eth.getBlock(result , function(error, result){
       if(!error){
         var trans = web3.eth.getTransaction(result.transactions[1], function(error,result){
           if(!error){
             var str = web3.toAscii(result.input,);
             console.log(str);
           }else{
              console.log(error);
           }
         });
       }else{
          console.log(error);
       }
     });
 }else{
    console.log(error);
  }
})

(If i forget some token sorry)

All of this only for obtain the data of a transaction like "from", "to" and "input". Where is the problem?

More information:

  • I'm using metamask and meteor.js
  • I'm running this in Ropsten test-net
  • If I use the function web3.eth.getBlock wiht a correct blocknumber I can obtain all the data, the problem is the filter and how I use it.
2
  • IN the first snippet, I suspect that filter.stopWatching executes before the callback has a chance to work. The way it's laid out suggests an expectation that those commands will execute in order, but it's not the case with JavaScript. I would consider commenting out filter.stopWatching and start from block 0, then build up complexity after I see it work. Hope it helps. May 12, 2017 at 18:29
  • @Rob Hitchens yes man, I think the problem lies in the order and speed of javascript execution, but i don't found how to fix it.
    – Gawey
    May 15, 2017 at 7:20

4 Answers 4

12

Another way (perhaps much simpler) to get a list of transactions on an account is to use an API from a block scraper such as http://etherscan.io. The trouble with this is it's fully centralized.

A fully decentralized way is go against the node (as you're doing). The trouble here is that, while it is decentralized, it's slow. Especially if your smart contract has a very long transaction history.

An even deeper problem with going against the node is that simply getting the transactions is not enough. You will also need to get the transaction receipts. You need these to determine if the transactions completed with an error or not.

Worse yet even than that is incoming message calls (what used to be called internal transactions). These are "transactions" initiated by an outside smart contract directly into your address. These "transactions" do not appear on the blockchain directly, but are buried down in an internal trace of the initiating transaction. If you're looking only at your address, these will be missed.

7
  • My smart contract don't ahve a very long transaction but is slow too. I read about internal trnasactions, but i test it and my transaction don't are internals because in etherescan.io they doesn't put this transactions like internals transactions in their blocks scaned's. I will try the api of etehrscan.io, but this is a hotfix not a real fix for this problem :/
    – Gawey
    May 15, 2017 at 7:24
  • Etherscan's public API for this use case seems to be deprecated...
    – CQM
    Aug 16, 2017 at 22:29
  • @CQM I'm not seeing that, but maybe I missed it. Do you have s link? Aug 16, 2017 at 22:56
  • etherscan.io/apis#tokens see the deprecated ones, is there a more applicable endpoint?
    – CQM
    Aug 16, 2017 at 23:12
  • I'm guessing, but I would bet they depreciated it because it was a maintenance issue. You don't have etherscan, you could use the RPC directly against a node. Aug 17, 2017 at 3:37
2

Arrays are indexed starting from '0'. You're indexing from '1'. Try transactions[0].

1

Summary

Querying a node directly for all transactions is difficult due to the way the blockchain stores data. Blockchains like Ethereum aren't relational databases themselves and are not designed for easy querying. They are a string a blocks connected to each other, a sort of linked list.

Because of this, if all you have is a node, you would need to "brute force" go through each block, gather a list of all transactions, and check if the transaction originates or is sent to the address you are looking for. Additionally, you'd need an archive node to do this.

This is often time-consuming, so a faster method that's commonly used would be to use a service that has its own database and sorts transactions into it to be easily queried.

Let's look at both, and examples of each.

How we will do this

For our example, we will use the Ethereum Mainnet Aave token, as it's a proxy contract and we can also show some event querying aspects like "how many times it's been upgraded by governance".

Brute Force

Here is an example of brute force getting transactions with web3.py. We add a start block and end block, because otherwise you're going to make a bajillion calls to your node.

import os

from web3 import Web3

START_BLOCK = 17950195
END_BLOCK = 17950197


def main():
    w3 = Web3(Web3.HTTPProvider(os.getenv("RPC_URL")))
    for block in range(START_BLOCK, END_BLOCK):
        block = w3.eth.get_block(block, full_transactions=True)
        for transaction in block.transactions:
            print(transaction["hash"])


if __name__ == "__main__":
    main()

The "brute force" way would involve going block-by-block transaction-by-transaction till you find all the events you're looking for, and can take a very long time.

And here is the worst part this list is non-exhaustive. If your address is a contract, contracts can make transactions to and from each other in a single transaction, but will not be the main "to" or "from".

For example:

person A calls "doStuff" on -> contract B
"from" == person A
"to" == contract B

If "doStuff" on contract B calls -> contract C

"from" and "to" will still just be A & B even though we interacted with C. 
The python code above would miss this contract to contract call. 

To get all of those transactions, you'd have to debug each transaction, keep track of the stack and keep track of which opcodes interact with other contracts.

It's a pretty laborious and time-intensive process. So the python code shown above is actually just a subset of all transactions that interact with an address.

You could write all this, but most op to go with indexing transactions into a easier to query database, or use a service that makes it easier.

Centralized / Service Techniques

Etherscan (UI)

One of the easist ways to get a list of transactions (and internal transactions) is to use a block explorer like etherscan.

For our Aave token, it's very easy to see a list of transactions. And if we select internal and toggle onadvanced we can see a list of contracts that have interacted with Etherscan.

On Etherscan's back end, they are indexing all this data for us, so we can "see" it easier.

enter image description here

They also have an advanced filtered mode, but getting exactly what you want can be a little tricky.

Dune Analytics

Dune analytics indexes blockchain "stuff" so that you can query it as if it's a SQL database. For example, we can easily see all transactions of our Aave token.

SELECT
  *
FROM ethereum.traces
WHERE
  "from" = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
  or "to" = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9

Dune comes with a table known as ethereum.traces which includes all these contract -> contract transactions. The query above will find EVERY transaction that interacted with the Aave token, or the Aave token interacted with.

Alchemy / QuickNode / Etc

Note: For this we are using a Python SDK I made to make it easier to work with the Alchemy API, but you could just as easily just call the Alchemy API directly with your language of choice.

Another popular method would be to use something like Alchemy's getAssetTransfers which does something similar.

They similarly have options to get all regular transactions, traces (which they call internal) etc.

import os

from alchemy_sdk_py import Alchemy

ALCHEMY_API_KEY = os.getenv("ALCHEMY_API_KEY")
CHAIN_ID = 1
MY_ADDRESS = "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"  # Aave token on ETH Mainnet


def main():
    alchemy = Alchemy(network=CHAIN_ID)
    transfers = alchemy.get_asset_transfers(to_address=MY_ADDRESS)
    # this is a paginated version, we could add  `get_all_flag=True` but we'd make a LOT of API calls!
    print(transfers)


if __name__ == "__main__":
    main()

Bonus: How to get all transactions that emitted a certain event

Let's say I want to find all the times the Aave tokens was upgraded by governance and emitted the Upgraded(address) event.

First, we'd get the topic0 of the event (the hash of the event signature). If I use foundry's cast I get:

cast keccak "Upgraded(address)
0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b

Brute Force

Skipped, but you'd do something similar to above.

Dune

SELECT
  *
FROM ethereum.logs
WHERE
  "contract_address" = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9
AND topic0 = from_hex('bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b')

Etherscan

I'm not sure at this time.

Alchemy

import os

from alchemy_sdk_py import Alchemy

ALCHEMY_API_KEY = os.getenv("ALCHEMY_API_KEY")
CHAIN_ID = 1
MY_ADDRESS = "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9"  # Aave token on ETH Mainnet


def main():
    alchemy = Alchemy(network=CHAIN_ID)
    upgraded_events = alchemy.get_logs(
        contract_address=MY_ADDRESS,
        topics=["0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b"],
    )
    print(upgraded_events)


if __name__ == "__main__":
    main()
-2

The answer is rather simple. I also tried to solve this by coding my way through it. Etherscan has a feature allowing you to download all the transactions as a csv file. At the bottom of the page: Download CSV Export

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.