call.go 3.02 KB
Newer Older
1 2 3 4 5 6
package batching

import (
	"fmt"
	"math/big"

7
	"github.com/ethereum-optimism/optimism/op-service/txmgr"
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/common/hexutil"
)

type BoundContract struct {
	abi  *abi.ABI
	addr common.Address
}

func NewBoundContract(abi *abi.ABI, addr common.Address) *BoundContract {
	return &BoundContract{
		abi:  abi,
		addr: addr,
	}
}

func (b *BoundContract) Call(method string, args ...interface{}) *ContractCall {
	return NewContractCall(b.abi, b.addr, method, args...)
}

type ContractCall struct {
	Abi    *abi.ABI
	Addr   common.Address
	Method string
	Args   []interface{}
}

func NewContractCall(abi *abi.ABI, addr common.Address, method string, args ...interface{}) *ContractCall {
	return &ContractCall{
		Abi:    abi,
		Addr:   addr,
		Method: method,
		Args:   args,
	}
}

46 47 48 49
func (c *ContractCall) Pack() ([]byte, error) {
	return c.Abi.Pack(c.Method, c.Args...)
}

50
func (c *ContractCall) ToCallArgs() (interface{}, error) {
51
	data, err := c.Pack()
52 53 54 55 56 57 58 59 60 61
	if err != nil {
		return nil, fmt.Errorf("failed to pack arguments: %w", err)
	}
	msg := ethereum.CallMsg{
		To:   &c.Addr,
		Data: data,
	}
	return toCallArg(msg), nil
}

62
func (c *ContractCall) Unpack(hex hexutil.Bytes) (*CallResult, error) {
63 64 65 66
	out, err := c.Abi.Unpack(c.Method, hex)
	if err != nil {
		return nil, fmt.Errorf("failed to unpack data: %w", err)
	}
67
	return &CallResult{out: out}, nil
68 69
}

70 71 72 73 74 75
func toCallArg(msg ethereum.CallMsg) interface{} {
	arg := map[string]interface{}{
		"from": msg.From,
		"to":   msg.To,
	}
	if len(msg.Data) > 0 {
76
		arg["input"] = hexutil.Bytes(msg.Data)
77 78 79 80 81 82 83 84 85 86 87 88 89
	}
	if msg.Value != nil {
		arg["value"] = (*hexutil.Big)(msg.Value)
	}
	if msg.Gas != 0 {
		arg["gas"] = hexutil.Uint64(msg.Gas)
	}
	if msg.GasPrice != nil {
		arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
	}
	return arg
}

90 91 92 93 94 95 96 97 98 99 100
func (c *ContractCall) ToTxCandidate() (txmgr.TxCandidate, error) {
	data, err := c.Pack()
	if err != nil {
		return txmgr.TxCandidate{}, fmt.Errorf("failed to pack arguments: %w", err)
	}
	return txmgr.TxCandidate{
		TxData: data,
		To:     &c.Addr,
	}, nil
}

101 102 103 104 105 106 107 108 109 110 111 112
type CallResult struct {
	out []interface{}
}

func (c *CallResult) GetUint8(i int) uint8 {
	return *abi.ConvertType(c.out[i], new(uint8)).(*uint8)
}

func (c *CallResult) GetUint32(i int) uint32 {
	return *abi.ConvertType(c.out[i], new(uint32)).(*uint32)
}

Adrian Sutton's avatar
Adrian Sutton committed
113 114 115 116
func (c *CallResult) GetUint64(i int) uint64 {
	return *abi.ConvertType(c.out[i], new(uint64)).(*uint64)
}

117 118 119 120 121 122 123 124
func (c *CallResult) GetBool(i int) bool {
	return *abi.ConvertType(c.out[i], new(bool)).(*bool)
}

func (c *CallResult) GetHash(i int) common.Hash {
	return *abi.ConvertType(c.out[i], new([32]byte)).(*[32]byte)
}

125 126 127 128
func (c *CallResult) GetAddress(i int) common.Address {
	return *abi.ConvertType(c.out[i], new([20]byte)).(*[20]byte)
}

129 130 131
func (c *CallResult) GetBigInt(i int) *big.Int {
	return *abi.ConvertType(c.out[i], new(*big.Int)).(**big.Int)
}
132 133 134 135

func (c *CallResult) GetStruct(i int, target interface{}) {
	abi.ConvertType(c.out[i], target)
}