forked from thirdweb-dev/go-sdk
/
contract_encoder.go
116 lines (102 loc) · 3.29 KB
/
contract_encoder.go
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package thirdweb
import (
"context"
"fmt"
"reflect"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)
// This interface is currently supported by all contract encoder classes and provides a generic
// method to encode write function calls.
type ContractEncoder struct {
abi *abi.ABI
contract *bind.BoundContract
helper *contractHelper
}
func newContractEncoder(contractAbi string, helper *contractHelper) (*ContractEncoder, error) {
parsedAbi, err := abi.JSON(strings.NewReader(contractAbi))
if err != nil {
return nil, err
}
contract := bind.NewBoundContract(helper.getAddress(), parsedAbi, helper.GetProvider(), helper.GetProvider(), helper.GetProvider())
return &ContractEncoder{
abi: &parsedAbi,
contract: contract,
helper: helper,
}, nil
}
// Get the unsigned transaction data for any contract call on a contract.
//
// signerAddress: the address expected to sign this transaction
//
// method: the name of the contract function to encode transaction data for
//
// args: the arguments to pass to the contract function.
//
// returns: the encoded transaction data for the transaction.
//
// Example
//
// toAddress := "0x..."
// amount := 1
//
// // Now you can get the transaction data for the contract call.
// tx, err := contract.Encoder.Encode(context.Background(), "transfer", toAddress, amount)
// fmt.Println(tx.Data()) // Now you can access all transaction data, like the following fields
// fmt.Println(tx.Nonce())
// fmt.Println(tx.Value())
func (encoder *ContractEncoder) Encode(ctx context.Context, signerAddress string, method string, args ...interface{}) (*types.Transaction, error) {
abiMethod, exist := encoder.abi.Methods[method]
if !exist {
return nil, fmt.Errorf("function '%s' not found in contract '%s'", method, encoder.helper.getAddress().String())
}
if len(abiMethod.Inputs) != len(args) {
return nil, fmt.Errorf(
"function '%s' requires %d arguments, but %d arguments were provided.\nExpected function signature '%s'",
method,
len(abiMethod.Inputs),
len(args),
abiMethod.Sig,
)
}
// Validate argument input types and convert to proper input types for contract
// So we can allow users to pass in string intead of address, int instead of big, etc.
typedArgs := []interface{}{}
for i, arg := range args {
input := abiMethod.Inputs[i]
inputType := fmt.Sprint(input.Type)
if inputType == "address" {
parsedArg, ok := arg.(string)
if !ok {
return nil, fmt.Errorf(
"argument %d (%v) should be of type 'string', but type '%v' was provided",
i,
input.Name,
reflect.TypeOf(arg),
)
}
arg = common.HexToAddress(parsedArg)
}
// } else if strings.Contains(inputType, "int") {
// parsedArg, ok := arg.(int)
// if !ok {
// return nil, fmt.Errorf(
// "argument %d (%v) should be of type 'int', but type '%v' was provided",
// i,
// input.Name,
// reflect.TypeOf(arg),
// )
// }
// arg = big.NewInt(int64(parsedArg))
// }
typedArgs = append(typedArgs, arg)
}
txOpts, err := encoder.helper.getUnsignedTxOptions(ctx, signerAddress)
if err != nil {
return nil, err
}
return encoder.contract.Transact(txOpts, method, typedArgs...)
}