forked from EscanBE/evermint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
contract.go
125 lines (104 loc) · 3.43 KB
/
contract.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
117
118
119
120
121
122
123
124
125
package testutil
import (
"fmt"
"math/big"
"github.com/gogo/protobuf/proto"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/servprotocolorg/serv/v12/app"
"github.com/servprotocolorg/serv/v12/testutil/tx"
evm "github.com/servprotocolorg/serv/v12/x/evm/types"
)
// DeployContract deploys a contract with the provided private key,
// compiled contract data and constructor arguments
func DeployContract(
ctx sdk.Context,
app *app.Serv,
priv cryptotypes.PrivKey,
queryClientEvm evm.QueryClient,
contract evm.CompiledContract,
constructorArgs ...interface{},
) (common.Address, error) {
chainID := app.EvmKeeper.ChainID()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
nonce := app.EvmKeeper.GetNonce(ctx, from)
ctorArgs, err := contract.ABI.Pack("", constructorArgs...)
if err != nil {
return common.Address{}, err
}
data := append(contract.Bin, ctorArgs...) //nolint:gocritic
gas, err := tx.GasLimit(ctx, from, data, queryClientEvm)
if err != nil {
return common.Address{}, err
}
msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{
ChainID: chainID,
Nonce: nonce,
GasLimit: gas,
GasFeeCap: app.FeeMarketKeeper.GetBaseFee(ctx),
GasTipCap: big.NewInt(1),
Input: data,
Accesses: ðtypes.AccessList{},
})
msgEthereumTx.From = from.String()
res, err := DeliverEthTx(app, priv, msgEthereumTx)
if err != nil {
return common.Address{}, err
}
if _, err := CheckEthTxResponse(res, app.AppCodec()); err != nil {
return common.Address{}, err
}
return crypto.CreateAddress(from, nonce), nil
}
// DeployContractWithFactory deploys a contract using a contract factory
// with the provided factoryAddress
func DeployContractWithFactory(
ctx sdk.Context,
app *app.Serv,
priv cryptotypes.PrivKey,
factoryAddress common.Address,
) (common.Address, abci.ResponseDeliverTx, error) {
chainID := app.EvmKeeper.ChainID()
from := common.BytesToAddress(priv.PubKey().Address().Bytes())
factoryNonce := app.EvmKeeper.GetNonce(ctx, factoryAddress)
nonce := app.EvmKeeper.GetNonce(ctx, from)
msgEthereumTx := evm.NewTx(&evm.EvmTxArgs{
ChainID: chainID,
Nonce: nonce,
To: &factoryAddress,
GasLimit: uint64(100000),
GasPrice: big.NewInt(1000000000),
})
msgEthereumTx.From = from.String()
res, err := DeliverEthTx(app, priv, msgEthereumTx)
if err != nil {
return common.Address{}, abci.ResponseDeliverTx{}, err
}
if _, err := CheckEthTxResponse(res, app.AppCodec()); err != nil {
return common.Address{}, abci.ResponseDeliverTx{}, err
}
return crypto.CreateAddress(factoryAddress, factoryNonce), res, err
}
// CheckEthTxResponse checks that the transaction was executed successfully
func CheckEthTxResponse(r abci.ResponseDeliverTx, cdc codec.Codec) (*evm.MsgEthereumTxResponse, error) {
if !r.IsOK() {
return nil, fmt.Errorf("tx failed. Code: %d, Logs: %s", r.Code, r.Log)
}
var txData sdk.TxMsgData
if err := cdc.Unmarshal(r.Data, &txData); err != nil {
return nil, err
}
var res evm.MsgEthereumTxResponse
if err := proto.Unmarshal(txData.MsgResponses[0].Value, &res); err != nil {
return nil, err
}
if res.Failed() {
return nil, fmt.Errorf("tx failed. VmError: %s", res.VmError)
}
return &res, nil
}