Skip to content

Commit

Permalink
[wip] modify ContractQuery func, breaking change
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubhaankar-Sharma committed Jul 31, 2023
1 parent af08a69 commit ee59622
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 21 deletions.
10 changes: 10 additions & 0 deletions ethcoder/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ func AbiDecodeExprAndStringify(expr string, input []byte) ([]string, error) {
return AbiMarshalStringValues(argTypes, input)
}

func AbiDecodeExprToInterfaces(expr string, input []byte) ([]interface{}, error) {
argsList := parseArgumentExpr(expr)
argTypes := []string{}
for _, v := range argsList {
argTypes = append(argTypes, v.Type)
}

return AbiDecoderWithReturnedValues(argTypes, input)
}

func AbiMarshalStringValues(argTypes []string, input []byte) ([]string, error) {
values, err := AbiDecoderWithReturnedValues(argTypes, input)
if err != nil {
Expand Down
21 changes: 16 additions & 5 deletions ethrpc/ens.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,36 @@ func ResolveEnsAddress(ctx context.Context, ens string, provider *Provider) (com
return common.Address{}, false, fmt.Errorf("ethrpc: failed to generate namehash: %w", err)
}

resolverAddress, err := provider.contractQuery(ctx, ENSContractAddress, "resolver(bytes32)", "address", []interface{}{namehash})
res, err := provider.contractQuery(ctx, ENSContractAddress, "resolver(bytes32)", "address", []interface{}{namehash})
if err != nil {
return common.Address{}, false, fmt.Errorf("ethrpc: failed to query resolver address: %w", err)
}

if len(resolverAddress) < 1 || (resolverAddress[0] == common.Address{}.Hex()) {
if len(res) < 1 {
return common.Address{}, false, nil
}

contractAddress, err := provider.contractQuery(ctx, resolverAddress[0], "addr(bytes32)", "address", []interface{}{namehash})
resolverAddress, ok := res[0].(common.Address)
if !ok || resolverAddress.Hex() == (common.Address{}).Hex() {
return common.Address{}, false, nil
}

res, err = provider.contractQuery(ctx, resolverAddress.Hex(), "addr(bytes32)", "address", []interface{}{namehash})
if err != nil {
return common.Address{}, false, fmt.Errorf("ethrpc: failed to query resolver address: %w", err)
}

if len(contractAddress) < 1 {
if len(res) < 1 {
return common.Address{}, false, nil
}

contractAddress, ok := res[0].(common.Address)

if !ok || contractAddress.Hex() == (common.Address{}).Hex() {
return common.Address{}, false, nil
}

return common.HexToAddress(contractAddress[0]), true, nil
return contractAddress, true, nil
}

// NameHash generates a hash from a name that can be used to
Expand Down
6 changes: 3 additions & 3 deletions ethrpc/ethrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func (p *Provider) SubscribeFilterLogs(ctx context.Context, query ethereum.Filte

// ie, ContractQuery(context.Background(), "0xabcdef..", "balanceOf(uint256)", "uint256", []string{"1"})
// TODO: add common methods in helpers util, and also use generics to convert the return for us
func (p *Provider) ContractQuery(ctx context.Context, contractAddress string, inputAbiExpr, outputAbiExpr string, args interface{}) ([]string, error) {
func (p *Provider) ContractQuery(ctx context.Context, contractAddress string, inputAbiExpr, outputAbiExpr string, args interface{}) ([]interface{}, error) {
if !common.IsHexAddress(contractAddress) {
// Check for ens
ensAddress, ok, err := ResolveEnsAddress(ctx, contractAddress, p)
Expand All @@ -405,7 +405,7 @@ func (p *Provider) ContractQuery(ctx context.Context, contractAddress string, in
return p.contractQuery(ctx, contractAddress, inputAbiExpr, outputAbiExpr, args)
}

func (p *Provider) contractQuery(ctx context.Context, contractAddress string, inputAbiExpr, outputAbiExpr string, args interface{}) ([]string, error) {
func (p *Provider) contractQuery(ctx context.Context, contractAddress string, inputAbiExpr, outputAbiExpr string, args interface{}) ([]interface{}, error) {
contract := common.HexToAddress(contractAddress)

var (
Expand Down Expand Up @@ -441,7 +441,7 @@ func (p *Provider) contractQuery(ctx context.Context, contractAddress string, in
if err != nil {
return nil, fmt.Errorf("contract call failed: %w", err)
}
resp, err := ethcoder.AbiDecodeExprAndStringify(outputAbiExpr, output)
resp, err := ethcoder.AbiDecodeExprToInterfaces(outputAbiExpr, output)
if err != nil {
return nil, fmt.Errorf("abi decode of response failed: %w", err)
}
Expand Down
17 changes: 10 additions & 7 deletions ethrpc/ethrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ func TestERC20MintAndTransfer(t *testing.T) {
require.NotNil(t, receipt)

// Query erc20Mock balance to confirm
ret, err := provider.ContractQuery(ctx, erc20Mock.Address.Hex(), "balanceOf(address)", "uint256", []string{wallet.Address().Hex()})
res, err := provider.ContractQuery(ctx, erc20Mock.Address.Hex(), "balanceOf(address)", "uint256", []string{wallet.Address().Hex()})
require.NoError(t, err)
require.Equal(t, 1, len(ret))
require.Equal(t, "2000", ret[0])
require.Equal(t, 1, len(res))
ret, ok := res[0].(*big.Int)
require.True(t, ok)
require.Equal(t, "2000", ret.String())

// Transfer token to another wallet
wallet2, _ := testchain.DummyWallet(600)
Expand All @@ -74,11 +76,12 @@ func TestERC20MintAndTransfer(t *testing.T) {
txn, receipt = ethtest.SendTransactionAndWaitForReceipt(t, wallet, erc20Mock.Address, calldata, nil)
require.NotNil(t, txn)
require.NotNil(t, receipt)

ret, err = provider.ContractQuery(ctx, erc20Mock.Address.Hex(), "balanceOf(address)", "uint256", []string{wallet2.Address().Hex()})
res, err = provider.ContractQuery(ctx, erc20Mock.Address.Hex(), "balanceOf(address)", "uint256", []string{wallet2.Address().Hex()})
require.NoError(t, err)
require.Equal(t, 1, len(ret))
require.Equal(t, "42", ret[0])
require.Equal(t, 1, len(res))
ret, ok = res[0].(*big.Int)
require.True(t, ok)
require.Equal(t, "42", ret.String())
}

func TestBlockByNumber(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion ethtest/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func ContractCall(provider *ethrpc.Provider, contractAddress common.Address, con
return output, nil
}

func ContractQuery(provider *ethrpc.Provider, contractAddress common.Address, inputExpr, outputExpr string, args []string) ([]string, error) {
func ContractQuery(provider *ethrpc.Provider, contractAddress common.Address, inputExpr, outputExpr string, args []string) ([]interface{}, error) {
return provider.ContractQuery(context.Background(), contractAddress.Hex(), inputExpr, outputExpr, args)
}

Expand Down
9 changes: 6 additions & 3 deletions ethtest/erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ func (c *ERC20Mock) Transfer(t *testing.T, owner *ethwallet.Wallet, to ethkit.Ad
func (c *ERC20Mock) GetBalance(t *testing.T, account ethkit.Address, expectedAmount int64) {
provider := c.testchain.Provider

ret, err := provider.ContractQuery(context.Background(), c.Contract.Address.Hex(), "balanceOf(address)", "uint256", []string{account.Hex()})
res, err := provider.ContractQuery(context.Background(), c.Contract.Address.Hex(), "balanceOf(address)", "uint256", []string{account.Hex()})
require.NoError(t, err)
require.Equal(t, 1, len(ret))
require.Equal(t, fmt.Sprintf("%d", expectedAmount), ret[0])
require.NotEmpty(t, res)
ret, ok := res[0].(*big.Int)
require.True(t, ok)
require.NotEqual(t, big.NewInt(0), ret)
require.Equal(t, fmt.Sprintf("%d", expectedAmount), ret.String())
}
7 changes: 5 additions & 2 deletions ethtest/testchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ func TestContractHelpers(t *testing.T) {
assert.Equal(t, types.ReceiptStatusSuccessful, receipt.Status)

// Query the value ensuring its been updated on-chain
ret, err := ethtest.ContractQuery(testchain.Provider, callmockContract.Address, "lastValA()", "uint256", nil)
res, err := ethtest.ContractQuery(testchain.Provider, callmockContract.Address, "lastValA()", "uint256", nil)
assert.NoError(t, err)
assert.Equal(t, []string{"143"}, ret)
assert.Equal(t, 1, len(res))
ret, ok := res[0].(*big.Int)
assert.True(t, ok)
assert.Equal(t, "143", ret.String())

// Query the value using different method, where we unpack the value
var result *big.Int
Expand Down

0 comments on commit ee59622

Please sign in to comment.