From 8ebcbbf47926d15e7312a57ac7d3c4207e63c304 Mon Sep 17 00:00:00 2001 From: Mohamed Sohail Date: Tue, 17 May 2022 20:33:03 +0300 Subject: [PATCH] add: (wip) on-chain balance query (#5) * add: smart-contracts * add: implement and test changes to contract: - returns 0 instead of false error status - func return type is []big.Int * fix: test name * fix: (test) env var name --- README.md | 1 + batch_balance/batch_balance.go | 32 ++++++++++ batch_balance/batch_balance_test.go | 31 ++++++++++ batch_balance/smart-contract/Balances.sol | 48 +++++++++++++++ .../smart-contract/artifacts/abi.json | 38 ++++++++++++ .../smart-contract/artifacts/bytecode.json | 8 +++ batch_balance/token_balances.go | 24 ++++++++ batch_balance/token_balances_test.go | 59 +++++++++++++++++++ net/cic_net.go | 3 +- net/cic_net_test.go | 5 +- 10 files changed, 246 insertions(+), 3 deletions(-) create mode 100644 batch_balance/batch_balance.go create mode 100644 batch_balance/batch_balance_test.go create mode 100644 batch_balance/smart-contract/Balances.sol create mode 100644 batch_balance/smart-contract/artifacts/abi.json create mode 100644 batch_balance/smart-contract/artifacts/bytecode.json create mode 100644 batch_balance/token_balances.go create mode 100644 batch_balance/token_balances_test.go diff --git a/README.md b/README.md index 9901113..a01d3c9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Go modules to access various parts of the cic stack - meta (web2 metadata store) - net (cic smart contracts) +- batch balance query (`0xb9e215B789e9Ec6643Ba4ff7b98EA219F38c6fE5`) ## Installation diff --git a/batch_balance/batch_balance.go b/batch_balance/batch_balance.go new file mode 100644 index 0000000..68b4325 --- /dev/null +++ b/batch_balance/batch_balance.go @@ -0,0 +1,32 @@ +package balance + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" +) + +type BatchBalance struct { + ethClient *w3.Client + batchContract common.Address +} + +func NewBatchBalance(rpcEndpoint string, batchContract common.Address) (*BatchBalance, error) { + ethClient, err := w3.Dial(rpcEndpoint) + if err != nil { + return nil, err + } + + return &BatchBalance{ + ethClient: ethClient, + batchContract: batchContract, + }, nil +} + +func (c *BatchBalance) Close() error { + err := c.ethClient.Close() + if err != nil { + return err + } + + return nil +} diff --git a/batch_balance/batch_balance_test.go b/batch_balance/batch_balance_test.go new file mode 100644 index 0000000..c863640 --- /dev/null +++ b/batch_balance/batch_balance_test.go @@ -0,0 +1,31 @@ +package balance + +import ( + "os" + "testing" + + "github.com/lmittmann/w3" +) + +type tConfig struct { + rpcProvider string + batchContract string +} + +var conf = &tConfig{ + rpcProvider: os.Getenv("RPC_PROVIDER"), + batchContract: os.Getenv("BATCH_CONTRACT"), +} + +func TestBatchBalance_Connect(t *testing.T) { + name := "Test RPC connection" + wantErr := false + + cicnet, _ := NewBatchBalance(conf.rpcProvider, w3.A(conf.batchContract)) + + t.Run(name, func(t *testing.T) { + if err := cicnet.Close(); (err != nil) != wantErr { + t.Errorf("Close() error = %v, wantErr %v", err, wantErr) + } + }) +} diff --git a/batch_balance/smart-contract/Balances.sol b/batch_balance/smart-contract/Balances.sol new file mode 100644 index 0000000..fff3844 --- /dev/null +++ b/batch_balance/smart-contract/Balances.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT + +// Adapted from https://github.com/MyCryptoHQ/eth-scan + +pragma solidity >= 0.8.0; + +contract Balances { + struct Result { + bool success; + uint256 balance; + } + + function tokensBalance(address owner, address[] calldata contracts) external view returns (Result[] memory results) { + results = new Result[](contracts.length); + + bytes memory data = abi.encodeWithSignature("balanceOf(address)", owner); + + for (uint256 i = 0; i < contracts.length; i++) { + results[i] = staticCall(contracts[i], data, 8000000); + } + } + + function staticCall( + address target, + bytes memory data, + uint256 gas + ) private view returns (Result memory) { + uint256 size = codeSize(target); + + if (size > 0) { + (bool success, bytes memory result) = target.staticcall{ gas: gas }(data); + if (success) { + uint256 balance = abi.decode(result, (uint256)); + return Result(success, balance); + } + } + + return Result(false, 0); + } + + function codeSize(address _address) private view returns (uint256 size) { + // solhint-disable-next-line no-inline-assembly + assembly { + size := extcodesize(_address) + } + } +} + diff --git a/batch_balance/smart-contract/artifacts/abi.json b/batch_balance/smart-contract/artifacts/abi.json new file mode 100644 index 0000000..d803b14 --- /dev/null +++ b/batch_balance/smart-contract/artifacts/abi.json @@ -0,0 +1,38 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address[]", + "name": "contracts", + "type": "address[]" + } + ], + "name": "tokensBalance", + "outputs": [ + { + "components": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + } + ], + "internalType": "struct Balances.Result[]", + "name": "results", + "type": "tuple[]" + } + ], + "stateMutability": "view", + "type": "function" + } +] \ No newline at end of file diff --git a/batch_balance/smart-contract/artifacts/bytecode.json b/batch_balance/smart-contract/artifacts/bytecode.json new file mode 100644 index 0000000..cfaf533 --- /dev/null +++ b/batch_balance/smart-contract/artifacts/bytecode.json @@ -0,0 +1,8 @@ +{ + "functionDebugData": {}, + "generatedSources": [], + "linkReferences": {}, + "object": "608060405234801561001057600080fd5b50610793806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063e5da1b6814610030575b600080fd5b61004a60048036038101906100459190610392565b610060565b6040516100579190610554565b60405180910390f35b60608282905067ffffffffffffffff81111561007f5761007e6106e7565b5b6040519080825280602002602001820160405280156100b857816020015b6100a56102c9565b81526020019060019003908161009d5790505b5090506000846040516024016100ce9190610539565b6040516020818303038152906040527f70a08231000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060005b848490508110156101c157610190858583818110610171576101706106b8565b5b90506020020160208101906101869190610365565b83627a12006101ca565b8382815181106101a3576101a26106b8565b5b602002602001018190525080806101b990610640565b915050610150565b50509392505050565b6101d26102c9565b60006101dd856102be565b9050600081111561029a576000808673ffffffffffffffffffffffffffffffffffffffff1685876040516102119190610522565b6000604051808303818686fa925050503d806000811461024d576040519150601f19603f3d011682016040523d82523d6000602084013e610252565b606091505b509150915081156102975760008180602001905181019061027391906103f2565b905060405180604001604052808415158152602001828152509450505050506102b7565b50505b604051806040016040528060001515815260200160008152509150505b9392505050565b6000813b9050919050565b6040518060400160405280600015158152602001600081525090565b6000813590506102f48161072f565b92915050565b60008083601f8401126103105761030f61071b565b5b8235905067ffffffffffffffff81111561032d5761032c610716565b5b60208301915083602082028301111561034957610348610720565b5b9250929050565b60008151905061035f81610746565b92915050565b60006020828403121561037b5761037a61072a565b5b6000610389848285016102e5565b91505092915050565b6000806000604084860312156103ab576103aa61072a565b5b60006103b9868287016102e5565b935050602084013567ffffffffffffffff8111156103da576103d9610725565b5b6103e6868287016102fa565b92509250509250925092565b6000602082840312156104085761040761072a565b5b600061041684828501610350565b91505092915050565b600061042b83836104e4565b60408301905092915050565b610440816105c5565b82525050565b600061045182610586565b61045b81856105a9565b935061046683610576565b8060005b8381101561049757815161047e888261041f565b97506104898361059c565b92505060018101905061046a565b5085935050505092915050565b6104ad816105d7565b82525050565b60006104be82610591565b6104c881856105ba565b93506104d881856020860161060d565b80840191505092915050565b6040820160008201516104fa60008501826104a4565b50602082015161050d6020850182610513565b50505050565b61051c81610603565b82525050565b600061052e82846104b3565b915081905092915050565b600060208201905061054e6000830184610437565b92915050565b6000602082019050818103600083015261056e8184610446565b905092915050565b6000819050602082019050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b60006105d0826105e3565b9050919050565b60008115159050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60005b8381101561062b578082015181840152602081019050610610565b8381111561063a576000848401525b50505050565b600061064b82610603565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561067e5761067d610689565b5b600182019050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b610738816105c5565b811461074357600080fd5b50565b61074f81610603565b811461075a57600080fd5b5056fea26469706673582212209258960544fe4eb19cf9941592e1738fbb2198350b5d9438ae4426256d76a3ea64736f6c63430008070033", + "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x793 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x2B JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0xE5DA1B68 EQ PUSH2 0x30 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x4A PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x45 SWAP2 SWAP1 PUSH2 0x392 JUMP JUMPDEST PUSH2 0x60 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x57 SWAP2 SWAP1 PUSH2 0x554 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH1 0x60 DUP3 DUP3 SWAP1 POP PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x7F JUMPI PUSH2 0x7E PUSH2 0x6E7 JUMP JUMPDEST JUMPDEST PUSH1 0x40 MLOAD SWAP1 DUP1 DUP3 MSTORE DUP1 PUSH1 0x20 MUL PUSH1 0x20 ADD DUP3 ADD PUSH1 0x40 MSTORE DUP1 ISZERO PUSH2 0xB8 JUMPI DUP2 PUSH1 0x20 ADD JUMPDEST PUSH2 0xA5 PUSH2 0x2C9 JUMP JUMPDEST DUP2 MSTORE PUSH1 0x20 ADD SWAP1 PUSH1 0x1 SWAP1 SUB SWAP1 DUP2 PUSH2 0x9D JUMPI SWAP1 POP JUMPDEST POP SWAP1 POP PUSH1 0x0 DUP5 PUSH1 0x40 MLOAD PUSH1 0x24 ADD PUSH2 0xCE SWAP2 SWAP1 PUSH2 0x539 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH1 0x20 DUP2 DUP4 SUB SUB DUP2 MSTORE SWAP1 PUSH1 0x40 MSTORE PUSH32 0x70A0823100000000000000000000000000000000000000000000000000000000 PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF NOT AND PUSH1 0x20 DUP3 ADD DUP1 MLOAD PUSH28 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP4 DUP2 DUP4 AND OR DUP4 MSTORE POP POP POP POP SWAP1 POP PUSH1 0x0 JUMPDEST DUP5 DUP5 SWAP1 POP DUP2 LT ISZERO PUSH2 0x1C1 JUMPI PUSH2 0x190 DUP6 DUP6 DUP4 DUP2 DUP2 LT PUSH2 0x171 JUMPI PUSH2 0x170 PUSH2 0x6B8 JUMP JUMPDEST JUMPDEST SWAP1 POP PUSH1 0x20 MUL ADD PUSH1 0x20 DUP2 ADD SWAP1 PUSH2 0x186 SWAP2 SWAP1 PUSH2 0x365 JUMP JUMPDEST DUP4 PUSH3 0x7A1200 PUSH2 0x1CA JUMP JUMPDEST DUP4 DUP3 DUP2 MLOAD DUP2 LT PUSH2 0x1A3 JUMPI PUSH2 0x1A2 PUSH2 0x6B8 JUMP JUMPDEST JUMPDEST PUSH1 0x20 MUL PUSH1 0x20 ADD ADD DUP2 SWAP1 MSTORE POP DUP1 DUP1 PUSH2 0x1B9 SWAP1 PUSH2 0x640 JUMP JUMPDEST SWAP2 POP POP PUSH2 0x150 JUMP JUMPDEST POP POP SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH2 0x1D2 PUSH2 0x2C9 JUMP JUMPDEST PUSH1 0x0 PUSH2 0x1DD DUP6 PUSH2 0x2BE JUMP JUMPDEST SWAP1 POP PUSH1 0x0 DUP2 GT ISZERO PUSH2 0x29A JUMPI PUSH1 0x0 DUP1 DUP7 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND DUP6 DUP8 PUSH1 0x40 MLOAD PUSH2 0x211 SWAP2 SWAP1 PUSH2 0x522 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP7 DUP7 STATICCALL SWAP3 POP POP POP RETURNDATASIZE DUP1 PUSH1 0x0 DUP2 EQ PUSH2 0x24D JUMPI PUSH1 0x40 MLOAD SWAP2 POP PUSH1 0x1F NOT PUSH1 0x3F RETURNDATASIZE ADD AND DUP3 ADD PUSH1 0x40 MSTORE RETURNDATASIZE DUP3 MSTORE RETURNDATASIZE PUSH1 0x0 PUSH1 0x20 DUP5 ADD RETURNDATACOPY PUSH2 0x252 JUMP JUMPDEST PUSH1 0x60 SWAP2 POP JUMPDEST POP SWAP2 POP SWAP2 POP DUP2 ISZERO PUSH2 0x297 JUMPI PUSH1 0x0 DUP2 DUP1 PUSH1 0x20 ADD SWAP1 MLOAD DUP2 ADD SWAP1 PUSH2 0x273 SWAP2 SWAP1 PUSH2 0x3F2 JUMP JUMPDEST SWAP1 POP PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 DUP5 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD DUP3 DUP2 MSTORE POP SWAP5 POP POP POP POP POP PUSH2 0x2B7 JUMP JUMPDEST POP POP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP2 POP POP JUMPDEST SWAP4 SWAP3 POP POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 EXTCODESIZE SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 PUSH1 0x40 ADD PUSH1 0x40 MSTORE DUP1 PUSH1 0x0 ISZERO ISZERO DUP2 MSTORE PUSH1 0x20 ADD PUSH1 0x0 DUP2 MSTORE POP SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0x2F4 DUP2 PUSH2 0x72F JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 DUP4 PUSH1 0x1F DUP5 ADD SLT PUSH2 0x310 JUMPI PUSH2 0x30F PUSH2 0x71B JUMP JUMPDEST JUMPDEST DUP3 CALLDATALOAD SWAP1 POP PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x32D JUMPI PUSH2 0x32C PUSH2 0x716 JUMP JUMPDEST JUMPDEST PUSH1 0x20 DUP4 ADD SWAP2 POP DUP4 PUSH1 0x20 DUP3 MUL DUP4 ADD GT ISZERO PUSH2 0x349 JUMPI PUSH2 0x348 PUSH2 0x720 JUMP JUMPDEST JUMPDEST SWAP3 POP SWAP3 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD SWAP1 POP PUSH2 0x35F DUP2 PUSH2 0x746 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x37B JUMPI PUSH2 0x37A PUSH2 0x72A JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0x389 DUP5 DUP3 DUP6 ADD PUSH2 0x2E5 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 PUSH1 0x0 PUSH1 0x40 DUP5 DUP7 SUB SLT ISZERO PUSH2 0x3AB JUMPI PUSH2 0x3AA PUSH2 0x72A JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0x3B9 DUP7 DUP3 DUP8 ADD PUSH2 0x2E5 JUMP JUMPDEST SWAP4 POP POP PUSH1 0x20 DUP5 ADD CALLDATALOAD PUSH8 0xFFFFFFFFFFFFFFFF DUP2 GT ISZERO PUSH2 0x3DA JUMPI PUSH2 0x3D9 PUSH2 0x725 JUMP JUMPDEST JUMPDEST PUSH2 0x3E6 DUP7 DUP3 DUP8 ADD PUSH2 0x2FA JUMP JUMPDEST SWAP3 POP SWAP3 POP POP SWAP3 POP SWAP3 POP SWAP3 JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0x408 JUMPI PUSH2 0x407 PUSH2 0x72A JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0x416 DUP5 DUP3 DUP6 ADD PUSH2 0x350 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x42B DUP4 DUP4 PUSH2 0x4E4 JUMP JUMPDEST PUSH1 0x40 DUP4 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0x440 DUP2 PUSH2 0x5C5 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x451 DUP3 PUSH2 0x586 JUMP JUMPDEST PUSH2 0x45B DUP2 DUP6 PUSH2 0x5A9 JUMP JUMPDEST SWAP4 POP PUSH2 0x466 DUP4 PUSH2 0x576 JUMP JUMPDEST DUP1 PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x497 JUMPI DUP2 MLOAD PUSH2 0x47E DUP9 DUP3 PUSH2 0x41F JUMP JUMPDEST SWAP8 POP PUSH2 0x489 DUP4 PUSH2 0x59C JUMP JUMPDEST SWAP3 POP POP PUSH1 0x1 DUP2 ADD SWAP1 POP PUSH2 0x46A JUMP JUMPDEST POP DUP6 SWAP4 POP POP POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0x4AD DUP2 PUSH2 0x5D7 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x4BE DUP3 PUSH2 0x591 JUMP JUMPDEST PUSH2 0x4C8 DUP2 DUP6 PUSH2 0x5BA JUMP JUMPDEST SWAP4 POP PUSH2 0x4D8 DUP2 DUP6 PUSH1 0x20 DUP7 ADD PUSH2 0x60D JUMP JUMPDEST DUP1 DUP5 ADD SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x40 DUP3 ADD PUSH1 0x0 DUP3 ADD MLOAD PUSH2 0x4FA PUSH1 0x0 DUP6 ADD DUP3 PUSH2 0x4A4 JUMP JUMPDEST POP PUSH1 0x20 DUP3 ADD MLOAD PUSH2 0x50D PUSH1 0x20 DUP6 ADD DUP3 PUSH2 0x513 JUMP JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH2 0x51C DUP2 PUSH2 0x603 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x52E DUP3 DUP5 PUSH2 0x4B3 JUMP JUMPDEST SWAP2 POP DUP2 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0x54E PUSH1 0x0 DUP4 ADD DUP5 PUSH2 0x437 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP DUP2 DUP2 SUB PUSH1 0x0 DUP4 ADD MSTORE PUSH2 0x56E DUP2 DUP5 PUSH2 0x446 JUMP JUMPDEST SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 MLOAD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP3 DUP3 MSTORE PUSH1 0x20 DUP3 ADD SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x5D0 DUP3 PUSH2 0x5E3 JUMP JUMPDEST SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 ISZERO ISZERO SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 AND SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 JUMPDEST DUP4 DUP2 LT ISZERO PUSH2 0x62B JUMPI DUP1 DUP3 ADD MLOAD DUP2 DUP5 ADD MSTORE PUSH1 0x20 DUP2 ADD SWAP1 POP PUSH2 0x610 JUMP JUMPDEST DUP4 DUP2 GT ISZERO PUSH2 0x63A JUMPI PUSH1 0x0 DUP5 DUP5 ADD MSTORE JUMPDEST POP POP POP POP JUMP JUMPDEST PUSH1 0x0 PUSH2 0x64B DUP3 PUSH2 0x603 JUMP JUMPDEST SWAP2 POP PUSH32 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF DUP3 EQ ISZERO PUSH2 0x67E JUMPI PUSH2 0x67D PUSH2 0x689 JUMP JUMPDEST JUMPDEST PUSH1 0x1 DUP3 ADD SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x11 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x32 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH32 0x4E487B7100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 MSTORE PUSH1 0x41 PUSH1 0x4 MSTORE PUSH1 0x24 PUSH1 0x0 REVERT JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x738 DUP2 PUSH2 0x5C5 JUMP JUMPDEST DUP2 EQ PUSH2 0x743 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH2 0x74F DUP2 PUSH2 0x603 JUMP JUMPDEST DUP2 EQ PUSH2 0x75A JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 SWAP3 PC SWAP7 SDIV DIFFICULTY INVALID 0x4E 0xB1 SWAP13 0xF9 SWAP5 ISZERO SWAP3 0xE1 PUSH20 0x8FBB2198350B5D9438AE4426256D76A3EA64736F PUSH13 0x63430008070033000000000000 ", + "sourceMap": "60:1201:0:-:0;;;;;;;;;;;;;;;;;;;" +} \ No newline at end of file diff --git a/batch_balance/token_balances.go b/batch_balance/token_balances.go new file mode 100644 index 0000000..b51f2da --- /dev/null +++ b/batch_balance/token_balances.go @@ -0,0 +1,24 @@ +package balance + +import ( + "context" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" + "github.com/lmittmann/w3/module/eth" +) + +func (c *BatchBalance) TokensBalance(ctx context.Context, owner common.Address, tokens []common.Address) ([]*big.Int, error) { + var balancesResults []*big.Int + + err := c.ethClient.CallCtx( + ctx, + eth.CallFunc(w3.MustNewFunc("tokensBalance(address owner, address[] contracts)", "uint256[]"), c.batchContract, owner, tokens).Returns(&balancesResults), + ) + if err != nil { + return nil, err + } + + return balancesResults, nil +} diff --git a/batch_balance/token_balances_test.go b/batch_balance/token_balances_test.go new file mode 100644 index 0000000..d499874 --- /dev/null +++ b/batch_balance/token_balances_test.go @@ -0,0 +1,59 @@ +package balance + +import ( + "context" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/lmittmann/w3" +) + +func TestBatchBalance_TokensBalance(t *testing.T) { + type args struct { + owner common.Address + tokens []common.Address + } + tests := []struct { + name string + args args + want bool + wantErr bool + }{ + { + name: "A random members (min dust available) balances", + args: args{ + owner: w3.A("0x4e956b5De3c33566c596754B4fa0ABd9F2789578"), + tokens: []common.Address{ + w3.A("0xaB89822F31c2092861F713F6F34bd6877a8C1878"), + w3.A("0x982caeF20362ADEAC3f9a25E37E20E6787f27f85"), + w3.A("0x9ADd261033baA414c84FF84A4Fe396338C1ba13a"), + w3.A("0x7dF20b526318d37Cd7DA9518E51d4A51fec30c9A"), + }, + }, + want: true, + wantErr: false, + }, + } + + batchBalance, err := NewBatchBalance(conf.rpcProvider, w3.A(conf.batchContract)) + + if err != nil { + t.Fatalf("NewBatchBalance error = %v", err) + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + got, err := batchBalance.TokensBalance(context.Background(), tt.args.owner, tt.args.tokens) + if (err != nil) != tt.wantErr { + t.Errorf("BatchBalance.TokensBalance() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if got[2].Int64() > 0 { + t.Errorf("TokenBalance = %d, want %d", got[2].Int64(), 0) + } + + }) + } +} diff --git a/net/cic_net.go b/net/cic_net.go index c7da894..63f0de2 100644 --- a/net/cic_net.go +++ b/net/cic_net.go @@ -2,10 +2,11 @@ package net import ( "crypto/ecdsa" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/lmittmann/w3" - "math/big" ) const ( diff --git a/net/cic_net_test.go b/net/cic_net_test.go index 8a06f87..8d0f74c 100644 --- a/net/cic_net_test.go +++ b/net/cic_net_test.go @@ -1,9 +1,10 @@ package net import ( - "github.com/lmittmann/w3" "os" "testing" + + "github.com/lmittmann/w3" ) type tConfig struct { @@ -26,7 +27,7 @@ func TestCicNet_Connect(t *testing.T) { t.Run(name, func(t *testing.T) { if err := cicnet.Close(); (err != nil) != wantErr { - t.Errorf("EntryCount() error = %v, wantErr %v", err, wantErr) + t.Errorf("Error() error = %v, wantErr %v", err, wantErr) } }) }