Skip to content

Commit e5035d7

Browse files
fedekunze0xstepit
andauthored
feat(werc20): precompile setup (evmos#1977)
* feat(werc20): precompile setup * fixes * comments * Apply suggestions from code review Co-authored-by: stepit <48993133+0xstepit@users.noreply.github.com> --------- Co-authored-by: stepit <48993133+0xstepit@users.noreply.github.com>
1 parent d519cec commit e5035d7

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

precompiles/common/types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import (
1414
evmosutils "github.com/evmos/evmos/v15/utils"
1515
)
1616

17+
const (
18+
// FallbackMethod is the name of the fallback method.
19+
FallbackMethod = "fallback"
20+
// ReceiveMethod is the name of the receive method.
21+
ReceiveMethod = "receive"
22+
)
23+
1724
var (
1825
// TrueValue is the byte array representing a true value in solidity.
1926
TrueValue = []byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1}

precompiles/werc20/tx.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright Tharsis Labs Ltd.(Evmos)
2+
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE)
3+
4+
package werc20
5+
6+
const (
7+
// DepositMethod defines the ABI method name for the IWERC20 deposit
8+
// transaction.
9+
DepositMethod = "deposit"
10+
// WithdrawMethod defines the ABI method name for the IWERC20 withdraw
11+
// transaction.
12+
WithdrawMethod = "withdraw"
13+
)

precompiles/werc20/werc20.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright Tharsis Labs Ltd.(Evmos)
2+
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE)
3+
4+
package werc20
5+
6+
import (
7+
"embed"
8+
9+
"github.com/ethereum/go-ethereum/common"
10+
"github.com/ethereum/go-ethereum/core/vm"
11+
12+
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
13+
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
14+
cmn "github.com/evmos/evmos/v15/precompiles/common"
15+
erc20 "github.com/evmos/evmos/v15/precompiles/erc20"
16+
erc20types "github.com/evmos/evmos/v15/x/erc20/types"
17+
transferkeeper "github.com/evmos/evmos/v15/x/ibc/transfer/keeper"
18+
)
19+
20+
// abiPath defines the path to the WERC-20 precompile ABI JSON file.
21+
const abiPath = "./abi.json"
22+
23+
// Embed abi json file to the executable binary. Needed when importing as dependency.
24+
//
25+
//go:embed abi.json
26+
var f embed.FS
27+
28+
var _ vm.PrecompiledContract = &Precompile{}
29+
30+
// Precompile defines the precompiled contract for WERC20.
31+
type Precompile struct {
32+
*erc20.Precompile
33+
}
34+
35+
// NewPrecompile creates a new WERC20 Precompile instance as a
36+
// PrecompiledContract interface.
37+
func NewPrecompile(
38+
tokenPair erc20types.TokenPair,
39+
bankKeeper bankkeeper.Keeper,
40+
authzKeeper authzkeeper.Keeper,
41+
transferKeeper transferkeeper.Keeper,
42+
) (*Precompile, error) {
43+
newABI, err := cmn.LoadABI(f, abiPath)
44+
if err != nil {
45+
return nil, err
46+
}
47+
48+
erc20Precompile, err := erc20.NewPrecompile(tokenPair, bankKeeper, authzKeeper, transferKeeper)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
// use the IWERC20 ABI
54+
erc20Precompile.Precompile.ABI = newABI
55+
56+
return &Precompile{
57+
Precompile: erc20Precompile,
58+
}, nil
59+
}
60+
61+
// Address defines the address of the ERC20 precompile contract.
62+
func (p Precompile) Address() common.Address {
63+
return p.Precompile.Address()
64+
}
65+
66+
// RequiredGas calculates the contract gas use.
67+
func (p Precompile) RequiredGas(input []byte) uint64 {
68+
methodID := input[:4]
69+
method, err := p.MethodById(methodID)
70+
if err != nil {
71+
return 0
72+
}
73+
74+
// TODO: these values were obtained from Remix using the WEVMOS9.sol.
75+
// We should execute the transactions from Evmos testnet
76+
// to ensure parity in the values.
77+
switch method.Name {
78+
case cmn.FallbackMethod, cmn.ReceiveMethod, DepositMethod:
79+
return 28_799
80+
case WithdrawMethod:
81+
return 3_000_000
82+
}
83+
84+
return p.Precompile.RequiredGas(input)
85+
}
86+
87+
// Run executes the precompiled contract WERC20 methods defined in the ABI.
88+
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) {
89+
ctx, stateDB, method, initialGas, args, err := p.Precompile.RunSetup(evm, contract, readOnly, p.IsTransaction)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
// This handles any out of gas errors that may occur during the execution of a precompile tx or query.
95+
// It avoids panics and returns the out of gas error so the EVM can continue gracefully.
96+
defer cmn.HandleGasError(ctx, contract, initialGas, &err)()
97+
98+
switch method.Name {
99+
// WERC20 transactions
100+
case cmn.FallbackMethod, cmn.ReceiveMethod, DepositMethod:
101+
// bz, err = p.Deposit(ctx, contract, stateDB, method, args)
102+
case WithdrawMethod:
103+
// bz, err = p.Withdraw(ctx, contract, stateDB, method, args)
104+
105+
default:
106+
// ERC20 transactions and queries
107+
bz, err = p.Precompile.HandleMethod(ctx, contract, stateDB, method, args)
108+
}
109+
110+
if err != nil {
111+
return nil, err
112+
}
113+
114+
cost := ctx.GasMeter().GasConsumed() - initialGas
115+
116+
if !contract.UseGas(cost) {
117+
return nil, vm.ErrOutOfGas
118+
}
119+
120+
return bz, nil
121+
}
122+
123+
// IsTransaction checks if the given methodID corresponds to a transaction or query.
124+
func (p Precompile) IsTransaction(methodID string) bool {
125+
switch methodID {
126+
case cmn.FallbackMethod,
127+
cmn.ReceiveMethod,
128+
DepositMethod,
129+
WithdrawMethod:
130+
return true
131+
default:
132+
return p.Precompile.IsTransaction(methodID)
133+
}
134+
}

0 commit comments

Comments
 (0)