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..d7c47f1 --- /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_BALANCE"), +} + +func TestCicNet_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/smart-contracts/on-chain-balances-resolver/Balances.sol b/batch_balance/smart-contract/Balances.sol similarity index 100% rename from smart-contracts/on-chain-balances-resolver/Balances.sol rename to batch_balance/smart-contract/Balances.sol diff --git a/smart-contracts/on-chain-balances-resolver/artifacts/abi.json b/batch_balance/smart-contract/artifacts/abi.json similarity index 100% rename from smart-contracts/on-chain-balances-resolver/artifacts/abi.json rename to batch_balance/smart-contract/artifacts/abi.json diff --git a/smart-contracts/on-chain-balances-resolver/artifacts/bytecode.json b/batch_balance/smart-contract/artifacts/bytecode.json similarity index 100% rename from smart-contracts/on-chain-balances-resolver/artifacts/bytecode.json rename to batch_balance/smart-contract/artifacts/bytecode.json 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) } }) }