func CallBalanceOfMulticall(ctx context.Context, cl *ethclient.Client, Tokens *[]string, Account string, BlockNo *big.Int) ([]*big.Int, error) {
// Get RPC
var clientValue = reflect.ValueOf(cl).Elem()
fieldStruct := clientValue.FieldByName("c")
clientPointer := reflect.NewAt(fieldStruct.Type(), unsafe.Pointer(fieldStruct.UnsafeAddr())).Elem()
rpcClient, _ := clientPointer.Interface().(*rpc.Client)
_Balances := make([]*big.Int, len(*Tokens))
data := "0x610020565b600060405190508061001557606090505b818101604052919050565b6000805a6101ab604051600482823980518060e01c905061004081610004565b95508086019450808387395050506060600484019350835160e01c600485019450845160f81c6001860195506100766060610004565b43815260014303406020820152604081016000885b8881101561018b57805160f81c8060201b831792505060008260201c141561014157600181019050805160601c601482019150815160e01c6004830192508281840193505a60008084846000888ff160018a14156100ff575a82036100f06004610004565b8160e01b815260048e019d5050505b6101096001610004565b8160f81b81526101196004610004565b3d60e01b81526101283d610004565b3d6000823e60058f019e503d8f019e5050505050505050505b60018260201c141561017757600181019050805160601c601482019150803161016a6020610004565b81815260208a0199505050505b63ffffffff8216915060018201915061008b565b508082526101996004610004565b5a880360e01b81526004870196508684f3"
data_input_len := 9
var _calls string = ""
// Prep Data
_ContractInputData := "70a08231" + common.HexToHash(Account).String()[2:] // CallData
calldata_size := addZerosPadding(IntToHex(len(_ContractInputData)/2), 8-len(IntToHex(len(_ContractInputData)/2))) // 8 char calldata size
for _, Token := range *Tokens {
_Contract_Addr := addZerosPadding(common.HexToAddress(Token).String()[2:], 40-len(common.HexToAddress(Token).String()[2:]))
_SubStr := "00" + _Contract_Addr + calldata_size + _ContractInputData
//log.Println("Token: ", Token, " _SubStr: ", _SubStr)
data_input_len += (len(_SubStr) / 2)
_calls += _SubStr
}
data_input_len_hex := addZerosPadding(IntToHex(data_input_len), 8-len(IntToHex(data_input_len)))
data += data_input_len_hex + "0000ffff" + "01" + _calls
//log.Info("Data: ", data)
//log.Infof("data_input_len: %d data_input_len_hex: %s _str: %s", data_input_len, data_input_len_hex, _calls)
EthCallObj := EthCallObj{
From: Account,
Gas: "0xffffff",
GasPrice: "",
Value: "",
Data: data,
}
var EthCallResult string
err := rpcClient.CallContext(context.Background(), &EthCallResult, "eth_call", EthCallObj, "0x"+BigIntToHex(BlockNo), nil)
if err != nil {
log.Error("[CallBalanceOfMulticall] Unable to perform Multicall, err: ", err.Error())
return _Balances, err
}
// Now parse the result
//log.Println("EthCallResult: ", EthCallResult)
if len(EthCallResult) > 0 {
j := 0
i := 202
// Results are of the following structure
// 2 char Successfu (01 or 00)
// 00000020 --> 8 byte for len of return data, convert to int then * by 2 for char len
// 8 char Gas (i.e. 00010116)
// i.e. 010000002000000000000000000000000000000000000000000000000000000000000000000000320a
for i < len(EthCallResult) {
_len_ret, _ := strconv.ParseInt(EthCallResult[i+2:i+10], 16, 64)
_return_size := int(_len_ret * 2)
if EthCallResult[i:i+2] == "01" {
if _return_size != 0 {
_balance, s := big.NewInt(0).SetString(EthCallResult[i+10:i+10+_return_size], 16)
if s {
_Balances[j] = _balance
} else {
_Balances[j] = big.NewInt(0)
}
} else {
_Balances[j] = big.NewInt(0)
}
} else {
_Balances[j] = big.NewInt(0)
}
i += 10 + _return_size + 8
j += 1
}
} else {
log.Error("[CallBalanceOfMulticall] Empty Output")
return nil, nil
}
return _Balances, nil
}