diff --git a/exposed/evm.go b/exposed/evm.go index 53d05e7..1d60c83 100644 --- a/exposed/evm.go +++ b/exposed/evm.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/okex/okexchain-go-sdk/module/evm/types" gosdktypes "github.com/okex/okexchain-go-sdk/types" + rpctypes "github.com/okex/okexchain/app/rpc/types" ) // Evm shows the expected behavior for inner farm client @@ -38,10 +39,11 @@ type web3Getter interface { // Web3Proxy shows the expected behavior as Web3 without rest server routing type Web3Proxy interface { - Web3Query + Web3ProxyQuery } // Web3Query shows the expected behavior as web3 query request -type Web3Query interface { - BlockNumber() (hexutil.Uint64, error) +type Web3ProxyQuery interface { + BlockNumberProxy() (hexutil.Uint64, error) + EstimateGasProxy(args rpctypes.CallArgs) (hexutil.Uint64, error) } diff --git a/go.mod b/go.mod index 559f775..1430c8f 100644 --- a/go.mod +++ b/go.mod @@ -7,13 +7,13 @@ require ( github.com/cosmos/cosmos-sdk v0.39.2 github.com/ethereum/go-ethereum v1.9.25 github.com/golang/mock v1.5.0 - github.com/okex/okexchain v0.16.8 + github.com/okex/okexchain v0.16.9-0.20210310104528-ee5068ccb54b github.com/stretchr/testify v1.6.1 github.com/tendermint/tendermint v0.33.9 ) replace ( - github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.2-okexchain7 + github.com/cosmos/cosmos-sdk => github.com/okex/cosmos-sdk v0.39.2-okexchain9 github.com/tendermint/iavl => github.com/okex/iavl v0.14.1-okexchain1 - github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-okexchain4 + github.com/tendermint/tendermint => github.com/okex/tendermint v0.33.9-okexchain5 ) diff --git a/go.sum b/go.sum index 1a9f35e..e996b1d 100644 --- a/go.sum +++ b/go.sum @@ -506,14 +506,14 @@ github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/okex/cosmos-sdk v0.39.2-okexchain7 h1:7fi/6BDN1wWkyXSssqk0rL9T9p61AElSCk3DMANWN94= -github.com/okex/cosmos-sdk v0.39.2-okexchain7/go.mod h1:Y1C2roqCVZ6gSYG31X77x4NLcbSGS9VP1GIiAE1imcc= +github.com/okex/cosmos-sdk v0.39.2-okexchain9 h1:BgsmfnMdYq+kM2SeJXrUMGniYoYq2KqYodms4KO57ZM= +github.com/okex/cosmos-sdk v0.39.2-okexchain9/go.mod h1:Y1C2roqCVZ6gSYG31X77x4NLcbSGS9VP1GIiAE1imcc= github.com/okex/iavl v0.14.1-okexchain1 h1:aP9Rpxb1QU06WgTJ/xLyEQbZOiZzKy3once7wGtNLIU= github.com/okex/iavl v0.14.1-okexchain1/go.mod h1:QmfViflFiXzxKLQE4tAUuWQHq+RSuQFxablW5oJZ6sE= -github.com/okex/okexchain v0.16.8 h1:pZCkV9d1wQycu1mOQgRkEjPWI2uCKDknwqaYCqMvXcQ= -github.com/okex/okexchain v0.16.8/go.mod h1:WjVxErmoYxD7safCzaN8jzizlyDMHmhkAOtxIO0sVpI= -github.com/okex/tendermint v0.33.9-okexchain4 h1:Xa/ouxDTfizyFa8YlfQJAfv9i4g85VQpAWTudwqZWLw= -github.com/okex/tendermint v0.33.9-okexchain4/go.mod h1:JU/5BLYWuZXBi5QPfGrewezhwHf7FiZu6+0RyK6d7F0= +github.com/okex/okexchain v0.16.9-0.20210310104528-ee5068ccb54b h1:vyDS5CJwW0yEsuF4FUA3C+Kwke7oFUM7IAIGFelpRz4= +github.com/okex/okexchain v0.16.9-0.20210310104528-ee5068ccb54b/go.mod h1:XuAYQ4GUp0uz36YXNuwdjOOkap82MCczmO/E76+lXHo= +github.com/okex/tendermint v0.33.9-okexchain5 h1:EmwYtssONbLjBbkX8SnjvgL5gNdLGzqPi/ch/yn1NC8= +github.com/okex/tendermint v0.33.9-okexchain5/go.mod h1:EoGTbJUufUueNIigY3zyO6f7GOj29OdpFhuR8sxWdSU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -780,7 +780,6 @@ golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200406173513-056763e48d71/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= diff --git a/module/evm/types/types.go b/module/evm/types/types.go index 5f8657f..e017afa 100644 --- a/module/evm/types/types.go +++ b/module/evm/types/types.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + apptypes "github.com/okex/okexchain/app/types" evmtypes "github.com/okex/okexchain/x/evm/types" "math/big" ) @@ -18,9 +19,6 @@ type ( ) var ( - DefaultGasPrice *big.Int + DefaultGasPrice = sdk.MustNewDecFromStr(defaultGasPrice).BigInt() + DefaultRPCGasLimit = big.NewInt(apptypes.DefaultRPCGasLimit) ) - -func init() { - DefaultGasPrice = sdk.MustNewDecFromStr(defaultGasPrice).BigInt() -} diff --git a/module/evm/web3_proxy.go b/module/evm/web3_proxy.go index 57ffb6d..f3e24a3 100644 --- a/module/evm/web3_proxy.go +++ b/module/evm/web3_proxy.go @@ -1,9 +1,23 @@ package evm import ( + "errors" + "fmt" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/exported" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ethcmn "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/okex/okexchain-go-sdk/exposed" + "github.com/okex/okexchain-go-sdk/module/evm/types" gosdktypes "github.com/okex/okexchain-go-sdk/types" + "github.com/okex/okexchain-go-sdk/utils" + rpctypes "github.com/okex/okexchain/app/rpc/types" + apptypes "github.com/okex/okexchain/app/types" + evmtypes "github.com/okex/okexchain/x/evm/types" ) // Web3Proxy returns the client with exposed.Web3Proxy's behaviour @@ -11,8 +25,8 @@ func (ec evmClient) Web3Proxy() exposed.Web3Proxy { return gosdktypes.Module(ec).(exposed.Web3Proxy) } -// BlockNumber returns the current block number as method "eth_blockNumber" -func (ec evmClient) BlockNumber() (hexutil.Uint64, error) { +// BlockNumberProxy returns the current block number as method "eth_blockNumber" without rest server routing +func (ec evmClient) BlockNumberProxy() (hexutil.Uint64, error) { resBlockchainInfo, err := ec.BlockchainInfo(0, 0) if err != nil { return hexutil.Uint64(0), err @@ -26,3 +40,104 @@ func (ec evmClient) BlockNumber() (hexutil.Uint64, error) { return hexutil.Uint64(blockNumber), nil } + +// EstimateGasProxy returns the estimated gas according to the args as method "eth_estimateGas" without rest server routing +func (ec evmClient) EstimateGasProxy(args rpctypes.CallArgs) (estimatedGas hexutil.Uint64, err error) { + simResponse, err := ec.doCallProxy(args, types.DefaultRPCGasLimit) + if err != nil { + return + } + + estimatedGas = hexutil.Uint64(simResponse.GasInfo.GasUsed + 1000) + return +} + +func (ec evmClient) accountNonce(addr ethcmn.Address) (nonce uint64, err error) { + // get account info from chain + path := fmt.Sprintf("custom/%s/%s", auth.QuerierRoute, auth.QueryAccount) + bytes, err := ec.GetCodec().MarshalJSON(authtypes.NewQueryAccountParams(addr.Bytes())) + if err != nil { + return nonce, utils.ErrClientQuery(err.Error()) + } + + res, _, err := ec.Query(path, bytes) + if res == nil { + return nonce, errors.New("failed. your account has no record on the chain") + } + + var account exported.Account + if err = ec.GetCodec().UnmarshalJSON(res, &account); err != nil { + return nonce, utils.ErrUnmarshalJSON(err.Error()) + } + + return account.GetSequence(), err +} + +func (ec evmClient) doCallProxy(args rpctypes.CallArgs, globalGasCap *big.Int) ( + simResponse *sdk.SimulationResponse, err error) { + if args.From == nil { + return simResponse, errors.New("failed. empty from address in CallArgs") + } + + nonce, _ := ec.accountNonce(*args.From) + + // Set default gas & gas price if none were set + // Change this to uint64(math.MaxUint64 / 2) if gas cap can be configured + gas := uint64(apptypes.DefaultRPCGasLimit) + if args.Gas != nil { + gas = uint64(*args.Gas) + } + + if globalGasCap != nil && globalGasCap.Uint64() < gas { + gas = globalGasCap.Uint64() + } + + // Set gas price using default or parameter if passed in + gasPrice := big.NewInt(apptypes.DefaultGasPrice) + if args.GasPrice != nil { + gasPrice = args.GasPrice.ToInt() + } + + // Set value for transaction + value := new(big.Int) + if args.Value != nil { + value = args.Value.ToInt() + } + + // Set Data if provided + var data []byte + if args.Data != nil { + data = *args.Data + } + + // Set destination address for call + var toAddr sdk.AccAddress + if args.To != nil { + toAddr = args.To.Bytes() + } + + simMsg := evmtypes.NewMsgEthermint(nonce, &toAddr, sdk.NewIntFromBigInt(value), gas, sdk.NewIntFromBigInt(gasPrice), + data, args.From.Bytes()) + + var stdSig authtypes.StdSignature + tx := authtypes.NewStdTx([]sdk.Msg{simMsg}, authtypes.StdFee{}, []authtypes.StdSignature{stdSig}, "") + if err = tx.ValidateBasic(); err != nil { + return + } + + cdc := ec.GetCodec() + txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx) + if err != nil { + return + } + + // Transaction simulation through query + res, _, err := ec.Query("app/simulate", txBytes) + if err != nil { + return + } + + simResponse = new(sdk.SimulationResponse) + + return simResponse, cdc.UnmarshalBinaryBare(res, simResponse) +}