Skip to content

Commit

Permalink
Add: FlexibleCall to support multicall v2
Browse files Browse the repository at this point in the history
  • Loading branch information
Himitsuko committed Jun 24, 2022
1 parent aaa8485 commit c5b6d18
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 235 deletions.
4 changes: 2 additions & 2 deletions call/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var DefaultChainConfigs = map[Chain]ChainConfig{
Url: "https://bsc-dataseed1.ninicoin.io",
},
Ethereum: {
MultiCallAddress: "0xeefba1e63905ef1d7acba5a8513c70307c1ce441",
MultiCallAddress: "0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696",
Url: "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
},
Fantom: {
Expand All @@ -49,7 +49,7 @@ var DefaultChainConfigs = map[Chain]ChainConfig{
Url: "https://moonbeam.public.blastapi.io",
},
Moonriver: {
MultiCallAddress: "0xaef00a0cf402d9dedd54092d9ca179be6f9e5ce3",
MultiCallAddress: "0xEae947bF407A4a4f1c5a6A73312734A2863e3855",
Url: "https://moonriver.public.blastapi.io",
},
Celo: {
Expand Down
88 changes: 49 additions & 39 deletions call/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

type Argument struct {
Name string `json:"name"`
Key string `json:"key"`
Type string `json:"type"`
InternalType string `json:"internalType"`
}
Expand Down Expand Up @@ -40,7 +40,7 @@ type Contract struct {
rawMethods map[string]string
methods []Method
calls []core.Call
multiCaller *core.Caller
multiCaller *core.MultiCaller
}

func NewContractBuilder() ContractBuilder {
Expand All @@ -53,7 +53,7 @@ func NewContractBuilder() ContractBuilder {
return contract.WithChainConfig(DefaultChainConfigs[Ethereum])
}

func (c *Contract) WithChainConfig(config ChainConfig) *Contract {
func (ct *Contract) WithChainConfig(config ChainConfig) *Contract {
if config.MultiCallAddress == "" || config.Url == "" {
panic("Invalid configuration. MultiCallAddress and Url must be set")
}
Expand All @@ -63,75 +63,85 @@ func (c *Contract) WithChainConfig(config ChainConfig) *Contract {
panic(err)
}

return c.WithClient(client).AtAddress(config.MultiCallAddress).Build()
return ct.WithClient(client).AtAddress(config.MultiCallAddress).Build()
}

func (a *Contract) WithClient(ethClient *ethclient.Client) ContractBuilder {
a.ethClient = ethClient
return a
func (ct *Contract) WithClient(ethClient *ethclient.Client) ContractBuilder {
ct.ethClient = ethClient
return ct
}

func (a *Contract) Build() *Contract {
return a
func (ct *Contract) Build() *Contract {
return ct
}

func (a *Contract) AtAddress(address string) ContractBuilder {
caller, err := core.NewCaller(a.ethClient, common.HexToAddress(address))
func (ct *Contract) AtAddress(address string) ContractBuilder {
caller, err := core.NewMultiCaller(ct.ethClient, common.HexToAddress(address))
if err != nil {
panic(err)
}
a.multiCaller = caller
return a
ct.multiCaller = caller
return ct
}

func (a *Contract) AddCall(callName string, contractAddress string, method string, args ...interface{}) *Contract {
callData, err := a.contractAbi.Pack(method, args...)
func (ct *Contract) AddCall(callName string, contractAddress string, method string, args ...interface{}) *Contract {
callData, err := ct.contractAbi.Pack(method, args...)
if err != nil {
panic(err)
}
a.calls = append(a.calls, core.Call{
ct.calls = append(ct.calls, core.Call{
Method: method,
Target: common.HexToAddress(contractAddress),
Name: callName,
Key: callName,
CallData: callData,
})
return a
return ct
}

func (a *Contract) AddMethod(signature string) *Contract {
existCall, ok := a.rawMethods[strings.ToLower(signature)]
func (ct *Contract) AddMethod(signature string) *Contract {
existCall, ok := ct.rawMethods[strings.ToLower(signature)]
if ok {
panic("Caller named " + existCall + " is exist on ABI")
panic("MultiCaller named " + existCall + " is exist on ABI")
}
a.rawMethods[strings.ToLower(signature)] = signature
a.methods = append(a.methods, parseNewMethod(signature))
newAbi, err := repackAbi(a.methods)
ct.rawMethods[strings.ToLower(signature)] = signature
ct.methods = append(ct.methods, parseNewMethod(signature))
newAbi, err := repackAbi(ct.methods)
if err != nil {
panic(err)
}
a.contractAbi = newAbi
ct.contractAbi = newAbi
if err != nil {
panic(err)
}
return a
return ct
}

func (a *Contract) Abi() abi.ABI {
return a.contractAbi
func (ct *Contract) Abi() abi.ABI {
return ct.contractAbi
}

func (a *Contract) Call(blockNumber *big.Int) (*big.Int, map[string][]interface{}, error) {
func (ct *Contract) Call(blockNumber *big.Int) (*big.Int, map[string][]interface{}, error) {
res := make(map[string][]interface{})
blockNumber, results, err := a.multiCaller.Execute(a.calls, blockNumber)
for _, call := range a.calls {
res[call.Name], _ = a.contractAbi.Unpack(call.Method, results[call.Name].ReturnData)
blockNumber, results, err := ct.multiCaller.StrictlyExecute(ct.calls, blockNumber)
for _, call := range ct.calls {
res[call.Key], _ = ct.contractAbi.Unpack(call.Method, results[call.Key].ReturnData)
}
a.ClearCall()
ct.ClearCall()
return blockNumber, res, err
}

func (a *Contract) ClearCall() {
a.calls = []core.Call{}
func (ct *Contract) FlexibleCall(requireSuccess bool) (map[string][]interface{}, error) {
res := make(map[string][]interface{})
results, err := ct.multiCaller.Execute(ct.calls, requireSuccess)
for _, call := range ct.calls {
res[call.Key], _ = ct.contractAbi.Unpack(call.Method, results[call.Key].ReturnData)
}
ct.ClearCall()
return res, err
}

func (ct *Contract) ClearCall() {
ct.calls = []core.Call{}
}

func parseNewMethod(signature string) Method {
Expand Down Expand Up @@ -159,7 +169,7 @@ func parseNewMethod(signature string) Method {
for _, inParam := range params {
if inParam != "" {
newMethod.Inputs = append(newMethod.Inputs, Argument{
Name: "",
Key: "",
Type: strings.TrimSpace(inParam),
InternalType: strings.TrimSpace(inParam),
})
Expand All @@ -172,7 +182,7 @@ func parseNewMethod(signature string) Method {

for _, outParam := range outputs {
newMethod.Outputs = append(newMethod.Outputs, Argument{
Name: "",
Key: "",
Type: strings.TrimSpace(outParam),
InternalType: strings.TrimSpace(outParam),
})
Expand All @@ -186,7 +196,7 @@ func parseNewMethod(signature string) Method {
for _, inParam := range params {
if inParam != "" {
newMethod.Inputs = append(newMethod.Inputs, Argument{
Name: "",
Key: "",
Type: strings.TrimSpace(inParam),
InternalType: strings.TrimSpace(inParam),
})
Expand All @@ -196,7 +206,7 @@ func parseNewMethod(signature string) Method {

returnType := strings.TrimSpace(singleReturnPaths[1])
newMethod.Outputs = append(newMethod.Outputs, Argument{
Name: "",
Key: "",
Type: returnType,
InternalType: returnType,
})
Expand Down
18 changes: 18 additions & 0 deletions call/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ var TestAddresses = map[Chain]string{
Moonriver: "0xE3F5a90F9cb311505cd691a46596599aA1A0AD7D",
}

var TestAddressesV2 = map[Chain]string{
Ethereum: "0xB8c77482e45F1F44dE1745F52C74426C631bDD52",
}

func TestContractBuilder_Default(t *testing.T) {
caller := NewContractBuilder().AddMethod("function totalSupply()(uint256)")
_, result, err := caller.
Expand Down Expand Up @@ -58,3 +62,17 @@ func TestContractBuilder_Call(t *testing.T) {
}
}
}

func TestContractBuilder_FlexibleCall(t *testing.T) {
for chain, address := range TestAddressesV2 {
caller := NewContractBuilder().
WithChainConfig(DefaultChainConfigs[chain]).
AddMethod("totalSupply()(uint256)")
result, err := caller.AddCall("ts", address, "totalSupply").FlexibleCall(false)
if err != nil {
assert.Failf(t, "Error calling %s contract", string(chain))
} else {
assert.Equal(t, result["ts"][0].(*big.Int).Cmp(big.NewInt(0)), 1)
}
}
}
Loading

0 comments on commit c5b6d18

Please sign in to comment.