diff --git a/app/app.go b/app/app.go index 850be9215f..fc9fa4c434 100644 --- a/app/app.go +++ b/app/app.go @@ -670,6 +670,7 @@ func New( if enableCustomEVMPrecompiles { if err := precompiles.InitializePrecompiles( + false, &app.EvmKeeper, app.BankKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), diff --git a/precompiles/addr/addr.go b/precompiles/addr/addr.go index aff5b06c77..f787a47084 100644 --- a/precompiles/addr/addr.go +++ b/precompiles/addr/addr.go @@ -88,6 +88,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "addr" +} + func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/precompiles/bank/bank.go b/precompiles/bank/bank.go index c31b7e2f0f..da076d46b0 100644 --- a/precompiles/bank/bank.go +++ b/precompiles/bank/bank.go @@ -126,6 +126,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "bank" +} + func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/precompiles/common/precompiles.go b/precompiles/common/precompiles.go index 5a38be8d9a..8b6d8eeeda 100644 --- a/precompiles/common/precompiles.go +++ b/precompiles/common/precompiles.go @@ -55,6 +55,10 @@ func (p Precompile) Prepare(evm *vm.EVM, input []byte) (sdk.Context, *abi.Method return ctxer.Ctx(), method, args, nil } +func (p Precompile) GetABI() abi.ABI { + return p.ABI +} + func ValidateArgsLength(args []interface{}, length int) error { if len(args) != length { return fmt.Errorf("expected %d arguments but got %d", length, len(args)) diff --git a/precompiles/distribution/distribution.go b/precompiles/distribution/distribution.go index 33dfb35338..08ff3ee5b9 100644 --- a/precompiles/distribution/distribution.go +++ b/precompiles/distribution/distribution.go @@ -96,6 +96,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "distribution" +} + func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { if readOnly { return nil, errors.New("cannot call distr precompile from staticcall") diff --git a/precompiles/gov/gov.go b/precompiles/gov/gov.go index e80f6f4f4c..096165fcb3 100644 --- a/precompiles/gov/gov.go +++ b/precompiles/gov/gov.go @@ -99,6 +99,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "gov" +} + func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { if readOnly { return nil, errors.New("cannot call gov precompile from staticcall") diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go index 51f17b04bd..a103e45aa5 100644 --- a/precompiles/ibc/ibc.go +++ b/precompiles/ibc/ibc.go @@ -251,6 +251,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "ibc" +} + func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { addr := arg.(common.Address) if addr == (common.Address{}) { diff --git a/precompiles/json/json.go b/precompiles/json/json.go index 3712bc292b..0a0344f515 100644 --- a/precompiles/json/json.go +++ b/precompiles/json/json.go @@ -88,6 +88,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "json" +} + func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/precompiles/oracle/oracle.go b/precompiles/oracle/oracle.go index 06f1dd60ad..44c954a596 100644 --- a/precompiles/oracle/oracle.go +++ b/precompiles/oracle/oracle.go @@ -113,6 +113,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "oracle" +} + func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, value *big.Int, _ bool) (bz []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/precompiles/pointer/pointer.go b/precompiles/pointer/pointer.go index 8fb594b848..88b933c7fa 100644 --- a/precompiles/pointer/pointer.go +++ b/precompiles/pointer/pointer.go @@ -93,6 +93,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "pointer" +} + func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { if readOnly { return nil, 0, errors.New("cannot call pointer precompile from staticcall") diff --git a/precompiles/pointerview/pointerview.go b/precompiles/pointerview/pointerview.go index acbc975616..6019dd7dd2 100644 --- a/precompiles/pointerview/pointerview.go +++ b/precompiles/pointerview/pointerview.go @@ -78,6 +78,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "pointerview" +} + func (p Precompile) Run(evm *vm.EVM, _ common.Address, _ common.Address, input []byte, _ *big.Int, _ bool) (ret []byte, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/precompiles/setup.go b/precompiles/setup.go index a0908d4963..3cadd9792d 100644 --- a/precompiles/setup.go +++ b/precompiles/setup.go @@ -3,6 +3,7 @@ package precompiles import ( "sync" + "github.com/ethereum/go-ethereum/accounts/abi" ecommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/sei-protocol/sei-chain/precompiles/addr" @@ -22,7 +23,23 @@ import ( var SetupMtx = &sync.Mutex{} var Initialized = false +type PrecompileInfo struct { + ABI abi.ABI + Address ecommon.Address +} + +// PrecompileNamesToInfo is Populated by InitializePrecompiles +var PrecompileNamesToInfo = map[string]PrecompileInfo{} + +type IPrecompile interface { + vm.PrecompiledContract + GetABI() abi.ABI + GetName() string + Address() ecommon.Address +} + func InitializePrecompiles( + dryRun bool, evmKeeper common.EVMKeeper, bankKeeper common.BankKeeper, wasmdKeeper common.WasmdKeeper, @@ -42,73 +59,98 @@ func InitializePrecompiles( if err != nil { return err } - addPrecompileToVM(bankp, bankp.Address()) wasmdp, err := wasmd.NewPrecompile(evmKeeper, wasmdKeeper, wasmdViewKeeper, bankKeeper) if err != nil { return err } - addPrecompileToVM(wasmdp, wasmdp.Address()) jsonp, err := json.NewPrecompile() if err != nil { return err } - addPrecompileToVM(jsonp, jsonp.Address()) addrp, err := addr.NewPrecompile(evmKeeper) if err != nil { return err } - addPrecompileToVM(addrp, addrp.Address()) stakingp, err := staking.NewPrecompile(stakingKeeper, evmKeeper, bankKeeper) if err != nil { return err } - addPrecompileToVM(stakingp, stakingp.Address()) govp, err := gov.NewPrecompile(govKeeper, evmKeeper, bankKeeper) if err != nil { return err } - addPrecompileToVM(govp, govp.Address()) distrp, err := distribution.NewPrecompile(distrKeeper, evmKeeper) if err != nil { return err } - addPrecompileToVM(distrp, distrp.Address()) oraclep, err := oracle.NewPrecompile(oracleKeeper, evmKeeper) if err != nil { return err } - addPrecompileToVM(oraclep, oraclep.Address()) ibcp, err := ibc.NewPrecompile(transferKeeper, evmKeeper) if err != nil { return err } - addPrecompileToVM(ibcp, ibcp.Address()) pointerp, err := pointer.NewPrecompile(evmKeeper, bankKeeper, wasmdViewKeeper) if err != nil { return err } - addPrecompileToVM(pointerp, pointerp.Address()) pointerviewp, err := pointerview.NewPrecompile(evmKeeper) if err != nil { return err } - addPrecompileToVM(pointerviewp, pointerviewp.Address()) - Initialized = true + PrecompileNamesToInfo[bankp.GetName()] = PrecompileInfo{ABI: bankp.GetABI(), Address: bankp.Address()} + PrecompileNamesToInfo[wasmdp.GetName()] = PrecompileInfo{ABI: wasmdp.GetABI(), Address: wasmdp.Address()} + PrecompileNamesToInfo[jsonp.GetName()] = PrecompileInfo{ABI: jsonp.GetABI(), Address: jsonp.Address()} + PrecompileNamesToInfo[addrp.GetName()] = PrecompileInfo{ABI: addrp.GetABI(), Address: addrp.Address()} + PrecompileNamesToInfo[stakingp.GetName()] = PrecompileInfo{ABI: stakingp.GetABI(), Address: stakingp.Address()} + PrecompileNamesToInfo[govp.GetName()] = PrecompileInfo{ABI: govp.GetABI(), Address: govp.Address()} + PrecompileNamesToInfo[distrp.GetName()] = PrecompileInfo{ABI: distrp.GetABI(), Address: distrp.Address()} + PrecompileNamesToInfo[oraclep.GetName()] = PrecompileInfo{ABI: oraclep.GetABI(), Address: oraclep.Address()} + PrecompileNamesToInfo[ibcp.GetName()] = PrecompileInfo{ABI: ibcp.GetABI(), Address: ibcp.Address()} + PrecompileNamesToInfo[pointerp.GetName()] = PrecompileInfo{ABI: pointerp.GetABI(), Address: pointerp.Address()} + PrecompileNamesToInfo[pointerviewp.GetName()] = PrecompileInfo{ABI: pointerviewp.GetABI(), Address: pointerviewp.Address()} + if !dryRun { + addPrecompileToVM(bankp) + addPrecompileToVM(wasmdp) + addPrecompileToVM(jsonp) + addPrecompileToVM(addrp) + addPrecompileToVM(stakingp) + addPrecompileToVM(govp) + addPrecompileToVM(distrp) + addPrecompileToVM(oraclep) + addPrecompileToVM(ibcp) + addPrecompileToVM(pointerp) + addPrecompileToVM(pointerviewp) + Initialized = true + } return nil } +func GetPrecompileInfo(name string) PrecompileInfo { + if !Initialized { + // Precompile Info does not require any keeper state + _ = InitializePrecompiles(true, nil, nil, nil, nil, nil, nil, nil, nil, nil) + } + i, ok := PrecompileNamesToInfo[name] + if !ok { + panic(name + "doesn't exist as a precompile") + } + return i +} + // This function modifies global variable in `vm` module. It should only be called once // per precompile during initialization -func addPrecompileToVM(p vm.PrecompiledContract, addr ecommon.Address) { - vm.PrecompiledContractsHomestead[addr] = p - vm.PrecompiledContractsByzantium[addr] = p - vm.PrecompiledContractsIstanbul[addr] = p - vm.PrecompiledContractsBerlin[addr] = p - vm.PrecompiledContractsCancun[addr] = p - vm.PrecompiledContractsBLS[addr] = p - vm.PrecompiledAddressesHomestead = append(vm.PrecompiledAddressesHomestead, addr) - vm.PrecompiledAddressesByzantium = append(vm.PrecompiledAddressesByzantium, addr) - vm.PrecompiledAddressesIstanbul = append(vm.PrecompiledAddressesIstanbul, addr) - vm.PrecompiledAddressesBerlin = append(vm.PrecompiledAddressesBerlin, addr) - vm.PrecompiledAddressesCancun = append(vm.PrecompiledAddressesCancun, addr) +func addPrecompileToVM(p IPrecompile) { + vm.PrecompiledContractsHomestead[p.Address()] = p + vm.PrecompiledContractsByzantium[p.Address()] = p + vm.PrecompiledContractsIstanbul[p.Address()] = p + vm.PrecompiledContractsBerlin[p.Address()] = p + vm.PrecompiledContractsCancun[p.Address()] = p + vm.PrecompiledContractsBLS[p.Address()] = p + vm.PrecompiledAddressesHomestead = append(vm.PrecompiledAddressesHomestead, p.Address()) + vm.PrecompiledAddressesByzantium = append(vm.PrecompiledAddressesByzantium, p.Address()) + vm.PrecompiledAddressesIstanbul = append(vm.PrecompiledAddressesIstanbul, p.Address()) + vm.PrecompiledAddressesBerlin = append(vm.PrecompiledAddressesBerlin, p.Address()) + vm.PrecompiledAddressesCancun = append(vm.PrecompiledAddressesCancun, p.Address()) } diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 1c96a56661..e828a02ff6 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -105,6 +105,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "staking" +} + func (p Precompile) Run(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, value *big.Int, readOnly bool) (bz []byte, err error) { if readOnly { return nil, errors.New("cannot call staking precompile from staticcall") diff --git a/precompiles/wasmd/wasmd.go b/precompiles/wasmd/wasmd.go index 06d9db2530..226ae9637e 100644 --- a/precompiles/wasmd/wasmd.go +++ b/precompiles/wasmd/wasmd.go @@ -125,6 +125,10 @@ func (p Precompile) Address() common.Address { return p.address } +func (p Precompile) GetName() string { + return "wasmd" +} + func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool) (ret []byte, remainingGas uint64, err error) { ctx, method, args, err := p.Prepare(evm, input) if err != nil { diff --git a/x/evm/client/cli/common.go b/x/evm/client/cli/common.go new file mode 100644 index 0000000000..5e56ed8272 --- /dev/null +++ b/x/evm/client/cli/common.go @@ -0,0 +1,107 @@ +package cli + +import ( + "errors" + "fmt" + "math" + "math/big" + "strconv" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" +) + +func getMethodPayload(newAbi abi.ABI, args []string) ([]byte, error) { + method := newAbi.Methods[args[0]] + abiArgs := []interface{}{} + for i, input := range method.Inputs { + idx := i + 1 + if idx >= len(args) { + return nil, errors.New("not enough arguments") + } + var arg interface{} + var err error + switch input.Type.T { + case abi.IntTy: + if input.Type.Size > 64 { + bi, success := new(big.Int).SetString(args[idx], 10) + if !success { + return nil, errors.New("invalid big.Int") + } else { + arg = bi + } + } else { + val, e := strconv.ParseInt(args[idx], 10, 64) + err = e + switch input.Type.Size { + case 8: + if val > math.MaxInt8 { + return nil, errors.New("int8 overflow") + } + arg = int8(val) + case 16: + if val > math.MaxInt16 { + return nil, errors.New("int16 overflow") + } + arg = int16(val) + case 32: + if val > math.MaxInt32 { + return nil, errors.New("int32 overflow") + } + arg = int32(val) + case 64: + arg = val + } + } + case abi.UintTy: + if input.Type.Size > 64 { + bi, success := new(big.Int).SetString(args[idx], 10) + if !success { + return nil, errors.New("invalid big.Int") + } else { + arg = bi + } + } else { + val, e := strconv.ParseUint(args[idx], 10, 64) + err = e + switch input.Type.Size { + case 8: + if val > math.MaxUint8 { + return nil, errors.New("uint8 overflow") + } + arg = uint8(val) + case 16: + if val > math.MaxUint16 { + return nil, errors.New("uint16 overflow") + } + arg = uint16(val) + case 32: + if val > math.MaxUint32 { + return nil, errors.New("uint32 overflow") + } + arg = uint32(val) + case 64: + arg = val + } + } + case abi.BoolTy: + if args[idx] != TrueStr && args[idx] != FalseStr { + return nil, fmt.Errorf("boolean argument has to be either \"%s\" or \"%s\"", TrueStr, FalseStr) + } else { + arg = args[idx] == TrueStr + } + case abi.StringTy: + arg = args[idx] + case abi.AddressTy: + arg = common.HexToAddress(args[idx]) + default: + return nil, errors.New("argument type not supported yet") + } + if err != nil { + return nil, err + } + abiArgs = append(abiArgs, arg) + } + + return newAbi.Pack(args[0], abiArgs...) +} diff --git a/x/evm/client/cli/query.go b/x/evm/client/cli/query.go index 084f4a725c..ff9f102107 100644 --- a/x/evm/client/cli/query.go +++ b/x/evm/client/cli/query.go @@ -8,7 +8,6 @@ import ( "fmt" "math/big" "os" - "strconv" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" @@ -172,80 +171,7 @@ func CmdQueryPayload() *cobra.Command { if err != nil { return err } - method := newAbi.Methods[args[1]] - abiArgs := []interface{}{} - for i, input := range method.Inputs { - idx := i + 2 - if idx >= len(args) { - return errors.New("not enough arguments") - } - var arg interface{} - var err error - switch input.Type.T { - case abi.IntTy: - if input.Type.Size > 64 { - bi, success := new(big.Int).SetString(args[idx], 10) - if !success { - err = errors.New("invalid big.Int") - } else { - arg = bi - } - } else { - val, e := strconv.ParseInt(args[idx], 10, 64) - err = e - switch input.Type.Size { - case 8: - arg = int8(val) - case 16: - arg = int16(val) - case 32: - arg = int32(val) - case 64: - arg = val - } - } - case abi.UintTy: - if input.Type.Size > 64 { - bi, success := new(big.Int).SetString(args[idx], 10) - if !success { - err = errors.New("invalid big.Int") - } else { - arg = bi - } - } else { - val, e := strconv.ParseUint(args[idx], 10, 64) - err = e - switch input.Type.Size { - case 8: - arg = uint8(val) - case 16: - arg = uint16(val) - case 32: - arg = uint32(val) - case 64: - arg = val - } - } - case abi.BoolTy: - if args[idx] != TrueStr && args[idx] != FalseStr { - err = fmt.Errorf("boolean argument has to be either \"%s\" or \"%s\"", TrueStr, FalseStr) - } else { - arg = args[idx] == TrueStr - } - case abi.StringTy: - arg = args[idx] - case abi.AddressTy: - arg = common.HexToAddress(args[idx]) - default: - return errors.New("argument type not supported yet") - } - if err != nil { - return err - } - abiArgs = append(abiArgs, arg) - } - - bz, err := newAbi.Pack(args[1], abiArgs...) + bz, err := getMethodPayload(newAbi, args[1:]) if err != nil { return err } diff --git a/x/evm/client/cli/tx.go b/x/evm/client/cli/tx.go index c7dc727a3c..5787e978de 100644 --- a/x/evm/client/cli/tx.go +++ b/x/evm/client/cli/tx.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "io" - "math" "math/big" "net/http" "os" @@ -27,13 +26,10 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/codec/legacy" "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/sei-protocol/sei-chain/evmrpc" - "github.com/sei-protocol/sei-chain/precompiles/staking" + "github.com/sei-protocol/sei-chain/precompiles" "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw20" - "github.com/sei-protocol/sei-chain/x/evm/artifacts/cw721" "github.com/sei-protocol/sei-chain/x/evm/artifacts/native" "github.com/sei-protocol/sei-chain/x/evm/artifacts/wsei" "github.com/sei-protocol/sei-chain/x/evm/types" @@ -61,13 +57,10 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdAssociateAddress()) cmd.AddCommand(CmdSend()) cmd.AddCommand(CmdDeployContract()) - cmd.AddCommand(CmdDeployErc20()) - cmd.AddCommand(CmdDeployErcCw20()) cmd.AddCommand(CmdCallContract()) - cmd.AddCommand(CmdDeployErcCw721()) cmd.AddCommand(CmdDeployWSEI()) cmd.AddCommand(CmdERC20Send()) - cmd.AddCommand(CmdDelegate()) + cmd.AddCommand(CmdCallPrecompile()) cmd.AddCommand(NativeSendTxCmd()) cmd.AddCommand(NewAddERCNativePointerProposalTxCmd()) cmd.AddCommand(NewAddERCCW20PointerProposalTxCmd()) @@ -296,259 +289,9 @@ func CmdDeployContract() *cobra.Command { return cmd } -func CmdDeployErc20() *cobra.Command { - cmd := &cobra.Command{ - Use: "deploy-erc20 [denom] [name] [symbol] [decimal] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", - Short: "Deploy ERC20 contract for a native Sei token", - Long: "", - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) (err error) { - err = sdk.ValidateDenom(args[0]) - if err != nil { - return err - } - denom := args[0] - name := args[1] - symbol := args[2] - decimal, err := strconv.ParseUint(args[3], 10, 64) - if err != nil { - return err - } - if decimal > math.MaxUint8 { - return fmt.Errorf("decimal cannot be larger than %d", math.MaxUint8) - } - - bytecode := native.GetBin() - constructorArguments := []interface{}{ - denom, name, symbol, uint8(decimal), - } - - packedArgs, err := native.GetParsedABI().Pack("", constructorArguments...) - if err != nil { - return err - } - contractData := append(bytecode, packedArgs...) - - key, err := getPrivateKey(cmd) - if err != nil { - return err - } - - rpc, err := cmd.Flags().GetString(FlagRPC) - if err != nil { - return err - } - var nonce uint64 - if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { - nonce = uint64(n) - } else { - nonce, err = getNonce(rpc, key.PublicKey) - if err != nil { - return err - } - } - - txData, err := getTxData(cmd) - if err != nil { - return err - } - txData.Nonce = nonce - txData.Value = utils.Big0 - txData.Data = contractData - - resp, err := sendTx(txData, rpc, key) - if err != nil { - return err - } - - senderAddr := crypto.PubkeyToAddress(key.PublicKey) - data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) - if err != nil { - return err - } - hash := crypto.Keccak256Hash(data) - contractAddress := hash.Bytes()[12:] - contractAddressHex := hex.EncodeToString(contractAddress) - - fmt.Println("Deployer:", senderAddr) - fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) - fmt.Println("Transaction hash:", resp.Hex()) - return nil - }, - } - - cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") - cmd.Flags().Uint64(FlagGas, 5000000, "Gas limit for the transaction") - cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") - cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") - flags.AddTxFlagsToCmd(cmd) - - return cmd -} - -func CmdDeployErcCw20() *cobra.Command { - cmd := &cobra.Command{ - Use: "deploy-erccw20 [cw20addr] [name] [symbol] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", - Short: "Deploy ERC20 contract for a CW20 token", - Long: "", - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) (err error) { - _, err = sdk.AccAddressFromBech32(args[0]) - if err != nil { - return err - } - - bytecode := cw20.GetBin() - constructorArguments := []interface{}{ - args[0], args[1], args[2], - } - - packedArgs, err := cw20.GetParsedABI().Pack("", constructorArguments...) - if err != nil { - return err - } - contractData := append(bytecode, packedArgs...) - - key, err := getPrivateKey(cmd) - if err != nil { - return err - } - - rpc, err := cmd.Flags().GetString(FlagRPC) - if err != nil { - return err - } - var nonce uint64 - if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { - nonce = uint64(n) - } else { - nonce, err = getNonce(rpc, key.PublicKey) - if err != nil { - return err - } - } - - txData, err := getTxData(cmd) - if err != nil { - return err - } - txData.Nonce = nonce - txData.Value = utils.Big0 - txData.Data = contractData - - resp, err := sendTx(txData, rpc, key) - if err != nil { - return err - } - - senderAddr := crypto.PubkeyToAddress(key.PublicKey) - data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) - if err != nil { - return err - } - hash := crypto.Keccak256Hash(data) - contractAddress := hash.Bytes()[12:] - contractAddressHex := hex.EncodeToString(contractAddress) - - fmt.Println("Deployer:", senderAddr) - fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) - fmt.Println("Transaction hash:", resp.Hex()) - return nil - }, - } - - cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") - cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") - cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") - cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") - flags.AddTxFlagsToCmd(cmd) - - return cmd -} - -func CmdDeployErcCw721() *cobra.Command { - cmd := &cobra.Command{ - Use: "deploy-erccw721 [cw721addr] [name] [symbol] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", - Short: "Deploy ERC721 contract for a CW20 token", - Long: "", - Args: cobra.ExactArgs(3), - RunE: func(cmd *cobra.Command, args []string) (err error) { - _, err = sdk.AccAddressFromBech32(args[0]) - if err != nil { - return err - } - - bytecode := cw721.GetBin() - constructorArguments := []interface{}{ - args[0], args[1], args[2], - } - - packedArgs, err := cw721.GetParsedABI().Pack("", constructorArguments...) - if err != nil { - return err - } - contractData := append(bytecode, packedArgs...) - - key, err := getPrivateKey(cmd) - if err != nil { - return err - } - - rpc, err := cmd.Flags().GetString(FlagRPC) - if err != nil { - return err - } - var nonce uint64 - if n, err := cmd.Flags().GetInt64(FlagNonce); err == nil && n >= 0 { - nonce = uint64(n) - } else { - nonce, err = getNonce(rpc, key.PublicKey) - if err != nil { - return err - } - } - - txData, err := getTxData(cmd) - if err != nil { - return err - } - txData.Nonce = nonce - txData.Value = utils.Big0 - txData.Data = contractData - - resp, err := sendTx(txData, rpc, key) - if err != nil { - return err - } - - senderAddr := crypto.PubkeyToAddress(key.PublicKey) - data, err := rlp.EncodeToBytes([]interface{}{senderAddr, nonce}) - if err != nil { - return err - } - hash := crypto.Keccak256Hash(data) - contractAddress := hash.Bytes()[12:] - contractAddressHex := hex.EncodeToString(contractAddress) - - fmt.Println("Deployer:", senderAddr) - fmt.Println("Deployed to:", fmt.Sprintf("0x%s", contractAddressHex)) - fmt.Println("Transaction hash:", resp.Hex()) - return nil - }, - } - - cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") - cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") - cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") - cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") - flags.AddTxFlagsToCmd(cmd) - - return cmd -} - func CmdCallContract() *cobra.Command { cmd := &cobra.Command{ - Use: "call-contract [addr] [payload hex] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Use: "call-contract [addr] [payload hex] --value= --from= --gas-fee-cap= --gas-limt= --evm-rpc=", Short: "Call EVM contract with a bytes payload in hex", Long: "", Args: cobra.ExactArgs(2), @@ -578,17 +321,21 @@ func CmdCallContract() *cobra.Command { } } - value, err := cmd.Flags().GetUint64(FlagValue) + value, err := cmd.Flags().GetString(FlagValue) if err != nil { return err } + valueBig, success := new(big.Int).SetString(value, 10) + if !success || valueBig.Cmp(utils.Big0) < 0 { + return fmt.Errorf("%s is not a valid value. Must be a decimal nonnegative integer", value) + } txData, err := getTxData(cmd) if err != nil { return err } txData.Nonce = nonce - txData.Value = big.NewInt(int64(value)) + txData.Value = valueBig txData.Data = payload txData.To = &contract @@ -604,7 +351,7 @@ func CmdCallContract() *cobra.Command { cmd.Flags().Uint64(FlagGasFeeCap, 1000000000000, "Gas fee cap for the transaction") cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") - cmd.Flags().Uint64(FlagValue, 0, "Value for the transaction") + cmd.Flags().String(FlagValue, "0", "Value for the transaction") cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") flags.AddTxFlagsToCmd(cmd) @@ -681,19 +428,15 @@ func CmdERC20Send() *cobra.Command { return cmd } -func CmdDelegate() *cobra.Command { +func CmdCallPrecompile() *cobra.Command { cmd := &cobra.Command{ - Use: "delegate [val-addr] [amount] --from= --gas-fee-cap= --gas-limt= --evm-rpc=", - Short: "delegate recipient usei", + Use: "call-precompile [precompile name] [method] [args...] --value= --from= --gas-fee-cap= --gas-limt= --evm-rpc=", + Short: "call method on precompile", Long: "", - Args: cobra.ExactArgs(2), + Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) (err error) { - amt, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } - abi := staking.GetABI() - payload, err := abi.Pack("delegate", args[0], new(big.Int).SetUint64(amt)) + pInfo := precompiles.GetPrecompileInfo(args[0]) + payload, err := getMethodPayload(pInfo.ABI, args[1:]) if err != nil { return err } @@ -717,14 +460,23 @@ func CmdDelegate() *cobra.Command { } } + value, err := cmd.Flags().GetString(FlagValue) + if err != nil { + return err + } + valueBig, success := new(big.Int).SetString(value, 10) + if !success || valueBig.Cmp(utils.Big0) < 0 { + return fmt.Errorf("%s is not a valid value. Must be a decimal nonnegative integer", value) + } + txData, err := getTxData(cmd) if err != nil { return err } txData.Nonce = nonce - txData.Value = utils.Big0 + txData.Value = valueBig txData.Data = payload - to := common.HexToAddress(staking.StakingAddress) + to := pInfo.Address txData.To = &to resp, err := sendTx(txData, rpc, key) @@ -741,6 +493,7 @@ func CmdDelegate() *cobra.Command { cmd.Flags().Uint64(FlagGas, 7000000, "Gas limit for the transaction") cmd.Flags().String(FlagRPC, fmt.Sprintf("http://%s:8545", evmrpc.LocalAddress), "RPC endpoint to send request to") cmd.Flags().Int64(FlagNonce, -1, "Nonce override for the transaction. Negative value means no override") + cmd.Flags().String(FlagValue, "", "Value for the transaction") flags.AddTxFlagsToCmd(cmd) return cmd