banteg / multicall.py

aggregate results of multiple smart contract calls into one
MIT License
251 stars 108 forks source link

Getting 'message': 'invalid opcode: SHR' Error while doing mutlicall with historical block number #70

Closed ashrita-systango closed 5 months ago

ashrita-systango commented 1 year ago

Hi,

I have written a script that takes multiple wallet/account address, token address & block number, then it prepares a multicall & call the function. For recent block numbers I get the proper result but for block number which are old like block numbers from 2017 or 2018 it gives invalid opcode SHR error. If I make the same contract function call via web3 library then it returns the result as expected.

I am getting error till block number 7256659 on ethereum.

Below is the sample code for Multicall on ETH chain:

from web3 import Web3
from web3.middleware import geth_poa_middleware
from multicall import Call, Multicall

addresses = [{'walletAddress': '0x536480A12fa7A2934872448752F864Cd0F9ba796', 'tokenAddress': '0xa74476443119a942de498590fe1f2454d7d4ac0d'}]

block_number = 4310318
GET_BALANCE_FN = "balanceOf(address)(uint256)"

def call_back_obj(success, value):
    if success is True:
        return value
    else:
        return False

node_provider = 'eth_node_provider_url'

def get_web3_instance():
    w3 = Web3(Web3.HTTPProvider(node_provider))
    w3.middleware_onion.inject(geth_poa_middleware, layer=0)
    return w3

_w3 = get_web3_instance()

def token_balance_handler(addresses, block_number=None):
    calls = []
    for address in addresses:
        contract_addr = address.get("tokenAddress")
        wallet_addr = address.get("walletAddress")
        calls.append(
            Call(
                contract_addr,
                [GET_BALANCE_FN, (wallet_addr)],
                [[f"{wallet_addr}-{contract_addr}", call_back_obj]],
            )
        )
    return Multicall(
                calls, _w3=_w3, block_id=block_number, require_success=False
            )

print(token_balance_handler(addresses, block_number)())

Sample code for contract function call via web3:

from web3 import Web3

node_provider_url = ""
# connect to Ethereum network
web3 = Web3(Web3.HTTPProvider(node_provider_url))

# set the address and ABI of the contract
contract_address = '0xa74476443119A942dE498590Fe1f2454d7D4aC0d'
contract_abi = [{'constant': True, 'inputs': [{'name': 'account', 'type': 'address'}], 'name': 'balanceOf', 'outputs': [{'name': '', 'type': 'uint256'}], 'payable': False, 'stateMutability': 'view', 'type': 'function'}]

# create a contract object
contract = web3.eth.contract(address=contract_address, abi=contract_abi)

# specify block number
block_number = 4310318

# call the balanceOf function at specific block number
account_address = '0x536480A12fa7A2934872448752F864Cd0F9ba796'
balance = contract.functions.balanceOf(account_address).call(block_identifier=block_number)

print(f'The balance of {account_address} at block {block_number} is {balance} tokens.')
BobTheBuidler commented 1 year ago

This is interesting, I checked the deploy block for both GNT and for the multicall2 contract, neither one seems to coincide with the block at which you see the issue start.

Does this error replicate on another node?

BobTheBuidler commented 5 months ago

going to close this due to no activity. Feel free to reopen if this is still an issue.