diff --git a/app/ante/account_number.go b/app/ante/account_number.go new file mode 100644 index 0000000..bcd355a --- /dev/null +++ b/app/ante/account_number.go @@ -0,0 +1,48 @@ +package ante + +import ( + storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + cosmosante "github.com/cosmos/cosmos-sdk/x/auth/ante" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" +) + +// AccountNumberDecorator is a custom ante handler that increments the account number depending on +// the execution mode (Simulate, CheckTx, Finalize). +// +// This is to avoid account number conflicts when running concurrent Simulate, CheckTx, and Finalize. +type AccountNumberDecorator struct { + ak cosmosante.AccountKeeper +} + +// NewAccountNumberDecorator creates a new instance of AccountNumberDecorator. +func NewAccountNumberDecorator(ak cosmosante.AccountKeeper) AccountNumberDecorator { + return AccountNumberDecorator{ak} +} + +// AnteHandle is the AnteHandler implementation for AccountNumberDecorator. +func (and AccountNumberDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { + if !ctx.IsCheckTx() && !ctx.IsReCheckTx() && !simulate { + return next(ctx, tx, simulate) + } + + ak := and.ak.(*authkeeper.AccountKeeper) + + gasFreeCtx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) + num, err := ak.AccountNumber.Peek(gasFreeCtx) + if err != nil { + return ctx, err + } + + accountNumAddition := uint64(1_000_000) + if simulate { + accountNumAddition += 1_000_000 + } + + if err := ak.AccountNumber.Set(gasFreeCtx, num+accountNumAddition); err != nil { + return ctx, err + } + + return next(ctx, tx, simulate) +} diff --git a/app/ante/ante.go b/app/ante/ante.go index 081263f..504d54a 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -11,6 +11,8 @@ import ( opchildante "github.com/initia-labs/OPinit/x/opchild/ante" opchildtypes "github.com/initia-labs/OPinit/x/opchild/types" + initiaante "github.com/initia-labs/initia/app/ante" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" "github.com/skip-mev/block-sdk/v2/block" auctionante "github.com/skip-mev/block-sdk/v2/x/auction/ante" @@ -25,9 +27,11 @@ type HandlerOptions struct { IBCkeeper *ibckeeper.Keeper OPChildKeeper opchildtypes.AnteKeeper AuctionKeeper auctionkeeper.Keeper - TxEncoder sdk.TxEncoder - MevLane auctionante.MEVLane - FreeLane block.Lane + EVMKeeper *evmkeeper.Keeper + + TxEncoder sdk.TxEncoder + MevLane auctionante.MEVLane + FreeLane block.Lane } // NewAnteHandler returns an AnteHandler that checks and increments sequence @@ -46,9 +50,13 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") } + if options.EVMKeeper == nil { + return nil, errorsmod.Wrap(sdkerrors.ErrLogic, "EVM keeper is required for ante builder") + } + sigGasConsumer := options.SigGasConsumer if sigGasConsumer == nil { - sigGasConsumer = ante.DefaultSigVerificationGasConsumer + sigGasConsumer = initiaante.DefaultSigVerificationGasConsumer } txFeeChecker := options.TxFeeChecker @@ -72,6 +80,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { } anteDecorators := []sdk.AnteDecorator{ + NewAccountNumberDecorator(options.AccountKeeper), ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), @@ -83,7 +92,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { ante.NewSetPubKeyDecorator(options.AccountKeeper), ante.NewValidateSigCountDecorator(options.AccountKeeper), ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), - ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + NewSigVerificationDecorator(options.AccountKeeper, options.EVMKeeper, options.SignModeHandler), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewRedundantRelayDecorator(options.IBCkeeper), auctionante.NewAuctionDecorator(options.AuctionKeeper, options.TxEncoder, options.MevLane), diff --git a/app/ante/sigverify.go b/app/ante/sigverify.go new file mode 100644 index 0000000..0b3b9c6 --- /dev/null +++ b/app/ante/sigverify.go @@ -0,0 +1,200 @@ +package ante + +import ( + "fmt" + + "google.golang.org/protobuf/types/known/anypb" + + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + txsigning "cosmossdk.io/x/tx/signing" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/initia-labs/initia/crypto/ethsecp256k1" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" +) + +// SigVerificationDecorator verifies all signatures for a tx and return an error if any are invalid. Note, +// the SigVerificationDecorator will not check signatures on ReCheck. +// +// CONTRACT: Pubkeys are set in context for all signers before this decorator runs +// CONTRACT: Tx must implement SigVerifiableTx interface +type SigVerificationDecorator struct { + ak authante.AccountKeeper + ek *evmkeeper.Keeper + signModeHandler *txsigning.HandlerMap +} + +func NewSigVerificationDecorator( + ak authante.AccountKeeper, + ek *evmkeeper.Keeper, + signModeHandler *txsigning.HandlerMap) SigVerificationDecorator { + return SigVerificationDecorator{ + ak: ak, + ek: ek, + signModeHandler: signModeHandler, + } +} + +func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + sigTx, ok := tx.(authsigning.Tx) + if !ok { + return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type") + } + + // stdSigs contains the sequence number, account number, and signatures. + // When simulating, this would just be a 0-length slice. + sigs, err := sigTx.GetSignaturesV2() + if err != nil { + return ctx, err + } + + signers, err := sigTx.GetSigners() + if err != nil { + return ctx, err + } + + // check that signer length and signature length are the same + if len(sigs) != len(signers) { + return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signers), len(sigs)) + } + + for i, sig := range sigs { + acc, err := authante.GetSignerAcc(ctx, svd.ak, signers[i]) + if err != nil { + return ctx, err + } + + // retrieve pubkey + pubKey := acc.GetPubKey() + if !simulate && pubKey == nil { + return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set") + } + + // Check account sequence number. + if sig.Sequence != acc.GetSequence() { + return ctx, errorsmod.Wrapf( + sdkerrors.ErrWrongSequence, + "account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence, + ) + } + + // retrieve signer data + genesis := ctx.BlockHeight() == 0 + chainID := ctx.ChainID() + var accNum uint64 + if !genesis { + accNum = acc.GetAccountNumber() + } + + // no need to verify signatures on recheck tx + if !simulate && !ctx.IsReCheckTx() { + anyPk, _ := codectypes.NewAnyWithValue(pubKey) + + signerData := txsigning.SignerData{ + Address: acc.GetAddress().String(), + ChainID: chainID, + AccountNumber: accNum, + Sequence: acc.GetSequence(), + PubKey: &anypb.Any{ + TypeUrl: anyPk.TypeUrl, + Value: anyPk.Value, + }, + } + adaptableTx, ok := tx.(authsigning.V2AdaptableTx) + if !ok { + return ctx, fmt.Errorf("expected tx to implement V2AdaptableTx, got %T", tx) + } + txData := adaptableTx.GetSigningTxData() + err = verifySignature(ctx, pubKey, signerData, sig.Data, svd.signModeHandler, txData, svd.ek, tx) + if err != nil { + var errMsg string + if authante.OnlyLegacyAminoSigners(sig.Data) { + // If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number, + // and therefore communicate sequence number as a potential cause of error. + errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID) + } else { + errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s): (%s)", accNum, chainID, err.Error()) + } + return ctx, errorsmod.Wrap(sdkerrors.ErrUnauthorized, errMsg) + + } + } + } + + return next(ctx, tx, simulate) +} + +// defaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas +// for signature verification based upon the public key type. The cost is fetched from the given params and is matched +// by the concrete type. +func DefaultSigVerificationGasConsumer( + meter storetypes.GasMeter, sig signing.SignatureV2, params types.Params, +) error { + pubkey := sig.PubKey + switch pubkey := pubkey.(type) { + case *ed25519.PubKey: + meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519") + return errorsmod.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported") + + case *secp256k1.PubKey, *ethsecp256k1.PubKey: + meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1") + return nil + + case *secp256r1.PubKey: + meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1") + return nil + + case multisig.PubKey: + multisignature, ok := sig.Data.(*signing.MultiSignatureData) + if !ok { + return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data) + } + err := consumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence) + if err != nil { + return err + } + return nil + + default: + return errorsmod.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey) + } +} + +// consumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature +func consumeMultisignatureVerificationGas( + meter storetypes.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey, + params types.Params, accSeq uint64, +) error { + size := sig.BitArray.Count() + sigIndex := 0 + + for i := 0; i < size; i++ { + if !sig.BitArray.GetIndex(i) { + continue + } + sigV2 := signing.SignatureV2{ + PubKey: pubkey.GetPubKeys()[i], + Data: sig.Signatures[sigIndex], + Sequence: accSeq, + } + err := DefaultSigVerificationGasConsumer(meter, sigV2, params) + if err != nil { + return err + } + sigIndex++ + } + + return nil +} diff --git a/app/ante/verify.go b/app/ante/verify.go new file mode 100644 index 0000000..0cb00a0 --- /dev/null +++ b/app/ante/verify.go @@ -0,0 +1,116 @@ +package ante + +import ( + "context" + "fmt" + + signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + errorsmod "cosmossdk.io/errors" + txsigning "cosmossdk.io/x/tx/signing" + + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/crypto/types/multisig" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" + evmtypes "github.com/initia-labs/minievm/x/evm/types" + + coretypes "github.com/ethereum/go-ethereum/core/types" +) + +// internalSignModeToAPI converts a signing.SignMode to a protobuf SignMode. +func internalSignModeToAPI(mode signing.SignMode) (signingv1beta1.SignMode, error) { + switch mode { + case signing.SignMode_SIGN_MODE_DIRECT: + return signingv1beta1.SignMode_SIGN_MODE_DIRECT, nil + case signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON: + return signingv1beta1.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, nil + case signing.SignMode_SIGN_MODE_TEXTUAL: + return signingv1beta1.SignMode_SIGN_MODE_TEXTUAL, nil + case signing.SignMode_SIGN_MODE_DIRECT_AUX: + return signingv1beta1.SignMode_SIGN_MODE_DIRECT_AUX, nil + case signing.SignMode_SIGN_MODE_EIP_191: + return signingv1beta1.SignMode_SIGN_MODE_EIP_191, nil + default: + return signingv1beta1.SignMode_SIGN_MODE_UNSPECIFIED, fmt.Errorf("unsupported sign mode %s", mode) + } +} + +// verifySignature verifies a transaction signature contained in SignatureData abstracting over different signing +// modes. It differs from verifySignature in that it uses the new txsigning.TxData interface in x/tx. +func verifySignature( + ctx context.Context, + pubKey cryptotypes.PubKey, + signerData txsigning.SignerData, + signatureData signing.SignatureData, + handler *txsigning.HandlerMap, + txData txsigning.TxData, + // required to verify EVM signatures + ek *evmkeeper.Keeper, + tx sdk.Tx, +) error { + switch data := signatureData.(type) { + case *signing.SingleSignatureData: + if data.SignMode == evmkeeper.SignMode_SIGN_MODE_ETHEREUM { + // eth sign mode + ethTx, expectedSender, err := evmkeeper.NewTxUtils(ek).ConvertCosmosTxToEthereumTx(ctx, tx) + if err != nil { + return err + } + if ethTx == nil { + return fmt.Errorf("failed to convert tx to ethereum tx") + } + + sdkCtx := sdk.UnwrapSDKContext(ctx) + ethChainID := evmtypes.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID()) + signer := coretypes.LatestSignerForChainID(ethChainID) + sender, err := signer.Sender(ethTx) + if err != nil { + return errorsmod.Wrapf(sdkerrors.ErrorInvalidSigner, "failed to recover sender address: %v", err) + } + + // check if the recovered sender matches the expected sender + if expectedSender == nil || *expectedSender != sender { + return errorsmod.Wrapf(sdkerrors.ErrorInvalidSigner, "expected sender %s, got %s", expectedSender, sender) + } + + return nil + } + + signMode, err := internalSignModeToAPI(data.SignMode) + if err != nil { + return err + } + signBytes, err := handler.GetSignBytes(ctx, signMode, signerData, txData) + if err != nil { + return err + } + + if !pubKey.VerifySignature(signBytes, data.Signature) { + return fmt.Errorf("unable to verify single signer signature") + } + + return nil + + case *signing.MultiSignatureData: + multiPK, ok := pubKey.(multisig.PubKey) + if !ok { + return fmt.Errorf("expected %T, got %T", (multisig.PubKey)(nil), pubKey) + } + err := multiPK.VerifyMultisignature(func(mode signing.SignMode) ([]byte, error) { + signMode, err := internalSignModeToAPI(mode) + if err != nil { + return nil, err + } + return handler.GetSignBytes(ctx, signMode, signerData, txData) + }, data) + if err != nil { + return err + } + return nil + default: + return fmt.Errorf("unexpected SignatureData %T", signatureData) + } +} diff --git a/app/app.go b/app/app.go index 5aa5a5d..88b0ebe 100644 --- a/app/app.go +++ b/app/app.go @@ -103,6 +103,7 @@ import ( appheaderinfo "github.com/initia-labs/initia/app/header_info" initialanes "github.com/initia-labs/initia/app/lanes" "github.com/initia-labs/initia/app/params" + cryptocodec "github.com/initia-labs/initia/crypto/codec" ibchooks "github.com/initia-labs/initia/x/ibc-hooks" ibchookskeeper "github.com/initia-labs/initia/x/ibc-hooks/keeper" ibchookstypes "github.com/initia-labs/initia/x/ibc-hooks/types" @@ -144,6 +145,7 @@ import ( ibcevmhooks "github.com/initia-labs/minievm/app/ibc-hooks" appkeepers "github.com/initia-labs/minievm/app/keepers" + evmindexer "github.com/initia-labs/minievm/indexer" "github.com/initia-labs/minievm/x/bank" bankkeeper "github.com/initia-labs/minievm/x/bank/keeper" "github.com/initia-labs/minievm/x/evm" @@ -267,12 +269,16 @@ type MinitiaApp struct { // fake keeper to indexer indexerKeeper *indexerkeeper.Keeper indexerModule indexermodule.AppModuleBasic + + // evm indexer + evmIndexer evmindexer.EVMIndexer } // NewMinitiaApp returns a reference to an initialized Initia. func NewMinitiaApp( logger log.Logger, db dbm.DB, + indexerDB dbm.DB, traceStore io.Writer, loadLatest bool, evmConfig evmconfig.EVMConfig, @@ -289,6 +295,8 @@ func NewMinitiaApp( encodingConfig := params.MakeEncodingConfig() std.RegisterLegacyAminoCodec(encodingConfig.Amino) std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + cryptocodec.RegisterLegacyAminoCodec(encodingConfig.Amino) + cryptocodec.RegisterInterfaces(encodingConfig.InterfaceRegistry) appCodec := encodingConfig.Codec legacyAmino := encodingConfig.Amino @@ -760,7 +768,7 @@ func NewMinitiaApp( marketmap.NewAppModule(appCodec, app.MarketMapKeeper), ) - if err := app.setupIndexer(appOpts, homePath, ac, vc, appCodec); err != nil { + if err := app.setupIndexer(indexerDB, appOpts, homePath, ac, vc, appCodec); err != nil { panic(err) } @@ -902,7 +910,8 @@ func NewMinitiaApp( panic(err) } - app.SetMempool(mempool) + // wrap mempool to receive pending txs from the indexer + app.SetMempool(app.evmIndexer.MempoolWrapper(mempool)) anteHandler := app.setAnteHandler(mevLane, freeLane) // NOTE seems this optional, to reduce mempool logic cost @@ -1024,6 +1033,7 @@ func (app *MinitiaApp) setAnteHandler( AuctionKeeper: *app.AuctionKeeper, MevLane: mevLane, FreeLane: freeLane, + EVMKeeper: app.EVMKeeper, }, ) if err != nil { @@ -1259,11 +1269,11 @@ func VerifyAddressLen() func(addr []byte) error { } } -func (app *MinitiaApp) setupIndexer(appOpts servertypes.AppOptions, homePath string, ac, vc address.Codec, appCodec codec.Codec) error { +func (app *MinitiaApp) setupIndexer(indexerDB dbm.DB, appOpts servertypes.AppOptions, homePath string, ac, vc address.Codec, appCodec codec.Codec) error { // initialize the indexer fake-keeper indexerConfig, err := indexerconfig.NewConfig(appOpts) if err != nil { - panic(err) + return err } app.indexerKeeper = indexerkeeper.NewKeeper( appCodec, @@ -1276,56 +1286,66 @@ func (app *MinitiaApp) setupIndexer(appOpts servertypes.AppOptions, homePath str smBlock, err := blocksubmodule.NewBlockSubmodule(appCodec, app.indexerKeeper, app.OPChildKeeper) if err != nil { - panic(err) + return err } smTx, err := tx.NewTxSubmodule(appCodec, app.indexerKeeper) if err != nil { - panic(err) + return err } smPair, err := pair.NewPairSubmodule(appCodec, app.indexerKeeper, app.IBCKeeper.ChannelKeeper, app.TransferKeeper) if err != nil { - panic(err) + return err } - /* - smNft, err := nft.NewMoveNftSubmodule(ac, appCodec, app.indexerKeeper, app.EvmKeeper, smPair) - if err != nil { - panic(err) - } - err = app.indexerKeeper.RegisterSubmodules(smBlock, smTx, smPair, smNft) - */ + err = app.indexerKeeper.RegisterSubmodules(smBlock, smTx, smPair) if err != nil { - panic(err) + return err } + app.indexerModule = indexermodule.NewAppModuleBasic(app.indexerKeeper) + // Add your implementation here indexer, err := indexer.NewIndexer(app.GetBaseApp().Logger(), app.indexerKeeper) - if err != nil || indexer == nil { + if err != nil { return nil } - if err = indexer.Validate(); err != nil { - return err - } + liseners := []storetypes.ABCIListener{} + if indexer != nil { + if err = indexer.Validate(); err != nil { + return err + } - if err = indexer.Prepare(nil); err != nil { - return err - } + if err = indexer.Prepare(nil); err != nil { + return err + } - if err = app.indexerKeeper.Seal(); err != nil { - return err + if err = app.indexerKeeper.Seal(); err != nil { + return err + } + + if err = indexer.Start(nil); err != nil { + return err + } + + liseners = append(liseners, indexer) } - if err = indexer.Start(nil); err != nil { + // add evm indexer + evmIndexer, err := evmindexer.NewEVMIndexer(indexerDB, appCodec, app.Logger(), app.txConfig, app.EVMKeeper) + if err != nil { return err } - streamingManager := storetypes.StreamingManager{ - ABCIListeners: []storetypes.ABCIListener{indexer}, + // register evm indexer to app + app.evmIndexer = evmIndexer + liseners = append(liseners, evmIndexer) + + app.SetStreamingManager(storetypes.StreamingManager{ + ABCIListeners: liseners, StopNodeOnErr: true, - } - app.SetStreamingManager(streamingManager) + }) return nil } @@ -1345,3 +1365,15 @@ func (app *MinitiaApp) Close() error { return nil } + +// IndexerKeeper returns the evm indexer +func (app *MinitiaApp) EVMIndexer() evmindexer.EVMIndexer { + return app.evmIndexer +} + +// CheckStateContextGetter returns a function that returns a new Context for state checking. +func (app *MinitiaApp) CheckStateContextGetter() func() sdk.Context { + return func() sdk.Context { + return app.GetContextForCheckTx(nil) + } +} diff --git a/app/app_test.go b/app/app_test.go index 9b3c372..65ac9e4 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -65,7 +65,10 @@ func TestInitGenesisOnMigration(t *testing.T) { db := dbm.NewMemDB() logger := log.NewLogger(os.Stdout) app := NewMinitiaApp( - logger, db, nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) + logger, db, dbm.NewMemDB(), + nil, true, evmconfig.DefaultEVMConfig(), + EmptyAppOptions{}, + ) ctx := app.NewContextLegacy(true, cmtproto.Header{Height: app.LastBlockHeight()}) // Create a mock module. This module will serve as the new module we're @@ -121,7 +124,10 @@ func TestGetKey(t *testing.T) { db := dbm.NewMemDB() app := NewMinitiaApp( log.NewLogger(os.Stdout), - db, nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) + db, dbm.NewMemDB(), nil, true, + evmconfig.DefaultEVMConfig(), + EmptyAppOptions{}, + ) require.NotEmpty(t, app.GetKey(banktypes.StoreKey)) require.NotEmpty(t, app.GetMemKey(capabilitytypes.MemStoreKey)) diff --git a/app/const.go b/app/const.go index 1d2b25e..c04c89d 100644 --- a/app/const.go +++ b/app/const.go @@ -2,7 +2,7 @@ package app const ( // FeeDeductionGasAmount is a estimated gas amount of fee payment - FeeDeductionGasAmount = 50_000 + FeeDeductionGasAmount = 150_000 // AccountAddressPrefix is the prefix of bech32 encoded address AccountAddressPrefix = "init" diff --git a/app/encoding.go b/app/encoding.go index 412c161..d02b001 100644 --- a/app/encoding.go +++ b/app/encoding.go @@ -18,7 +18,7 @@ import ( // MakeEncodingConfig creates an EncodingConfig for testing func MakeEncodingConfig() params.EncodingConfig { - tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) + tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) encodingConfig := params.EncodingConfig{ InterfaceRegistry: tempApp.InterfaceRegistry(), Codec: tempApp.AppCodec(), @@ -30,7 +30,7 @@ func MakeEncodingConfig() params.EncodingConfig { } func AutoCliOpts() autocli.AppOptions { - tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) + tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) modules := make(map[string]appmodule.AppModule, 0) for _, m := range tempApp.ModuleManager.Modules { if moduleWithName, ok := m.(module.HasName); ok { @@ -51,7 +51,7 @@ func AutoCliOpts() autocli.AppOptions { } func BasicManager() module.BasicManager { - tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) + tempApp := NewMinitiaApp(log.NewNopLogger(), dbm.NewMemDB(), dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), EmptyAppOptions{}) return tempApp.BasicModuleManager } diff --git a/app/genesis.go b/app/genesis.go index aaff606..d8f57a9 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -22,6 +22,8 @@ import ( slinkytypes "github.com/skip-mev/slinky/pkg/types" marketmaptypes "github.com/skip-mev/slinky/x/marketmap/types" oracletypes "github.com/skip-mev/slinky/x/oracle/types" + + evmtypes "github.com/initia-labs/minievm/x/evm/types" ) // GenesisState - The genesis state of the blockchain is represented here as a map of raw json @@ -39,7 +41,7 @@ func NewDefaultGenesisState(cdc codec.Codec, mbm module.BasicManager, denom stri ConfigureMinGasPrices(cdc). ConfigureICA(cdc). ConfigureIBCAllowedClients(cdc). - ConfigureAuctionFee(cdc, denom). + ConfigureDefaultDenom(cdc, denom). AddMarketData(cdc, cdc.InterfaceRegistry().SigningContext().AddressCodec()) } @@ -105,13 +107,18 @@ func (genState GenesisState) AddMarketData(cdc codec.JSONCodec, ac address.Codec return genState } -func (genState GenesisState) ConfigureAuctionFee(cdc codec.JSONCodec, denom string) GenesisState { +func (genState GenesisState) ConfigureDefaultDenom(cdc codec.JSONCodec, denom string) GenesisState { var auctionGenState auctiontypes.GenesisState cdc.MustUnmarshalJSON(genState[auctiontypes.ModuleName], &auctionGenState) auctionGenState.Params.ReserveFee.Denom = denom auctionGenState.Params.MinBidIncrement.Denom = denom genState[auctiontypes.ModuleName] = cdc.MustMarshalJSON(&auctionGenState) + var evmGenState evmtypes.GenesisState + cdc.MustUnmarshalJSON(genState[evmtypes.ModuleName], &evmGenState) + evmGenState.Params.FeeDenom = denom + genState[evmtypes.ModuleName] = cdc.MustMarshalJSON(&evmGenState) + return genState } diff --git a/app/ibc-hooks/ack_test.go b/app/ibc-hooks/ack_test.go index 1329e96..31f499a 100644 --- a/app/ibc-hooks/ack_test.go +++ b/app/ibc-hooks/ack_test.go @@ -51,7 +51,7 @@ func Test_onAckIcs20Packet_memo(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -87,7 +87,7 @@ func Test_onAckIcs20Packet_memo(t *testing.T) { // check the contract state queryInputBz, err := abi.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -102,7 +102,7 @@ func Test_onAckIcs20Packet_memo(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 99 if ack is success - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(99).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -114,7 +114,7 @@ func Test_onAckIcs20Packet_memo(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 1 if ack is failed - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(100).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -157,7 +157,7 @@ func Test_onAckPacket_memo_ICS721(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -197,7 +197,7 @@ func Test_onAckPacket_memo_ICS721(t *testing.T) { // check the contract state queryInputBz, err := abi.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -212,7 +212,7 @@ func Test_onAckPacket_memo_ICS721(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 99 if ack is success - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(99).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -224,7 +224,7 @@ func Test_onAckPacket_memo_ICS721(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 1 if ack is failed - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(100).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) diff --git a/app/ibc-hooks/receive_test.go b/app/ibc-hooks/receive_test.go index f92f602..96df29d 100644 --- a/app/ibc-hooks/receive_test.go +++ b/app/ibc-hooks/receive_test.go @@ -49,7 +49,7 @@ func Test_onReceiveIcs20Packet_memo(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -95,7 +95,7 @@ func Test_onReceiveIcs20Packet_memo(t *testing.T) { require.NoError(t, err) // check the contract state - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -136,7 +136,7 @@ func Test_onReceiveIcs20Packet_memo_ICS721(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -182,7 +182,7 @@ func Test_onReceiveIcs20Packet_memo_ICS721(t *testing.T) { require.NoError(t, err) // check the contract state - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) diff --git a/app/ibc-hooks/timeout_test.go b/app/ibc-hooks/timeout_test.go index a28834f..b11b736 100644 --- a/app/ibc-hooks/timeout_test.go +++ b/app/ibc-hooks/timeout_test.go @@ -48,7 +48,7 @@ func Test_onTimeoutIcs20Packet_memo(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -81,7 +81,7 @@ func Test_onTimeoutIcs20Packet_memo(t *testing.T) { // check the contract state queryInputBz, err := abi.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -96,7 +96,7 @@ func Test_onTimeoutIcs20Packet_memo(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 99 - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(99).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -136,7 +136,7 @@ func Test_onTimeoutPacket_memo_ICS721(t *testing.T) { codeBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, evmAddr, codeBz, nil) require.NoError(t, err) abi, err := counter.CounterMetaData.GetAbi() @@ -169,7 +169,7 @@ func Test_onTimeoutPacket_memo_ICS721(t *testing.T) { // check the contract state queryInputBz, err := abi.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -184,7 +184,7 @@ func Test_onTimeoutPacket_memo_ICS721(t *testing.T) { require.NoError(t, err) // check the contract state; increased by 99 - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(99).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) diff --git a/app/test_helpers.go b/app/test_helpers.go index 74876b6..7ee75f9 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -21,7 +21,6 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" opchildtypes "github.com/initia-labs/OPinit/x/opchild/types" - "github.com/initia-labs/minievm/types" evmconfig "github.com/initia-labs/minievm/x/evm/config" ) @@ -57,6 +56,7 @@ func setup(db *dbm.DB, withGenesis bool) (*MinitiaApp, GenesisState) { app := NewMinitiaApp( log.NewNopLogger(), getOrCreateMemDB(db), + dbm.NewMemDB(), nil, true, evmconfig.DefaultEVMConfig(), @@ -64,7 +64,7 @@ func setup(db *dbm.DB, withGenesis bool) (*MinitiaApp, GenesisState) { ) if withGenesis { - return app, NewDefaultGenesisState(encCdc.Codec, app.BasicModuleManager, types.BaseDenom) + return app, NewDefaultGenesisState(encCdc.Codec, app.BasicModuleManager, sdk.DefaultBondDenom) } return app, GenesisState{} diff --git a/cmd/minitiad/config.go b/cmd/minitiad/config.go index 9872d27..3e474ef 100644 --- a/cmd/minitiad/config.go +++ b/cmd/minitiad/config.go @@ -8,6 +8,7 @@ import ( serverconfig "github.com/cosmos/cosmos-sdk/server/config" indexerconfig "github.com/initia-labs/kvindexer/config" + jsonrpcconfig "github.com/initia-labs/minievm/jsonrpc/config" evmconfig "github.com/initia-labs/minievm/x/evm/config" "github.com/initia-labs/minievm/types" @@ -18,6 +19,7 @@ type minitiaAppConfig struct { serverconfig.Config EVMConfig evmconfig.EVMConfig `mapstructure:"evm"` IndexerConfig indexerconfig.IndexerConfig `mapstructure:"indexer"` + JSONRPCConfig jsonrpcconfig.JSONRPCConfig `mapstructure:"jsonrpc"` } // initAppConfig helps to override default appConfig template and configs. @@ -56,10 +58,13 @@ func initAppConfig() (string, interface{}) { Config: *srvCfg, EVMConfig: evmconfig.DefaultEVMConfig(), IndexerConfig: indexerconfig.DefaultConfig(), + JSONRPCConfig: jsonrpcconfig.DefaultJSONRPCConfig(), } minitiaAppTemplate := serverconfig.DefaultConfigTemplate + - evmconfig.DefaultConfigTemplate + indexerconfig.DefaultConfigTemplate + evmconfig.DefaultConfigTemplate + + indexerconfig.DefaultConfigTemplate + + jsonrpcconfig.DefaultConfigTemplate return minitiaAppTemplate, minitiaAppConfig } diff --git a/cmd/minitiad/root.go b/cmd/minitiad/root.go index a29bd63..0e64c61 100644 --- a/cmd/minitiad/root.go +++ b/cmd/minitiad/root.go @@ -6,10 +6,12 @@ import ( "io" "os" "path" + "path/filepath" tmcli "github.com/cometbft/cometbft/libs/cli" "golang.org/x/sync/errgroup" + "github.com/spf13/cast" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -36,9 +38,12 @@ import ( "github.com/cosmos/cosmos-sdk/x/crisis" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + "github.com/initia-labs/minievm/jsonrpc" + jsonrpcconfig "github.com/initia-labs/minievm/jsonrpc/config" evmconfig "github.com/initia-labs/minievm/x/evm/config" "github.com/initia-labs/initia/app/params" + initiakeyring "github.com/initia-labs/initia/crypto/keyring" minitiaapp "github.com/initia-labs/minievm/app" opchildcli "github.com/initia-labs/OPinit/x/opchild/client/cli" @@ -86,7 +91,8 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { WithInput(os.Stdin). WithAccountRetriever(types.AccountRetriever{}). WithHomeDir(minitiaapp.DefaultNodeHome). - WithViper(minitiaapp.EnvPrefix) + WithViper(minitiaapp.EnvPrefix). + WithKeyringOptions(initiakeyring.EthSecp256k1Option()) rootCmd := &cobra.Command{ Use: basename, @@ -159,7 +165,14 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, b AddFlags: addModuleInitFlags, PostSetup: func(svrCtx *server.Context, clientCtx client.Context, ctx context.Context, g *errgroup.Group) error { sdk.GetConfig().Seal() - return nil + + // start jsonrpc server + return jsonrpc.StartJSONRPC( + ctx, g, a.App().(*minitiaapp.MinitiaApp), + svrCtx, + clientCtx, + jsonrpcconfig.GetConfig(a.appOpts), + ) }, }) @@ -249,15 +262,23 @@ func txCommand() *cobra.Command { } type appCreator struct { - app servertypes.Application + app servertypes.Application + appOpts servertypes.AppOptions } func (a *appCreator) AppCreator() servertypes.AppCreator { return func(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application { baseappOptions := server.DefaultBaseappOptions(appOpts) + // create EVM indexer db + dbDir, dbBackend := getDBConfig(appOpts) + indexerDB, err := dbm.NewDB("eth_index", dbBackend, dbDir) + if err != nil { + panic(err) + } + app := minitiaapp.NewMinitiaApp( - logger, db, traceStore, true, + logger, db, indexerDB, traceStore, true, evmconfig.GetConfig(appOpts), appOpts, baseappOptions..., @@ -265,6 +286,7 @@ func (a *appCreator) AppCreator() servertypes.AppCreator { // store app in creator a.app = app + a.appOpts = appOpts return app } @@ -292,13 +314,13 @@ func (a appCreator) appExport( var initiaApp *minitiaapp.MinitiaApp if height != -1 { - initiaApp = minitiaapp.NewMinitiaApp(logger, db, traceStore, false, evmconfig.DefaultEVMConfig(), appOpts) + initiaApp = minitiaapp.NewMinitiaApp(logger, db, dbm.NewMemDB(), traceStore, false, evmconfig.DefaultEVMConfig(), appOpts) if err := initiaApp.LoadHeight(height); err != nil { return servertypes.ExportedApp{}, err } } else { - initiaApp = minitiaapp.NewMinitiaApp(logger, db, traceStore, true, evmconfig.DefaultEVMConfig(), appOpts) + initiaApp = minitiaapp.NewMinitiaApp(logger, db, dbm.NewMemDB(), traceStore, true, evmconfig.DefaultEVMConfig(), appOpts) } return initiaApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) @@ -347,3 +369,20 @@ func readEnv(clientCtx client.Context) (client.Context, error) { return clientCtx, nil } + +// getDBConfig returns the database configuration for the EVM indexer +func getDBConfig(appOpts servertypes.AppOptions) (string, dbm.BackendType) { + rootDir := cast.ToString(appOpts.Get("home")) + dbDir := cast.ToString(appOpts.Get("db_dir")) + dbBackend := server.GetAppDBBackend(appOpts) + + return rootify(dbDir, rootDir), dbBackend +} + +// helper function to make config creation independent of root dir +func rootify(path, root string) string { + if filepath.IsAbs(path) { + return path + } + return filepath.Join(root, path) +} diff --git a/go.mod b/go.mod index dee8835..cdacaa6 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/hashicorp/go-metrics v0.5.3 github.com/holiman/uint256 v1.2.4 github.com/initia-labs/OPinit v0.3.2 - github.com/initia-labs/initia v0.3.3 + github.com/initia-labs/initia v0.3.4 github.com/initia-labs/kvindexer v0.1.3 github.com/initia-labs/kvindexer/submodules/block v0.1.0 github.com/initia-labs/kvindexer/submodules/pair v0.1.1 @@ -42,6 +42,7 @@ require ( github.com/noble-assets/forwarding/v2 v2.0.0-20240514101621-172acc02aac6 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 + github.com/rs/cors v1.8.3 github.com/skip-mev/block-sdk/v2 v2.1.2 github.com/skip-mev/slinky v0.4.3 github.com/spf13/cast v1.6.0 @@ -49,6 +50,8 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 + golang.org/x/crypto v0.23.0 + golang.org/x/net v0.25.0 golang.org/x/sync v0.7.0 google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 google.golang.org/grpc v1.63.2 @@ -68,9 +71,11 @@ require ( github.com/99designs/keyring v1.2.2 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect + github.com/IGLOU-EU/go-wildcard v1.0.3 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect + github.com/aptos-labs/serde-reflection/serde-generate/runtime/golang v0.0.0-20231213012317-73b6bbf74833 // indirect github.com/avast/retry-go/v4 v4.5.1 // indirect github.com/aws/aws-sdk-go v1.44.312 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -121,6 +126,7 @@ require ( github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-kit/kit v0.13.0 // indirect @@ -163,11 +169,14 @@ require ( github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect + github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/initia-labs/OPinit/api v0.3.0 // indirect + github.com/initia-labs/movevm v0.3.4 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/jsternberg/zap-logfmt v1.3.0 // indirect @@ -201,7 +210,6 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/rs/cors v1.8.3 // indirect github.com/rs/zerolog v1.32.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -209,6 +217,7 @@ require ( github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect + github.com/status-im/keycard-go v0.2.0 // indirect github.com/strangelove-ventures/cometbft-client v0.1.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.11 // indirect @@ -230,10 +239,8 @@ require ( go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/term v0.20.0 // indirect @@ -277,8 +284,7 @@ replace ( // initia custom replace ( - github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680 - github.com/cosmos/cosmos-sdk => github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501 + github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c github.com/cosmos/ibc-go/v8 => github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7 ) diff --git a/go.sum b/go.sum index 0611f31..29cd007 100644 --- a/go.sum +++ b/go.sum @@ -400,6 +400,8 @@ github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAK github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.7 h1:LsBGKxifENR/DN4E1RZaitsyL93HU44x0p8EnMHp4V4= +github.com/cosmos/cosmos-sdk v0.50.7/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= @@ -812,16 +814,14 @@ github.com/initia-labs/OPinit v0.3.2 h1:TeELD5GeSJJ9meY5b5YIXDdmCZt9kZOA2Chz+Iwx github.com/initia-labs/OPinit v0.3.2/go.mod h1:XlYsBFAKOFS6/wRIHB1vVbfonqX8QrC8cWK2GJvmX20= github.com/initia-labs/OPinit/api v0.3.0 h1:OY8ijwmgZLoYwtw9LI1mSY3VC8PY+gtxJFitB6ZNFl4= github.com/initia-labs/OPinit/api v0.3.0/go.mod h1:Xy/Nt3ubXLQ4zKn0m7RuQOM1sj8TVdlNNyek21TGYR0= -github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680 h1:4tcP5F26DdqiV1Y/XOllL4LUhyUV6HITfjVJnzR/Krs= -github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680/go.mod h1:qGaJePRWAc2OL3OGNd//8fqgypCaFjmwZcy/cNner84= -github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501 h1:OcLFeu3V9T156H4n6WzPNfKWjIUKdkC0P0EBA8zEWFE= -github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= +github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c h1:+icq583vNtAB5miQ+XAuTLqjzXyznRd/kc+ucHcmBXI= +github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c/go.mod h1:qGaJePRWAc2OL3OGNd//8fqgypCaFjmwZcy/cNner84= github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7 h1:V7K8wvE5FVVv6WTeITI+nqWfo4b9WlZyXQH0Olz5UVI= github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7/go.mod h1:x2gtBG0WHLgY08FE97lfhjtpcR5vcSAZbi34JnrsBbQ= github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c h1:FDwh5zZbm9v7C37ni4FytQQ9Os5XxYp1px5U7Nqdu2Y= github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8= -github.com/initia-labs/initia v0.3.3 h1:82ZkXki6CG+F+rPDBVpTzzSQY8NalXIZ0LnYSWNd+3U= -github.com/initia-labs/initia v0.3.3/go.mod h1:1yWifo9GnhIvwDtCTTN6kb2mfq2On+oel6ha/rBXaQQ= +github.com/initia-labs/initia v0.3.4 h1:i2fwTx9WDwGp2nyX64r6jtdtgfJmRqKAXGdxbHBRg9s= +github.com/initia-labs/initia v0.3.4/go.mod h1:nwtnVe3obacErGb7w6tq8Ych3U0d2f59rsgpVUeMnmM= github.com/initia-labs/kvindexer v0.1.3 h1:TLkgJjp5TiPnH+OzYfk7ZKQTKqGOfSte59Y3gasob+o= github.com/initia-labs/kvindexer v0.1.3/go.mod h1:rvAmgCAmEs4KM8sRRPcyTqNNwi8s2JiHybiFkYfp4KE= github.com/initia-labs/kvindexer/submodules/block v0.1.0 h1:y+EXnksd/I2F96mzIoQA64nZUZON2P+99YrSzeLCLoY= @@ -830,8 +830,8 @@ github.com/initia-labs/kvindexer/submodules/pair v0.1.1 h1:o151gA4jIbqEl+pWTOCiz github.com/initia-labs/kvindexer/submodules/pair v0.1.1/go.mod h1:8X1GE1ZLkH7z8TKb5MUh7UClTkcqVFIwXIIRdsqeUZY= github.com/initia-labs/kvindexer/submodules/tx v0.1.0 h1:6kbf6wmzXPN0XCQLasiFgq1AlZHkt5K3/ZG+IWw1nNs= github.com/initia-labs/kvindexer/submodules/tx v0.1.0/go.mod h1:i0XeLbLa6xdgTR01WF8kaAO50vMmwxbeq0fKexwpFHU= -github.com/initia-labs/movevm v0.3.3 h1:xUH5VvjBSfJP4jg3axefmBlcdZ/7qfVYnUU09R4oN4g= -github.com/initia-labs/movevm v0.3.3/go.mod h1:6MxR4GP5zH3JUc1IMgfqAe1e483mZVS7fshPknZPJ30= +github.com/initia-labs/movevm v0.3.4 h1:kzqs6uzTq0f5peZJNzLq/1qgnmAFfC+I9eCyPBducxM= +github.com/initia-labs/movevm v0.3.4/go.mod h1:6MxR4GP5zH3JUc1IMgfqAe1e483mZVS7fshPknZPJ30= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= diff --git a/go.work b/go.work index 694ccef..6ce2b47 100644 --- a/go.work +++ b/go.work @@ -4,3 +4,4 @@ use ( . ./integration-tests ) + diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..3843f7d --- /dev/null +++ b/go.work.sum @@ -0,0 +1,451 @@ +cloud.google.com/go v0.0.0-20170206221025-ce650573d812/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go/accessapproval v1.7.5/go.mod h1:g88i1ok5dvQ9XJsxpUInWWvUBrIZhyPDPbk4T01OoJ0= +cloud.google.com/go/accesscontextmanager v1.8.5/go.mod h1:TInEhcZ7V9jptGNqN3EzZ5XMhT6ijWxTGjzyETwmL0Q= +cloud.google.com/go/aiplatform v1.60.0/go.mod h1:eTlGuHOahHprZw3Hio5VKmtThIOak5/qy6pzdsqcQnM= +cloud.google.com/go/analytics v0.23.0/go.mod h1:YPd7Bvik3WS95KBok2gPXDqQPHy08TsCQG6CdUCb+u0= +cloud.google.com/go/apigateway v1.6.5/go.mod h1:6wCwvYRckRQogyDDltpANi3zsCDl6kWi0b4Je+w2UiI= +cloud.google.com/go/apigeeconnect v1.6.5/go.mod h1:MEKm3AiT7s11PqTfKE3KZluZA9O91FNysvd3E6SJ6Ow= +cloud.google.com/go/apigeeregistry v0.8.3/go.mod h1:aInOWnqF4yMQx8kTjDqHNXjZGh/mxeNlAf52YqtASUs= +cloud.google.com/go/appengine v1.8.5/go.mod h1:uHBgNoGLTS5di7BvU25NFDuKa82v0qQLjyMJLuPQrVo= +cloud.google.com/go/area120 v0.8.5/go.mod h1:BcoFCbDLZjsfe4EkCnEq1LKvHSK0Ew/zk5UFu6GMyA0= +cloud.google.com/go/artifactregistry v1.14.7/go.mod h1:0AUKhzWQzfmeTvT4SjfI4zjot72EMfrkvL9g9aRjnnM= +cloud.google.com/go/asset v1.17.2/go.mod h1:SVbzde67ehddSoKf5uebOD1sYw8Ab/jD/9EIeWg99q4= +cloud.google.com/go/assuredworkloads v1.11.5/go.mod h1:FKJ3g3ZvkL2D7qtqIGnDufFkHxwIpNM9vtmhvt+6wqk= +cloud.google.com/go/automl v1.13.5/go.mod h1:MDw3vLem3yh+SvmSgeYUmUKqyls6NzSumDm9OJ3xJ1Y= +cloud.google.com/go/baremetalsolution v1.2.4/go.mod h1:BHCmxgpevw9IEryE99HbYEfxXkAEA3hkMJbYYsHtIuY= +cloud.google.com/go/batch v1.8.0/go.mod h1:k8V7f6VE2Suc0zUM4WtoibNrA6D3dqBpB+++e3vSGYc= +cloud.google.com/go/beyondcorp v1.0.4/go.mod h1:Gx8/Rk2MxrvWfn4WIhHIG1NV7IBfg14pTKv1+EArVcc= +cloud.google.com/go/bigquery v1.59.1/go.mod h1:VP1UJYgevyTwsV7desjzNzDND5p6hZB+Z8gZJN1GQUc= +cloud.google.com/go/billing v1.18.2/go.mod h1:PPIwVsOOQ7xzbADCwNe8nvK776QpfrOAUkvKjCUcpSE= +cloud.google.com/go/binaryauthorization v1.8.1/go.mod h1:1HVRyBerREA/nhI7yLang4Zn7vfNVA3okoAR9qYQJAQ= +cloud.google.com/go/certificatemanager v1.7.5/go.mod h1:uX+v7kWqy0Y3NG/ZhNvffh0kuqkKZIXdvlZRO7z0VtM= +cloud.google.com/go/channel v1.17.5/go.mod h1:FlpaOSINDAXgEext0KMaBq/vwpLMkkPAw9b2mApQeHc= +cloud.google.com/go/cloudbuild v1.15.1/go.mod h1:gIofXZSu+XD2Uy+qkOrGKEx45zd7s28u/k8f99qKals= +cloud.google.com/go/clouddms v1.7.4/go.mod h1:RdrVqoFG9RWI5AvZ81SxJ/xvxPdtcRhFotwdE79DieY= +cloud.google.com/go/cloudtasks v1.12.6/go.mod h1:b7c7fe4+TJsFZfDyzO51F7cjq7HLUlRi/KZQLQjDsaY= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/contactcenterinsights v1.13.0/go.mod h1:ieq5d5EtHsu8vhe2y3amtZ+BE+AQwX5qAy7cpo0POsI= +cloud.google.com/go/container v1.31.0/go.mod h1:7yABn5s3Iv3lmw7oMmyGbeV6tQj86njcTijkkGuvdZA= +cloud.google.com/go/containeranalysis v0.11.4/go.mod h1:cVZT7rXYBS9NG1rhQbWL9pWbXCKHWJPYraE8/FTSYPE= +cloud.google.com/go/datacatalog v1.19.3/go.mod h1:ra8V3UAsciBpJKQ+z9Whkxzxv7jmQg1hfODr3N3YPJ4= +cloud.google.com/go/dataflow v0.9.5/go.mod h1:udl6oi8pfUHnL0z6UN9Lf9chGqzDMVqcYTcZ1aPnCZQ= +cloud.google.com/go/dataform v0.9.2/go.mod h1:S8cQUwPNWXo7m/g3DhWHsLBoufRNn9EgFrMgne2j7cI= +cloud.google.com/go/datafusion v1.7.5/go.mod h1:bYH53Oa5UiqahfbNK9YuYKteeD4RbQSNMx7JF7peGHc= +cloud.google.com/go/datalabeling v0.8.5/go.mod h1:IABB2lxQnkdUbMnQaOl2prCOfms20mcPxDBm36lps+s= +cloud.google.com/go/dataplex v1.14.2/go.mod h1:0oGOSFlEKef1cQeAHXy4GZPB/Ife0fz/PxBf+ZymA2U= +cloud.google.com/go/dataproc/v2 v2.4.0/go.mod h1:3B1Ht2aRB8VZIteGxQS/iNSJGzt9+CA0WGnDVMEm7Z4= +cloud.google.com/go/dataqna v0.8.5/go.mod h1:vgihg1mz6n7pb5q2YJF7KlXve6tCglInd6XO0JGOlWM= +cloud.google.com/go/datastore v1.15.0/go.mod h1:GAeStMBIt9bPS7jMJA85kgkpsMkvseWWXiaHya9Jes8= +cloud.google.com/go/datastream v1.10.4/go.mod h1:7kRxPdxZxhPg3MFeCSulmAJnil8NJGGvSNdn4p1sRZo= +cloud.google.com/go/deploy v1.17.1/go.mod h1:SXQyfsXrk0fBmgBHRzBjQbZhMfKZ3hMQBw5ym7MN/50= +cloud.google.com/go/dialogflow v1.49.0/go.mod h1:dhVrXKETtdPlpPhE7+2/k4Z8FRNUp6kMV3EW3oz/fe0= +cloud.google.com/go/dlp v1.11.2/go.mod h1:9Czi+8Y/FegpWzgSfkRlyz+jwW6Te9Rv26P3UfU/h/w= +cloud.google.com/go/documentai v1.25.0/go.mod h1:ftLnzw5VcXkLItp6pw1mFic91tMRyfv6hHEY5br4KzY= +cloud.google.com/go/domains v0.9.5/go.mod h1:dBzlxgepazdFhvG7u23XMhmMKBjrkoUNaw0A8AQB55Y= +cloud.google.com/go/edgecontainer v1.1.5/go.mod h1:rgcjrba3DEDEQAidT4yuzaKWTbkTI5zAMu3yy6ZWS0M= +cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= +cloud.google.com/go/essentialcontacts v1.6.6/go.mod h1:XbqHJGaiH0v2UvtuucfOzFXN+rpL/aU5BCZLn4DYl1Q= +cloud.google.com/go/eventarc v1.13.4/go.mod h1:zV5sFVoAa9orc/52Q+OuYUG9xL2IIZTbbuTHC6JSY8s= +cloud.google.com/go/filestore v1.8.1/go.mod h1:MbN9KcaM47DRTIuLfQhJEsjaocVebNtNQhSLhKCF5GM= +cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= +cloud.google.com/go/functions v1.16.0/go.mod h1:nbNpfAG7SG7Duw/o1iZ6ohvL7mc6MapWQVpqtM29n8k= +cloud.google.com/go/gkebackup v1.3.5/go.mod h1:KJ77KkNN7Wm1LdMopOelV6OodM01pMuK2/5Zt1t4Tvc= +cloud.google.com/go/gkeconnect v0.8.5/go.mod h1:LC/rS7+CuJ5fgIbXv8tCD/mdfnlAadTaUufgOkmijuk= +cloud.google.com/go/gkehub v0.14.5/go.mod h1:6bzqxM+a+vEH/h8W8ec4OJl4r36laxTs3A/fMNHJ0wA= +cloud.google.com/go/gkemulticloud v1.1.1/go.mod h1:C+a4vcHlWeEIf45IB5FFR5XGjTeYhF83+AYIpTy4i2Q= +cloud.google.com/go/gsuiteaddons v1.6.5/go.mod h1:Lo4P2IvO8uZ9W+RaC6s1JVxo42vgy+TX5a6hfBZ0ubs= +cloud.google.com/go/iap v1.9.4/go.mod h1:vO4mSq0xNf/Pu6E5paORLASBwEmphXEjgCFg7aeNu1w= +cloud.google.com/go/ids v1.4.5/go.mod h1:p0ZnyzjMWxww6d2DvMGnFwCsSxDJM666Iir1bK1UuBo= +cloud.google.com/go/iot v1.7.5/go.mod h1:nq3/sqTz3HGaWJi1xNiX7F41ThOzpud67vwk0YsSsqs= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/language v1.12.3/go.mod h1:evFX9wECX6mksEva8RbRnr/4wi/vKGYnAJrTRXU8+f8= +cloud.google.com/go/lifesciences v0.9.5/go.mod h1:OdBm0n7C0Osh5yZB7j9BXyrMnTRGBJIZonUMxo5CzPw= +cloud.google.com/go/logging v1.9.0/go.mod h1:1Io0vnZv4onoUnsVUQY3HZ3Igb1nBchky0A0y7BBBhE= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/managedidentities v1.6.5/go.mod h1:fkFI2PwwyRQbjLxlm5bQ8SjtObFMW3ChBGNqaMcgZjI= +cloud.google.com/go/maps v1.6.4/go.mod h1:rhjqRy8NWmDJ53saCfsXQ0LKwBHfi6OSh5wkq6BaMhI= +cloud.google.com/go/mediatranslation v0.8.5/go.mod h1:y7kTHYIPCIfgyLbKncgqouXJtLsU+26hZhHEEy80fSs= +cloud.google.com/go/memcache v1.10.5/go.mod h1:/FcblbNd0FdMsx4natdj+2GWzTq+cjZvMa1I+9QsuMA= +cloud.google.com/go/metastore v1.13.4/go.mod h1:FMv9bvPInEfX9Ac1cVcRXp8EBBQnBcqH6gz3KvJ9BAE= +cloud.google.com/go/monitoring v1.18.0/go.mod h1:c92vVBCeq/OB4Ioyo+NbN2U7tlg5ZH41PZcdvfc+Lcg= +cloud.google.com/go/networkconnectivity v1.14.4/go.mod h1:PU12q++/IMnDJAB+3r+tJtuCXCfwfN+C6Niyj6ji1Po= +cloud.google.com/go/networkmanagement v1.9.4/go.mod h1:daWJAl0KTFytFL7ar33I6R/oNBH8eEOX/rBNHrC/8TA= +cloud.google.com/go/networksecurity v0.9.5/go.mod h1:KNkjH/RsylSGyyZ8wXpue8xpCEK+bTtvof8SBfIhMG8= +cloud.google.com/go/notebooks v1.11.3/go.mod h1:0wQyI2dQC3AZyQqWnRsp+yA+kY4gC7ZIVP4Qg3AQcgo= +cloud.google.com/go/optimization v1.6.3/go.mod h1:8ve3svp3W6NFcAEFr4SfJxrldzhUl4VMUJmhrqVKtYA= +cloud.google.com/go/orchestration v1.8.5/go.mod h1:C1J7HesE96Ba8/hZ71ISTV2UAat0bwN+pi85ky38Yq8= +cloud.google.com/go/orgpolicy v1.12.1/go.mod h1:aibX78RDl5pcK3jA8ysDQCFkVxLj3aOQqrbBaUL2V5I= +cloud.google.com/go/osconfig v1.12.5/go.mod h1:D9QFdxzfjgw3h/+ZaAb5NypM8bhOMqBzgmbhzWViiW8= +cloud.google.com/go/oslogin v1.13.1/go.mod h1:vS8Sr/jR7QvPWpCjNqy6LYZr5Zs1e8ZGW/KPn9gmhws= +cloud.google.com/go/phishingprotection v0.8.5/go.mod h1:g1smd68F7mF1hgQPuYn3z8HDbNre8L6Z0b7XMYFmX7I= +cloud.google.com/go/policytroubleshooter v1.10.3/go.mod h1:+ZqG3agHT7WPb4EBIRqUv4OyIwRTZvsVDHZ8GlZaoxk= +cloud.google.com/go/privatecatalog v0.9.5/go.mod h1:fVWeBOVe7uj2n3kWRGlUQqR/pOd450J9yZoOECcQqJk= +cloud.google.com/go/pubsub v1.36.1/go.mod h1:iYjCa9EzWOoBiTdd4ps7QoMtMln5NwaZQpK1hbRfBDE= +cloud.google.com/go/pubsublite v1.8.1/go.mod h1:fOLdU4f5xldK4RGJrBMm+J7zMWNj/k4PxwEZXy39QS0= +cloud.google.com/go/recaptchaenterprise/v2 v2.9.2/go.mod h1:trwwGkfhCmp05Ll5MSJPXY7yvnO0p4v3orGANAFHAuU= +cloud.google.com/go/recommendationengine v0.8.5/go.mod h1:A38rIXHGFvoPvmy6pZLozr0g59NRNREz4cx7F58HAsQ= +cloud.google.com/go/recommender v1.12.1/go.mod h1:gf95SInWNND5aPas3yjwl0I572dtudMhMIG4ni8nr+0= +cloud.google.com/go/redis v1.14.2/go.mod h1:g0Lu7RRRz46ENdFKQ2EcQZBAJ2PtJHJLuiiRuEXwyQw= +cloud.google.com/go/resourcemanager v1.9.5/go.mod h1:hep6KjelHA+ToEjOfO3garMKi/CLYwTqeAw7YiEI9x8= +cloud.google.com/go/resourcesettings v1.6.5/go.mod h1:WBOIWZraXZOGAgoR4ukNj0o0HiSMO62H9RpFi9WjP9I= +cloud.google.com/go/retail v1.16.0/go.mod h1:LW7tllVveZo4ReWt68VnldZFWJRzsh9np+01J9dYWzE= +cloud.google.com/go/run v1.3.4/go.mod h1:FGieuZvQ3tj1e9GnzXqrMABSuir38AJg5xhiYq+SF3o= +cloud.google.com/go/scheduler v1.10.6/go.mod h1:pe2pNCtJ+R01E06XCDOJs1XvAMbv28ZsQEbqknxGOuE= +cloud.google.com/go/secretmanager v1.11.5/go.mod h1:eAGv+DaCHkeVyQi0BeXgAHOU0RdrMeZIASKc+S7VqH4= +cloud.google.com/go/security v1.15.5/go.mod h1:KS6X2eG3ynWjqcIX976fuToN5juVkF6Ra6c7MPnldtc= +cloud.google.com/go/securitycenter v1.24.4/go.mod h1:PSccin+o1EMYKcFQzz9HMMnZ2r9+7jbc+LvPjXhpwcU= +cloud.google.com/go/servicedirectory v1.11.4/go.mod h1:Bz2T9t+/Ehg6x+Y7Ycq5xiShYLD96NfEsWNHyitj1qM= +cloud.google.com/go/shell v1.7.5/go.mod h1:hL2++7F47/IfpfTO53KYf1EC+F56k3ThfNEXd4zcuiE= +cloud.google.com/go/spanner v1.57.0/go.mod h1:aXQ5QDdhPRIqVhYmnkAdwPYvj/DRN0FguclhEWw+jOo= +cloud.google.com/go/speech v1.21.1/go.mod h1:E5GHZXYQlkqWQwY5xRSLHw2ci5NMQNG52FfMU1aZrIA= +cloud.google.com/go/storagetransfer v1.10.4/go.mod h1:vef30rZKu5HSEf/x1tK3WfWrL0XVoUQN/EPDRGPzjZs= +cloud.google.com/go/talent v1.6.6/go.mod h1:y/WQDKrhVz12WagoarpAIyKKMeKGKHWPoReZ0g8tseQ= +cloud.google.com/go/texttospeech v1.7.5/go.mod h1:tzpCuNWPwrNJnEa4Pu5taALuZL4QRRLcb+K9pbhXT6M= +cloud.google.com/go/tpu v1.6.5/go.mod h1:P9DFOEBIBhuEcZhXi+wPoVy/cji+0ICFi4TtTkMHSSs= +cloud.google.com/go/trace v1.10.5/go.mod h1:9hjCV1nGBCtXbAE4YK7OqJ8pmPYSxPA0I67JwRd5s3M= +cloud.google.com/go/translate v1.10.1/go.mod h1:adGZcQNom/3ogU65N9UXHOnnSvjPwA/jKQUMnsYXOyk= +cloud.google.com/go/video v1.20.4/go.mod h1:LyUVjyW+Bwj7dh3UJnUGZfyqjEto9DnrvTe1f/+QrW0= +cloud.google.com/go/videointelligence v1.11.5/go.mod h1:/PkeQjpRponmOerPeJxNPuxvi12HlW7Em0lJO14FC3I= +cloud.google.com/go/vision/v2 v2.8.0/go.mod h1:ocqDiA2j97pvgogdyhoxiQp2ZkDCyr0HWpicywGGRhU= +cloud.google.com/go/vmmigration v1.7.5/go.mod h1:pkvO6huVnVWzkFioxSghZxIGcsstDvYiVCxQ9ZH3eYI= +cloud.google.com/go/vmwareengine v1.1.1/go.mod h1:nMpdsIVkUrSaX8UvmnBhzVzG7PPvNYc5BszcvIVudYs= +cloud.google.com/go/vpcaccess v1.7.5/go.mod h1:slc5ZRvvjP78c2dnL7m4l4R9GwL3wDLcpIWz6P/ziig= +cloud.google.com/go/webrisk v1.9.5/go.mod h1:aako0Fzep1Q714cPEM5E+mtYX8/jsfegAuS8aivxy3U= +cloud.google.com/go/websecurityscanner v1.6.5/go.mod h1:QR+DWaxAz2pWooylsBF854/Ijvuoa3FCyS1zBa1rAVQ= +cloud.google.com/go/workflows v1.12.4/go.mod h1:yQ7HUqOkdJK4duVtMeBCAOPiN1ZF1E9pAMX51vpwB/w= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= +github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20190129172621-c8b1d7a94ddf/go.mod h1:aJ4qN3TfrelA6NZ6AXsXRfmEVaYin3EDbSPJrKS8OXo= +github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= +github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= +github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= +github.com/aclements/go-gg v0.0.0-20170118225347-6dbb4e4fefb0/go.mod h1:55qNq4vcpkIuHowELi5C8e+1yUHtoLoOUR9QU5j7Tes= +github.com/aclements/go-moremath v0.0.0-20210112150236-f10218a38794/go.mod h1:7e+I0LQFUI9AXWxOfsQROs9xPhoJtbsyWcjJqDd4KPY= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/ajstarks/svgo v0.0.0-20210923152817-c3b6e2f0c527/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/cockroachdb/datadriven v1.0.0/go.mod h1:5Ib8Meh+jk1RlHIXej6Pzevx/NLlNvQB9pmSBZErGA4= +github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= +github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM= +github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/cockroachdb/pebble v0.0.0-20220817183557-09c6e030a677/go.mod h1:890yq1fUb9b6dGNwssgeUO5vQV9qfXnCPxAJhBQfXw0= +github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/djherbis/atime v1.1.0/go.mod h1:28OF6Y8s3NQWwacXc5eZTsEsiMzp7LF8MbXE+XJPdBE= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA= +github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ= +github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= +github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= +github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= +github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= +github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gogo/googleapis v0.0.0-20180223154316-0cd9801be74a/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/status v1.1.0/go.mod h1:BFv9nrluPLmrS0EmGVvLaPNmRosr9KapBYd5/hpY1WM= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac/go.mod h1:P32wAyui1PQ58Oce/KYkOqQv8cVw1zAapXOl+dRFGbc= +github.com/gonum/floats v0.0.0-20181209220543-c233463c7e82/go.mod h1:PxC8OnwL11+aosOB5+iEPoV3picfs8tUpkVd0pDo+Kg= +github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhSyOzRwuXkOgAvijx4o+4YMUJJo9OvPYMkks= +github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2EAE789SSiSJNqxPaC0aE9J8NTOI0Jo/A= +github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/safehtml v0.0.2/go.mod h1:L4KWwDsUJdECRAEpZoBn3O64bQaywRscowZjJAzjHnU= +github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e h1:CYRpN206UTHUinz3VJoLaBdy1gEGeJNsqT0mvswDcMw= +github.com/googleapis/gax-go v0.0.0-20161107002406-da06d194a00e/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= +github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/hydrogen18/memlistener v1.0.0/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/initia-labs/initia v0.3.4 h1:i2fwTx9WDwGp2nyX64r6jtdtgfJmRqKAXGdxbHBRg9s= +github.com/initia-labs/initia v0.3.4/go.mod h1:nwtnVe3obacErGb7w6tq8Ych3U0d2f59rsgpVUeMnmM= +github.com/initia-labs/movevm v0.3.4 h1:kzqs6uzTq0f5peZJNzLq/1qgnmAFfC+I9eCyPBducxM= +github.com/initia-labs/movevm v0.3.4/go.mod h1:6MxR4GP5zH3JUc1IMgfqAe1e483mZVS7fshPknZPJ30= +github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI= +github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q= +github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U= +github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I= +github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk= +github.com/kataras/golog v0.1.8/go.mod h1:rGPAin4hYROfk1qT9wZP6VY2rsb4zzc37QpdPjdkqVw= +github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U= +github.com/kataras/iris/v12 v12.2.0/go.mod h1:BLzBpEunc41GbE68OUaQlqX4jzi791mx5HU04uPb90Y= +github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw= +github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0= +github.com/kataras/pio v0.0.11/go.mod h1:38hH6SWH6m4DKSYmRhlrCJ5WItwWgCVrTNU62XZyUvI= +github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4= +github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw= +github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= +github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/echo/v4 v4.10.0/go.mod h1:S/T/5fy/GigaXnHTkh0ZGe4LpkkQysvRjFMSUTkDRNQ= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/linxGnu/grocksdb v1.7.15/go.mod h1:pY55D0o+r8yUYLq70QmhdudxYvoDb9F+9puf4m3/W+U= +github.com/linxGnu/grocksdb v1.8.12/go.mod h1:xZCIb5Muw+nhbDK4Y5UJuOrin5MceOuiXkVUR7vp4WY= +github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg= +github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ= +github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= +github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= +github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/tdewolff/minify/v2 v2.12.4/go.mod h1:h+SRvSIX3kwgwTFOpSckvSxgax3uy8kZTSF1Ojrr3bk= +github.com/tdewolff/parse/v2 v2.6.4/go.mod h1:woz0cgbLwFdtbjJu8PIKxhW05KplTFQkOdX78o+Jgrs= +github.com/tdewolff/test v1.0.7/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= +golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/oauth2 v0.0.0-20170207211851-4464e7848382/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/perf v0.0.0-20230113213139-801c7ef9e5c5/go.mod h1:UBKtEnL8aqnd+0JHqZ+2qoMDwtuy6cYhhKNoHLBiTQc= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= +gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= +gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ= +google.golang.org/api v0.0.0-20170206182103-3d017632ea10/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/genproto v0.0.0-20180518175338-11a468237815/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20230227214838-9b19f0bdc514/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= +google.golang.org/genproto v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= +google.golang.org/genproto/googleapis/api v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:PVreiBMirk8ypES6aw9d4p6iiBNSIfZEBqr3UGoAi2E= +google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/grpc v0.0.0-20170208002647-2a6bf6142e96/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.12.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= +google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/indexer/abci.go b/indexer/abci.go new file mode 100644 index 0000000..f9ebcf1 --- /dev/null +++ b/indexer/abci.go @@ -0,0 +1,155 @@ +package indexer + +import ( + "context" + "math/big" + + abci "github.com/cometbft/cometbft/abci/types" + + "cosmossdk.io/collections" + storetypes "cosmossdk.io/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/trie" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + "github.com/initia-labs/minievm/x/evm/keeper" + "github.com/initia-labs/minievm/x/evm/types" +) + +func (e *EVMIndexerImpl) ListenCommit(ctx context.Context, res abci.ResponseCommit, changeSet []*storetypes.StoreKVPair) error { + e.store.Write() + return nil +} + +// IndexBlock implements EVMIndexer. +func (e *EVMIndexerImpl) ListenFinalizeBlock(ctx context.Context, req abci.RequestFinalizeBlock, res abci.ResponseFinalizeBlock) error { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + batch := e.db.NewBatch() + defer batch.Close() + + txIndex := uint(0) + usedGas := uint64(0) + ethTxs := make([]*coretypes.Transaction, 0, len(req.Txs)) + receipts := make([]*coretypes.Receipt, 0, len(req.Txs)) + for idx, txBytes := range req.Txs { + tx, err := e.txConfig.TxDecoder()(txBytes) + if err != nil { + e.logger.Error("failed to decode tx", "err", err) + continue + } + + ethTx, _, err := keeper.NewTxUtils(e.evmKeeper).ConvertCosmosTxToEthereumTx(sdkCtx, tx) + if err != nil { + e.logger.Error("failed to convert CosmosTx to EthTx", "err", err) + return err + } + if ethTx == nil { + continue + } + + txIndex++ + usedGas += ethTx.Gas() + + txResults := res.TxResults[idx] + txStatus := coretypes.ReceiptStatusSuccessful + if txResults.Code != abci.CodeTypeOK { + txStatus = coretypes.ReceiptStatusFailed + } + + ethTxs = append(ethTxs, ethTx) + ethLogs := e.extractLogsFromEvents(txResults.Events) + receipts = append(receipts, &coretypes.Receipt{ + PostState: nil, + Status: txStatus, + CumulativeGasUsed: usedGas, + Bloom: coretypes.Bloom(coretypes.LogsBloom(ethLogs)), + Logs: ethLogs, + TransactionIndex: txIndex, + }) + } + + chainId := types.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID()) + blockGasMeter := sdkCtx.BlockGasMeter() + blockHeight := sdkCtx.BlockHeight() + + hasher := trie.NewStackTrie(nil) + blockHeader := coretypes.Header{ + TxHash: coretypes.DeriveSha(coretypes.Transactions(ethTxs), hasher), + ReceiptHash: coretypes.DeriveSha(coretypes.Receipts(receipts), hasher), + Bloom: coretypes.CreateBloom(receipts), + GasLimit: blockGasMeter.Limit(), + GasUsed: blockGasMeter.GasConsumedToLimit(), + Number: big.NewInt(blockHeight), + Time: uint64(sdkCtx.BlockTime().Unix()), + + // empty values + Root: coretypes.EmptyRootHash, + UncleHash: coretypes.EmptyUncleHash, + WithdrawalsHash: &coretypes.EmptyWithdrawalsHash, + ParentHash: common.Hash{}, + MixDigest: common.Hash{}, + Difficulty: big.NewInt(0), + Nonce: coretypes.EncodeNonce(0), + Coinbase: common.Address{}, + Extra: []byte{}, + } + + blockHash := blockHeader.Hash() + for txIndex, ethTx := range ethTxs { + txHash := ethTx.Hash() + receipt := receipts[txIndex] + + // store tx + rpcTx := rpctypes.NewRPCTransaction(ethTx, blockHash, uint64(blockHeight), uint64(receipt.TransactionIndex), chainId) + if err := e.TxMap.Set(ctx, txHash.Bytes(), *rpcTx); err != nil { + e.logger.Error("failed to store rpcTx", "err", err) + return err + } + if err := e.TxReceiptMap.Set(ctx, txHash.Bytes(), *receipt); err != nil { + e.logger.Error("failed to store tx receipt", "err", err) + return err + } + + // store index + if err := e.BlockAndIndexToTxHashMap.Set(ctx, collections.Join(uint64(blockHeight), uint64(receipt.TransactionIndex)), txHash.Bytes()); err != nil { + e.logger.Error("failed to store blockAndIndexToTxHash", "err", err) + return err + } + + // emit log events + if e.logsChan != nil { + for idx, log := range receipt.Logs { + // fill in missing fields before emitting + log.Index = uint(idx) + log.BlockHash = blockHash + log.BlockNumber = uint64(blockHeight) + log.TxHash = txHash + log.TxIndex = uint(txIndex) + } + + // emit logs event + e.logsChan <- receipt.Logs + } + } + + // index block header + if err := e.BlockHeaderMap.Set(ctx, uint64(blockHeight), blockHeader); err != nil { + e.logger.Error("failed to marshal blockHeader", "err", err) + return err + } + if err := e.BlockHashToNumberMap.Set(ctx, blockHash.Bytes(), uint64(blockHeight)); err != nil { + e.logger.Error("failed to store blockHashToNumber", "err", err) + return err + } + + // emit new block events + if e.blockChan != nil { + e.blockChan <- &blockHeader + } + + return nil +} diff --git a/indexer/indexer.go b/indexer/indexer.go new file mode 100644 index 0000000..e9a2dd9 --- /dev/null +++ b/indexer/indexer.go @@ -0,0 +1,117 @@ +package indexer + +import ( + "context" + + "cosmossdk.io/collections" + corestoretypes "cosmossdk.io/core/store" + "cosmossdk.io/log" + "cosmossdk.io/store/dbadapter" + storetypes "cosmossdk.io/store/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/types/mempool" + + "github.com/ethereum/go-ethereum/common" + coretypes "github.com/ethereum/go-ethereum/core/types" + + "github.com/initia-labs/kvindexer/store" + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" +) + +// EVMIndexer is an interface to interact with the EVM indexer. +type EVMIndexer interface { + storetypes.ABCIListener + + // tx + TxByHash(ctx context.Context, hash common.Hash) (*rpctypes.RPCTransaction, error) + TxByBlockAndIndex(ctx context.Context, blockHeight uint64, index uint64) (*rpctypes.RPCTransaction, error) + IterateBlockTxs(ctx context.Context, blockHeight uint64, cb func(tx *rpctypes.RPCTransaction) (bool, error)) error + + // tx receipt + TxReceiptByHash(ctx context.Context, hash common.Hash) (*coretypes.Receipt, error) + + // block + BlockHashToNumber(ctx context.Context, hash common.Hash) (uint64, error) + BlockHeaderByHash(ctx context.Context, hash common.Hash) (*coretypes.Header, error) + BlockHeaderByNumber(ctx context.Context, number uint64) (*coretypes.Header, error) + + // event subscription + Subscribe() (chan *coretypes.Header, chan []*coretypes.Log, chan *rpctypes.RPCTransaction) + MempoolWrapper(mempool mempool.Mempool) mempool.Mempool +} + +// EVMIndexerImpl implements EVMIndexer. +type EVMIndexerImpl struct { + db dbm.DB + logger log.Logger + txConfig client.TxConfig + appCodec codec.Codec + + evmKeeper *evmkeeper.Keeper + store *store.CacheStore + + schema collections.Schema + TxMap collections.Map[[]byte, rpctypes.RPCTransaction] + TxReceiptMap collections.Map[[]byte, coretypes.Receipt] + BlockHeaderMap collections.Map[uint64, coretypes.Header] + BlockAndIndexToTxHashMap collections.Map[collections.Pair[uint64, uint64], []byte] + BlockHashToNumberMap collections.Map[[]byte, uint64] + + blockChan chan *coretypes.Header + logsChan chan []*coretypes.Log + pendingChan chan *rpctypes.RPCTransaction +} + +func NewEVMIndexer( + db dbm.DB, + appCodec codec.Codec, + logger log.Logger, + txConfig client.TxConfig, + evmKeeper *evmkeeper.Keeper, +) (EVMIndexer, error) { + // TODO make cache size configurable + store := store.NewCacheStore(dbadapter.Store{DB: db}, 100) + sb := collections.NewSchemaBuilderFromAccessor( + func(ctx context.Context) corestoretypes.KVStore { + return store + }, + ) + + indexer := &EVMIndexerImpl{ + db: db, + store: store, + logger: logger, + txConfig: txConfig, + appCodec: appCodec, + evmKeeper: evmKeeper, + + TxMap: collections.NewMap(sb, prefixTx, "tx", collections.BytesKey, CollJsonVal[rpctypes.RPCTransaction]()), + TxReceiptMap: collections.NewMap(sb, prefixTxReceipt, "tx_receipt", collections.BytesKey, CollJsonVal[coretypes.Receipt]()), + BlockHeaderMap: collections.NewMap(sb, prefixBlockHeader, "block_header", collections.Uint64Key, CollJsonVal[coretypes.Header]()), + BlockAndIndexToTxHashMap: collections.NewMap(sb, prefixBlockAndIndexToTxHash, "block_and_index_to_tx_hash", collections.PairKeyCodec(collections.Uint64Key, collections.Uint64Key), collections.BytesValue), + BlockHashToNumberMap: collections.NewMap(sb, prefixBlockHashToNumber, "block_hash_to_number", collections.BytesKey, collections.Uint64Value), + + blockChan: nil, + logsChan: nil, + pendingChan: nil, + } + + schema, err := sb.Build() + if err != nil { + return nil, err + } + indexer.schema = schema + + return indexer, nil +} + +// Subscribe returns channels to receive blocks and logs. +func (e *EVMIndexerImpl) Subscribe() (chan *coretypes.Header, chan []*coretypes.Log, chan *rpctypes.RPCTransaction) { + e.blockChan = make(chan *coretypes.Header) + e.logsChan = make(chan []*coretypes.Log) + e.pendingChan = make(chan *rpctypes.RPCTransaction) + return e.blockChan, e.logsChan, e.pendingChan +} diff --git a/indexer/keys.go b/indexer/keys.go new file mode 100644 index 0000000..dc01022 --- /dev/null +++ b/indexer/keys.go @@ -0,0 +1,16 @@ +package indexer + +import ( + "cosmossdk.io/collections" +) + +var ( + // block indexes + prefixBlockHeader = collections.Prefix([]byte{0, 0, 1, 1}) + prefixBlockHashToNumber = collections.Prefix([]byte{0, 0, 1, 2}) + + // tx indexes + prefixTx = collections.Prefix([]byte{0, 0, 2, 1}) + prefixTxReceipt = collections.Prefix([]byte{0, 0, 2, 2}) + prefixBlockAndIndexToTxHash = collections.Prefix([]byte{0, 0, 2, 3}) +) diff --git a/indexer/mempool.go b/indexer/mempool.go new file mode 100644 index 0000000..4dee721 --- /dev/null +++ b/indexer/mempool.go @@ -0,0 +1,61 @@ +package indexer + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" + "github.com/ethereum/go-ethereum/common" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + evmkeeper "github.com/initia-labs/minievm/x/evm/keeper" + evmtypes "github.com/initia-labs/minievm/x/evm/types" +) + +var _ mempool.Mempool = (*MempoolWrapper)(nil) + +type MempoolWrapper struct { + mempool mempool.Mempool + indexer *EVMIndexerImpl +} + +func (indexer *EVMIndexerImpl) MempoolWrapper(mempool mempool.Mempool) mempool.Mempool { + return &MempoolWrapper{mempool: mempool, indexer: indexer} +} + +// CountTx implements mempool.Mempool. +func (m *MempoolWrapper) CountTx() int { + return m.mempool.CountTx() +} + +// Insert implements mempool.Mempool. +func (m *MempoolWrapper) Insert(ctx context.Context, tx sdk.Tx) error { + if m.indexer.pendingChan != nil { + txUtils := evmkeeper.NewTxUtils(m.indexer.evmKeeper) + ethTx, _, err := txUtils.ConvertCosmosTxToEthereumTx(ctx, tx) + if err != nil { + m.indexer.logger.Error("failed to convert CosmosTx to EthTx", "err", err) + return err + } + + if ethTx != nil { + sdkCtx := sdk.UnwrapSDKContext(ctx) + chainId := evmtypes.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID()) + rpcTx := rpctypes.NewRPCTransaction(ethTx, common.Hash{}, 0, 0, chainId) + + m.indexer.pendingChan <- rpcTx + } + } + + return m.mempool.Insert(ctx, tx) +} + +// Remove implements mempool.Mempool. +func (m *MempoolWrapper) Remove(tx sdk.Tx) error { + return m.mempool.Remove(tx) +} + +// Select implements mempool.Mempool. +func (m *MempoolWrapper) Select(ctx context.Context, txs [][]byte) mempool.Iterator { + return m.mempool.Select(ctx, txs) +} diff --git a/indexer/reader.go b/indexer/reader.go new file mode 100644 index 0000000..4b1fb53 --- /dev/null +++ b/indexer/reader.go @@ -0,0 +1,75 @@ +package indexer + +import ( + "context" + + "cosmossdk.io/collections" + "github.com/ethereum/go-ethereum/common" + coretypes "github.com/ethereum/go-ethereum/core/types" + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" +) + +// BlockHeaderByHash implements EVMIndexer. +func (e *EVMIndexerImpl) BlockHeaderByHash(ctx context.Context, hash common.Hash) (*coretypes.Header, error) { + blockNumber, err := e.BlockHashToNumberMap.Get(ctx, hash.Bytes()) + if err != nil { + return nil, err + } + + return e.BlockHeaderByNumber(ctx, blockNumber) +} + +// BlockHeaderByNumber implements EVMIndexer. +func (e *EVMIndexerImpl) BlockHeaderByNumber(ctx context.Context, blockNumber uint64) (*coretypes.Header, error) { + blockHeader, err := e.BlockHeaderMap.Get(ctx, blockNumber) + if err != nil { + return nil, err + } + + return &blockHeader, nil +} + +// TxByBlockAndIndex implements EVMIndexer. +func (e *EVMIndexerImpl) TxByBlockAndIndex(ctx context.Context, blockHeight uint64, index uint64) (*rpctypes.RPCTransaction, error) { + txHashBz, err := e.BlockAndIndexToTxHashMap.Get(ctx, collections.Join(blockHeight, index)) + if err != nil { + return nil, err + } + + txHash := common.BytesToHash(txHashBz) + return e.TxByHash(ctx, txHash) +} + +// TxByHash implements EVMIndexer. +func (e *EVMIndexerImpl) TxByHash(ctx context.Context, hash common.Hash) (*rpctypes.RPCTransaction, error) { + tx, err := e.TxMap.Get(ctx, hash.Bytes()) + if err != nil { + return nil, err + } + + return &tx, nil +} + +// IterateBlockTxs implements EVMIndexer. +func (e *EVMIndexerImpl) IterateBlockTxs(ctx context.Context, blockHeight uint64, cb func(tx *rpctypes.RPCTransaction) (bool, error)) error { + return e.BlockAndIndexToTxHashMap.Walk(ctx, collections.NewPrefixedPairRange[uint64, uint64](blockHeight), func(key collections.Pair[uint64, uint64], txHashBz []byte) (bool, error) { + txHash := common.BytesToHash(txHashBz) + tx, err := e.TxByHash(ctx, txHash) + if err != nil { + return true, err + } + + return cb(tx) + }) +} + +// TxReceiptByHash implements EVMIndexer. +func (e *EVMIndexerImpl) TxReceiptByHash(ctx context.Context, hash common.Hash) (*coretypes.Receipt, error) { + receipt, err := e.TxReceiptMap.Get(ctx, hash.Bytes()) + return &receipt, err +} + +// BlockHashToNumber implements EVMIndexer. +func (e *EVMIndexerImpl) BlockHashToNumber(ctx context.Context, hash common.Hash) (uint64, error) { + return e.BlockHashToNumberMap.Get(ctx, hash.Bytes()) +} diff --git a/indexer/utils.go b/indexer/utils.go new file mode 100644 index 0000000..82f5894 --- /dev/null +++ b/indexer/utils.go @@ -0,0 +1,102 @@ +package indexer + +import ( + "encoding/json" + "fmt" + "path/filepath" + + "github.com/spf13/cast" + + abci "github.com/cometbft/cometbft/abci/types" + + collcodec "cosmossdk.io/collections/codec" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/server" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + + coretypes "github.com/ethereum/go-ethereum/core/types" + + "github.com/initia-labs/minievm/x/evm/types" +) + +// helper function to make config creation independent of root dir +func rootify(path, root string) string { + if filepath.IsAbs(path) { + return path + } + return filepath.Join(root, path) +} + +// getDBConfig returns the database configuration for the EVM indexer +func getDBConfig(appOpts servertypes.AppOptions) (string, dbm.BackendType) { + rootDir := cast.ToString(appOpts.Get("home")) + dbDir := cast.ToString(appOpts.Get("db_dir")) + dbBackend := server.GetAppDBBackend(appOpts) + + return rootify(dbDir, rootDir), dbBackend +} + +// extractLogsFromEvents extracts logs from the events +func (e *EVMIndexerImpl) extractLogsFromEvents(events []abci.Event) []*coretypes.Log { + var ethLogs []*coretypes.Log + for _, event := range events { + if event.Type == types.EventTypeEVM { + logs := make(types.Logs, 0, len(event.Attributes)) + + for _, attr := range event.Attributes { + if attr.Key == types.AttributeKeyLog { + var log types.Log + err := json.Unmarshal([]byte(attr.Value), &log) + if err != nil { + e.logger.Error("failed to unmarshal log", "err", err) + continue + } + + logs = append(logs, log) + } + } + + ethLogs = logs.ToEthLogs() + break + } + } + + return ethLogs +} + +// CollJsonVal is used for protobuf values of the newest google.golang.org/protobuf API. +func CollJsonVal[T any]() collcodec.ValueCodec[T] { + return &collJsonVal[T]{} +} + +type collJsonVal[T any] struct{} + +func (c collJsonVal[T]) Encode(value T) ([]byte, error) { + return json.Marshal(value) +} + +func (c collJsonVal[T]) Decode(b []byte) (T, error) { + var value T + + err := json.Unmarshal(b, &value) + return value, err +} + +func (c collJsonVal[T]) EncodeJSON(value T) ([]byte, error) { + return json.Marshal(value) +} + +func (c collJsonVal[T]) DecodeJSON(b []byte) (T, error) { + var value T + + err := json.Unmarshal(b, &value) + return value, err +} + +func (c collJsonVal[T]) Stringify(value T) string { + return fmt.Sprintf("%v", value) +} + +func (c collJsonVal[T]) ValueType() string { + return "jsonvalue" +} diff --git a/integration-tests/erc721_transfer_test.go b/integration-tests/erc721_transfer_test.go index ee8e787..8cb3f80 100644 --- a/integration-tests/erc721_transfer_test.go +++ b/integration-tests/erc721_transfer_test.go @@ -136,7 +136,7 @@ func (suite *KeeperTestSuite) CreateNftClass( inputBz, err := nftKeeper.ABI.Pack("", name, name) suite.Require().NoError(err) - _, contractAddr, err := evmKeeper.EVMCreate(ctx, createAccountAddr, append(nftKeeper.ERC721Bin, inputBz...)) + _, contractAddr, _, err := evmKeeper.EVMCreate(ctx, createAccountAddr, append(nftKeeper.ERC721Bin, inputBz...), nil) suite.Require().NoError(err) classId, err := evmtypes.ClassIdFromCollectionAddress(endpoint.Chain.GetContext(), nftKeeper, contractAddr) @@ -167,7 +167,7 @@ func (suite *KeeperTestSuite) MintNft( contractAddr, err := types.ContractAddressFromClassId(ctx, nftKeeper, classId) suite.Require().NoError(err) - _, _, err = nftKeeper.EVMCall(ctx, createAccountAddr, contractAddr, inputBz) + _, _, err = nftKeeper.EVMCall(ctx, createAccountAddr, contractAddr, inputBz, nil) suite.Require().NoError(err) } diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 5bc6c31..cca0adb 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -10,7 +10,7 @@ require ( github.com/cosmos/cosmos-sdk v0.50.7 github.com/cosmos/ibc-go/v8 v8.2.1 github.com/ethereum/go-ethereum v1.14.2 - github.com/initia-labs/initia v0.3.3 + github.com/initia-labs/initia v0.3.4 github.com/initia-labs/minievm v0.3.0 github.com/stretchr/testify v1.9.0 ) @@ -149,7 +149,7 @@ require ( github.com/initia-labs/kvindexer/submodules/block v0.1.0 // indirect github.com/initia-labs/kvindexer/submodules/pair v0.1.1 // indirect github.com/initia-labs/kvindexer/submodules/tx v0.1.0 // indirect - github.com/initia-labs/movevm v0.3.3 // indirect + github.com/initia-labs/movevm v0.3.4 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.8 // indirect @@ -269,8 +269,7 @@ replace ( // initia custom replace ( - github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680 - github.com/cosmos/cosmos-sdk => github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501 + github.com/cometbft/cometbft => github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c github.com/cosmos/ibc-go/v8 => github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c github.com/ethereum/go-ethereum => github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 703ac96..ccf54ee 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -377,6 +377,8 @@ github.com/cosmos/cosmos-db v1.0.2 h1:hwMjozuY1OlJs/uh6vddqnk9j7VamLv+0DBlbEXbAK github.com/cosmos/cosmos-db v1.0.2/go.mod h1:Z8IXcFJ9PqKK6BIsVOB3QXtkKoqUOp1vRvPT39kOXEA= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= +github.com/cosmos/cosmos-sdk v0.50.7 h1:LsBGKxifENR/DN4E1RZaitsyL93HU44x0p8EnMHp4V4= +github.com/cosmos/cosmos-sdk v0.50.7/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= @@ -774,16 +776,14 @@ github.com/initia-labs/OPinit v0.3.2 h1:TeELD5GeSJJ9meY5b5YIXDdmCZt9kZOA2Chz+Iwx github.com/initia-labs/OPinit v0.3.2/go.mod h1:XlYsBFAKOFS6/wRIHB1vVbfonqX8QrC8cWK2GJvmX20= github.com/initia-labs/OPinit/api v0.3.0 h1:OY8ijwmgZLoYwtw9LI1mSY3VC8PY+gtxJFitB6ZNFl4= github.com/initia-labs/OPinit/api v0.3.0/go.mod h1:Xy/Nt3ubXLQ4zKn0m7RuQOM1sj8TVdlNNyek21TGYR0= -github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680 h1:4tcP5F26DdqiV1Y/XOllL4LUhyUV6HITfjVJnzR/Krs= -github.com/initia-labs/cometbft v0.0.0-20240621094738-408dc5262680/go.mod h1:qGaJePRWAc2OL3OGNd//8fqgypCaFjmwZcy/cNner84= -github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501 h1:OcLFeu3V9T156H4n6WzPNfKWjIUKdkC0P0EBA8zEWFE= -github.com/initia-labs/cosmos-sdk v0.0.0-20240627065534-d2180fcfd501/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= +github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c h1:+icq583vNtAB5miQ+XAuTLqjzXyznRd/kc+ucHcmBXI= +github.com/initia-labs/cometbft v0.0.0-20240704071917-6c77a401128c/go.mod h1:qGaJePRWAc2OL3OGNd//8fqgypCaFjmwZcy/cNner84= github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7 h1:V7K8wvE5FVVv6WTeITI+nqWfo4b9WlZyXQH0Olz5UVI= github.com/initia-labs/evm v0.0.0-20240620024053-f13ebda716b7/go.mod h1:x2gtBG0WHLgY08FE97lfhjtpcR5vcSAZbi34JnrsBbQ= github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c h1:FDwh5zZbm9v7C37ni4FytQQ9Os5XxYp1px5U7Nqdu2Y= github.com/initia-labs/ibc-go/v8 v8.0.0-20240419124350-4275a05abe2c/go.mod h1:wj3qx75iC/XNnsMqbPDCIGs0G6Y3E/lo3bdqCyoCy+8= -github.com/initia-labs/initia v0.3.3 h1:82ZkXki6CG+F+rPDBVpTzzSQY8NalXIZ0LnYSWNd+3U= -github.com/initia-labs/initia v0.3.3/go.mod h1:1yWifo9GnhIvwDtCTTN6kb2mfq2On+oel6ha/rBXaQQ= +github.com/initia-labs/initia v0.3.4 h1:i2fwTx9WDwGp2nyX64r6jtdtgfJmRqKAXGdxbHBRg9s= +github.com/initia-labs/initia v0.3.4/go.mod h1:nwtnVe3obacErGb7w6tq8Ych3U0d2f59rsgpVUeMnmM= github.com/initia-labs/kvindexer v0.1.3 h1:TLkgJjp5TiPnH+OzYfk7ZKQTKqGOfSte59Y3gasob+o= github.com/initia-labs/kvindexer v0.1.3/go.mod h1:rvAmgCAmEs4KM8sRRPcyTqNNwi8s2JiHybiFkYfp4KE= github.com/initia-labs/kvindexer/submodules/block v0.1.0 h1:y+EXnksd/I2F96mzIoQA64nZUZON2P+99YrSzeLCLoY= @@ -792,8 +792,8 @@ github.com/initia-labs/kvindexer/submodules/pair v0.1.1 h1:o151gA4jIbqEl+pWTOCiz github.com/initia-labs/kvindexer/submodules/pair v0.1.1/go.mod h1:8X1GE1ZLkH7z8TKb5MUh7UClTkcqVFIwXIIRdsqeUZY= github.com/initia-labs/kvindexer/submodules/tx v0.1.0 h1:6kbf6wmzXPN0XCQLasiFgq1AlZHkt5K3/ZG+IWw1nNs= github.com/initia-labs/kvindexer/submodules/tx v0.1.0/go.mod h1:i0XeLbLa6xdgTR01WF8kaAO50vMmwxbeq0fKexwpFHU= -github.com/initia-labs/movevm v0.3.3 h1:xUH5VvjBSfJP4jg3axefmBlcdZ/7qfVYnUU09R4oN4g= -github.com/initia-labs/movevm v0.3.3/go.mod h1:6MxR4GP5zH3JUc1IMgfqAe1e483mZVS7fshPknZPJ30= +github.com/initia-labs/movevm v0.3.4 h1:kzqs6uzTq0f5peZJNzLq/1qgnmAFfC+I9eCyPBducxM= +github.com/initia-labs/movevm v0.3.4/go.mod h1:6MxR4GP5zH3JUc1IMgfqAe1e483mZVS7fshPknZPJ30= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls= diff --git a/jsonrpc/backend/backend.go b/jsonrpc/backend/backend.go new file mode 100644 index 0000000..a7aaf82 --- /dev/null +++ b/jsonrpc/backend/backend.go @@ -0,0 +1,33 @@ +package backend + +import ( + "context" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/server" + + "github.com/initia-labs/minievm/app" + "github.com/initia-labs/minievm/jsonrpc/config" +) + +type JSONRPCBackend struct { + app *app.MinitiaApp + svrCtx *server.Context + clientCtx client.Context + cfg config.JSONRPCConfig + + ctx context.Context +} + +// NewJSONRPCBackend creates a new JSONRPCBackend instance +func NewJSONRPCBackend( + app *app.MinitiaApp, + svrCtx *server.Context, + clientCtx client.Context, + cfg config.JSONRPCConfig, +) *JSONRPCBackend { + ctx := context.Background() + return &JSONRPCBackend{ + app, svrCtx, clientCtx, cfg, ctx, + } +} diff --git a/jsonrpc/backend/block.go b/jsonrpc/backend/block.go new file mode 100644 index 0000000..8dcf480 --- /dev/null +++ b/jsonrpc/backend/block.go @@ -0,0 +1,189 @@ +package backend + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" +) + +func (b *JSONRPCBackend) BlockNumber() (hexutil.Uint64, error) { + res, err := b.clientCtx.Client.Status(b.ctx) + if err != nil { + return 0, err + } + + return hexutil.Uint64(res.SyncInfo.LatestBlockHeight), nil +} + +func (b *JSONRPCBackend) resolveBlockNrOrHash(blockNrOrHash rpc.BlockNumberOrHash) (uint64, error) { + if blockHash, ok := blockNrOrHash.Hash(); ok { + queryCtx, err := b.getQueryCtx() + if err != nil { + return 0, err + } + + return b.app.EVMIndexer().BlockHashToNumber(queryCtx, blockHash) + } else if blockNumber, ok := blockNrOrHash.Number(); !ok || blockNumber < 0 { + num, err := b.BlockNumber() + if err != nil { + return 0, err + } + + return uint64(num), nil + } else if blockNumber == 0 { + return uint64(1), nil + } else { + return uint64(blockNumber), nil + } +} + +func (b *JSONRPCBackend) resolveBlockNr(blockNr rpc.BlockNumber) (uint64, error) { + if blockNr < rpc.BlockNumber(0) { + num, err := b.BlockNumber() + if err != nil { + return 0, err + } + + return uint64(num), nil + } else if blockNr == rpc.BlockNumber(0) { + return uint64(1), nil + } else { + return uint64(blockNr), nil + } +} + +func (b *JSONRPCBackend) GetHeaderByNumber(ethBlockNum rpc.BlockNumber) (*coretypes.Header, error) { + blockNumber, err := b.resolveBlockNr(ethBlockNum) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + header, err := b.app.EVMIndexer().BlockHeaderByNumber(queryCtx, blockNumber) + if err != nil { + return nil, err + } + + return header, nil +} + +func (b *JSONRPCBackend) GetHeaderByHash(hash common.Hash) (*coretypes.Header, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + header, err := b.app.EVMIndexer().BlockHeaderByHash(queryCtx, hash) + if err != nil { + return nil, err + } + + return header, nil +} + +func (b *JSONRPCBackend) GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + blockNumber, err := b.resolveBlockNr(ethBlockNum) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + header, err := b.app.EVMIndexer().BlockHeaderByNumber(queryCtx, blockNumber) + if err != nil { + return nil, err + } + + txs := []*rpctypes.RPCTransaction{} + if fullTx { + b.app.EVMIndexer().IterateBlockTxs(queryCtx, blockNumber, func(tx *rpctypes.RPCTransaction) (bool, error) { + txs = append(txs, tx) + return false, nil + }) + } + + return formatBlock(header, txs), nil +} + +func (b *JSONRPCBackend) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + header, err := b.app.EVMIndexer().BlockHeaderByHash(queryCtx, hash) + if err != nil { + return nil, err + } + + txs := []*rpctypes.RPCTransaction{} + if fullTx { + blockNumber := header.Number.Uint64() + b.app.EVMIndexer().IterateBlockTxs(queryCtx, blockNumber, func(tx *rpctypes.RPCTransaction) (bool, error) { + txs = append(txs, tx) + return false, nil + }) + } + + return formatBlock(header, txs), nil +} + +func formatBlock(header *coretypes.Header, txs []*rpctypes.RPCTransaction) map[string]interface{} { + fields := formatHeader(header) + fields["transactions"] = txs + + // empty values + fields["size"] = hexutil.Uint64(0) + fields["uncles"] = []common.Hash{} + fields["withdrawals"] = coretypes.Withdrawals{} + + return fields +} + +// formatHeader converts the given header to the RPC output . +func formatHeader(head *coretypes.Header) map[string]interface{} { + result := map[string]interface{}{ + "number": (*hexutil.Big)(head.Number), + "hash": head.Hash(), + "parentHash": head.ParentHash, + "nonce": head.Nonce, + "mixHash": head.MixDigest, + "sha3Uncles": head.UncleHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": (*hexutil.Big)(head.Difficulty), + "extraData": hexutil.Bytes(head.Extra), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), + "timestamp": hexutil.Uint64(head.Time), + "transactionsRoot": head.TxHash, + "receiptsRoot": head.ReceiptHash, + } + if head.BaseFee != nil { + result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) + } + if head.WithdrawalsHash != nil { + result["withdrawalsRoot"] = head.WithdrawalsHash + } + if head.BlobGasUsed != nil { + result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed) + } + if head.ExcessBlobGas != nil { + result["excessBlobGas"] = hexutil.Uint64(*head.ExcessBlobGas) + } + if head.ParentBeaconRoot != nil { + result["parentBeaconBlockRoot"] = head.ParentBeaconRoot + } + return result +} diff --git a/jsonrpc/backend/eth.go b/jsonrpc/backend/eth.go new file mode 100644 index 0000000..8c39560 --- /dev/null +++ b/jsonrpc/backend/eth.go @@ -0,0 +1,159 @@ +package backend + +import ( + "errors" + "math/big" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + "github.com/initia-labs/minievm/x/evm/keeper" + "github.com/initia-labs/minievm/x/evm/types" +) + +func (b *JSONRPCBackend) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { + blockNumber, err := b.resolveBlockNrOrHash(blockNrOrHash) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtxWithHeight(blockNumber) + if err != nil { + return nil, err + } + + feeDenom, decimals, err := b.feeDenomWithDecimals() + if err != nil { + return nil, err + } + + balance, err := b.app.EVMKeeper.ERC20Keeper().GetBalance(queryCtx, sdk.AccAddress(address[:]), feeDenom) + if err != nil { + return nil, err + } + + return (*hexutil.Big)(types.ToEthersUint(decimals, balance.BigInt())), nil +} + +func (b *JSONRPCBackend) Call(args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *rpctypes.StateOverride, blockOverrides *rpctypes.BlockOverrides) (hexutil.Bytes, error) { + if overrides != nil { + return nil, errors.New("state overrides are not supported") + } + if blockOverrides != nil { + return nil, errors.New("block overrides are not supported") + } + + // if blockNrOrHash is nil, use the latest block + if blockNrOrHash != nil { + latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) + blockNrOrHash = &latest + } + + blockNumber, err := b.resolveBlockNrOrHash(*blockNrOrHash) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtxWithHeight(blockNumber) + if err != nil { + return nil, err + } + + // set call defaults + args.CallDefaults() + + // convert sender to string + sender := "" + if args.From != nil { + senderStr, err := b.app.AccountKeeper.AddressCodec().BytesToString(args.From[:]) + if err != nil { + return nil, err + } + + sender = senderStr + } + + contractAddr := "" + if args.To != nil { + contractAddr = args.To.Hex() + } + + res, err := keeper.NewQueryServer(b.app.EVMKeeper).Call(queryCtx, &types.QueryCallRequest{ + Sender: sender, + ContractAddr: contractAddr, + Input: hexutil.Encode(args.GetData()), + }) + + if err != nil { + return nil, err + } + + if res.Error != "" { + return nil, errors.New(res.Error) + } + + return hexutil.MustDecode(res.Response), nil +} + +func (b *JSONRPCBackend) GetStorageAt(address common.Address, key common.Hash, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + blockNumber, err := b.resolveBlockNrOrHash(blockNrOrHash) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtxWithHeight(blockNumber) + if err != nil { + return nil, err + } + + res, err := keeper.NewQueryServer(b.app.EVMKeeper).State(queryCtx, &types.QueryStateRequest{ + ContractAddr: address.Hex(), + Key: key.Hex(), + }) + + if err != nil { + return nil, err + } + + return hexutil.MustDecode(res.Value), nil +} + +func (b *JSONRPCBackend) GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + blockNumber, err := b.resolveBlockNrOrHash(blockNrOrHash) + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtxWithHeight(blockNumber) + if err != nil { + return nil, err + } + + res, err := keeper.NewQueryServer(b.app.EVMKeeper).Code(queryCtx, &types.QueryCodeRequest{ + ContractAddr: address.Hex(), + }) + + if err != nil { + return nil, err + } + + return hexutil.MustDecode(res.Code), nil +} + +func (b *JSONRPCBackend) ChainId() (*hexutil.Big, error) { + chainID, err := b.ChainID() + return (*hexutil.Big)(chainID), err +} + +func (b *JSONRPCBackend) ChainID() (*big.Int, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + sdkCtx := sdk.UnwrapSDKContext(queryCtx) + return types.ConvertCosmosChainIDToEthereumChainID(sdkCtx.ChainID()), nil +} diff --git a/jsonrpc/backend/filters.go b/jsonrpc/backend/filters.go new file mode 100644 index 0000000..8cf9113 --- /dev/null +++ b/jsonrpc/backend/filters.go @@ -0,0 +1,56 @@ +package backend + +import ( + coretypes "github.com/ethereum/go-ethereum/core/types" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" +) + +// GetLogsByHeight returns all the logs from all the ethereum transactions in a block. +func (b *JSONRPCBackend) GetLogsByHeight(height uint64) ([]*coretypes.Log, error) { + blockLogs := []*coretypes.Log{} + + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + blockHeader, err := b.app.EVMIndexer().BlockHeaderByNumber(queryCtx, height) + if err != nil { + return nil, err + } + + txs := []*rpctypes.RPCTransaction{} + b.app.EVMIndexer().IterateBlockTxs(queryCtx, height, func(tx *rpctypes.RPCTransaction) (bool, error) { + txs = append(txs, tx) + return false, nil + }) + + for _, tx := range txs { + receipt, err := b.app.EVMIndexer().TxReceiptByHash(queryCtx, tx.Hash) + if err != nil { + return nil, err + } + logs := receipt.Logs + for idx, log := range logs { + log.BlockHash = blockHeader.Hash() + log.BlockNumber = height + log.TxHash = tx.Hash + log.Index = uint(idx) + log.TxIndex = receipt.TransactionIndex + } + blockLogs = append(blockLogs, logs...) + } + + return blockLogs, nil +} + +// RPCFilterCap is the limit for total number of filters that can be created +func (b *JSONRPCBackend) RPCFilterCap() int32 { + return b.cfg.FilterCap +} + +// RPCFilterCap is the limit for total number of filters that can be created +func (b *JSONRPCBackend) RPCBlockRangeCap() int32 { + return b.cfg.BlockRangeCap +} diff --git a/jsonrpc/backend/gas.go b/jsonrpc/backend/gas.go new file mode 100644 index 0000000..31ce085 --- /dev/null +++ b/jsonrpc/backend/gas.go @@ -0,0 +1,152 @@ +package backend + +import ( + "errors" + "math/big" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + "github.com/initia-labs/minievm/x/evm/keeper" + "github.com/initia-labs/minievm/x/evm/types" +) + +func (b *JSONRPCBackend) EstimateGas(args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *rpctypes.StateOverride) (hexutil.Uint64, error) { + if overrides != nil { + return hexutil.Uint64(0), errors.New("state overrides are not supported") + } + + if args.Nonce == nil { + nonce, err := b.GetTransactionCount(*args.From, rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)) + if err != nil { + return hexutil.Uint64(0), err + } + + args.Nonce = nonce + } + + // set call defaults + args.CallDefaults() + + // convert sender to string + sender, err := b.app.AccountKeeper.AddressCodec().BytesToString(args.From[:]) + if err != nil { + return hexutil.Uint64(0), err + } + + _, decimals, err := b.feeDenomWithDecimals() + if err != nil { + return hexutil.Uint64(0), err + } + + sdkMsgs := []sdk.Msg{} + if args.To == nil { + sdkMsgs = append(sdkMsgs, &types.MsgCreate{ + Sender: sender, + Code: hexutil.Encode(args.GetData()), + Value: math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())), + }) + } else { + sdkMsgs = append(sdkMsgs, &types.MsgCall{ + Sender: sender, + ContractAddr: args.To.Hex(), + Input: hexutil.Encode(args.GetData()), + Value: math.NewIntFromBigInt(types.FromEthersUnit(decimals, args.Value.ToInt())), + }) + } + + txBuilder := b.app.TxConfig().NewTxBuilder() + txBuilder.SetMsgs(sdkMsgs...) + txBuilder.SetSignatures(signing.SignatureV2{ + PubKey: nil, + Data: &signing.SingleSignatureData{ + SignMode: keeper.SignMode_SIGN_MODE_ETHEREUM, + Signature: nil, + }, + Sequence: uint64(*args.Nonce), + }) + tx := txBuilder.GetTx() + txBytes, err := b.app.TxConfig().TxEncoder()(tx) + if err != nil { + return hexutil.Uint64(0), err + } + + gasInfo, _, err := b.app.Simulate(txBytes) + if err != nil { + b.svrCtx.Logger.Error("failed to simulate tx", "err", err) + return hexutil.Uint64(0), err + } + + return hexutil.Uint64(gasInfo.GasUsed), nil +} + +func (b *JSONRPCBackend) feeDenom() (string, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return "", err + } + + params, err := b.app.EVMKeeper.Params.Get(queryCtx) + if err != nil { + return "", err + } + + return params.FeeDenom, nil +} + +func (b *JSONRPCBackend) feeDenomWithDecimals() (string, uint8, error) { + feeDenom, err := b.feeDenom() + if err != nil { + return "", 0, err + } + + queryCtx, err := b.getQueryCtx() + if err != nil { + return "", 0, err + } + + decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom) + if err != nil { + return "", 0, err + } + + return feeDenom, decimals, nil +} + +func (b *JSONRPCBackend) GasPrice() (*hexutil.Big, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + params, err := b.app.OPChildKeeper.GetParams(queryCtx) + if err != nil { + return nil, err + } + + feeDenom, err := b.feeDenom() + if err != nil { + return nil, err + } + + decimals, err := b.app.EVMKeeper.ERC20Keeper().GetDecimals(queryCtx, feeDenom) + if err != nil { + return nil, err + } + + // multiply by 1e9 to prevent decimal drops + gasPrice := params.MinGasPrices.AmountOf(feeDenom). + MulTruncate(math.LegacyNewDec(1e9)). + TruncateInt().BigInt() + + return (*hexutil.Big)(types.ToEthersUint(decimals+9, gasPrice)), nil +} + +func (b *JSONRPCBackend) MaxPriorityFeePerGas() (*hexutil.Big, error) { + return (*hexutil.Big)(big.NewInt(0)), nil +} diff --git a/jsonrpc/backend/net.go b/jsonrpc/backend/net.go new file mode 100644 index 0000000..d8c1a7b --- /dev/null +++ b/jsonrpc/backend/net.go @@ -0,0 +1,25 @@ +package backend + +import ( + "strconv" + "strings" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (b *JSONRPCBackend) Version() (string, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return "", err + } + + sdkCtx := sdk.UnwrapSDKContext(queryCtx) + items := strings.Split(sdkCtx.ChainID(), "-") + version := items[len(items)-1] + + if _, err = strconv.Atoi(version); err != nil { + return "1", nil + } + + return version, err +} diff --git a/jsonrpc/backend/tx.go b/jsonrpc/backend/tx.go new file mode 100644 index 0000000..240803b --- /dev/null +++ b/jsonrpc/backend/tx.go @@ -0,0 +1,288 @@ +package backend + +import ( + "context" + "errors" + + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" + + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + "github.com/initia-labs/minievm/x/evm/keeper" + "github.com/initia-labs/minievm/x/evm/types" + + cmtrpcclient "github.com/cometbft/cometbft/rpc/client" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (b *JSONRPCBackend) SendRawTransaction(input hexutil.Bytes) (common.Hash, error) { + tx := new(coretypes.Transaction) + if err := tx.UnmarshalBinary(input); err != nil { + return common.Hash{}, err + } + + return tx.Hash(), b.SendTx(tx) +} + +func (b *JSONRPCBackend) SendTx(tx *coretypes.Transaction) error { + queryCtx, err := b.getQueryCtx() + if err != nil { + return err + } + + cosmosTx, err := keeper.NewTxUtils(b.app.EVMKeeper).ConvertEthereumTxToCosmosTx(queryCtx, tx) + if err != nil { + return err + } + + txBytes, err := b.app.TxEncode(cosmosTx) + if err != nil { + return err + } + + res, err := b.clientCtx.BroadcastTxSync(txBytes) + if err != nil { + return err + } + if res.Code != 0 { + return sdkerrors.ErrInvalidRequest.Wrapf("tx failed with code: %d: raw_log: %s", res.Code, res.RawLog) + } + + return nil +} + +func (b *JSONRPCBackend) getQueryCtx() (context.Context, error) { + return b.app.CreateQueryContext(0, false) +} + +func (b *JSONRPCBackend) getQueryCtxWithHeight(height uint64) (context.Context, error) { + return b.app.CreateQueryContext(int64(height), false) +} + +// GetTransactionByHash returns the transaction with the given hash. +func (b *JSONRPCBackend) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + return b.app.EVMIndexer().TxByHash(queryCtx, hash) +} + +// GetTransactionCount returns the number of transactions at the given block number. +func (b *JSONRPCBackend) GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { + sdkAddr := sdk.AccAddress(address[:]) + + var blockNumber rpc.BlockNumber + if blockHash, ok := blockNrOrHash.Hash(); ok { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + blockNumberU64, err := b.app.EVMIndexer().BlockHashToNumber(queryCtx, blockHash) + if err != nil { + return nil, err + } + + blockNumber = rpc.BlockNumber(blockNumberU64) + } else { + blockNumber, _ = blockNrOrHash.Number() + } + + seq := uint64(0) + var queryCtx context.Context + if blockNumber == rpc.PendingBlockNumber { + queryCtx = b.app.GetContextForCheckTx(nil) + } else { + var err error + queryCtx, err = b.app.CreateQueryContext(0, false) + if err != nil { + return nil, err + } + } + + acc := b.app.AccountKeeper.GetAccount(queryCtx, sdkAddr) + if acc != nil { + seq = acc.GetSequence() + } + + return (*hexutil.Uint64)(&seq), nil +} + +// GetTransactionReceipt returns the transaction receipt for the given transaction hash. +func (b *JSONRPCBackend) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + tx, err := b.app.EVMIndexer().TxByHash(queryCtx, hash) + if err != nil { + return nil, err + } + + receipt, err := b.app.EVMIndexer().TxReceiptByHash(queryCtx, hash) + if err != nil { + return nil, err + } + + return marshalReceipt(receipt, tx), nil +} + +// GetTransactionByBlockHashAndIndex returns the transaction at the given block hash and index. +func (b *JSONRPCBackend) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + number, err := b.app.EVMIndexer().BlockHashToNumber(queryCtx, hash) + if err != nil { + return nil, err + } + + return b.app.EVMIndexer().TxByBlockAndIndex(queryCtx, number, uint64(idx)) +} + +// GetTransactionByBlockNumberAndIndex returns the transaction at the given block number and index. +func (b *JSONRPCBackend) GetTransactionByBlockNumberAndIndex(blockNum rpc.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + number := uint64(blockNum.Int64()) + return b.app.EVMIndexer().TxByBlockAndIndex(queryCtx, number, uint64(idx)) +} + +// GetBlockTransactionCountByHash returns the number of transactions in a block from a block matching the given block hash. +func (b *JSONRPCBackend) GetBlockTransactionCountByHash(hash common.Hash) (*hexutil.Uint, error) { + block, err := b.GetBlockByHash(hash, true) + if err != nil { + return nil, err + } + + numTxs := hexutil.Uint(len(block["transactions"].([]*rpctypes.RPCTransaction))) + return &numTxs, nil +} + +// GetBlockTransactionCountByNumber returns the number of transactions in a block from a block matching the given block number. +func (b *JSONRPCBackend) GetBlockTransactionCountByNumber(blockNum rpc.BlockNumber) (*hexutil.Uint, error) { + block, err := b.GetBlockByNumber(blockNum, true) + if err != nil { + return nil, err + } + + numTxs := hexutil.Uint(len(block["transactions"].([]*rpctypes.RPCTransaction))) + return &numTxs, nil +} + +// GetRawTransactionByHash returns the bytes of the transaction for the given hash. +func (b *JSONRPCBackend) GetRawTransactionByHash(hash common.Hash) (hexutil.Bytes, error) { + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + rpcTx, err := b.app.EVMIndexer().TxByHash(queryCtx, hash) + if err != nil { + return nil, err + } + + return rpcTx.ToTransaction().MarshalBinary() +} + +// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. +func (b *JSONRPCBackend) GetRawTransactionByBlockHashAndIndex(blockHash common.Hash, index hexutil.Uint) (hexutil.Bytes, error) { + rpcTx, err := b.GetTransactionByBlockHashAndIndex(blockHash, index) + if err != nil { + return nil, err + } + + return rpcTx.ToTransaction().MarshalBinary() +} + +func (b *JSONRPCBackend) PendingTransactions() ([]*rpctypes.RPCTransaction, error) { + chainID, err := b.ChainID() + if err != nil { + return nil, err + } + + queryCtx, err := b.getQueryCtx() + if err != nil { + return nil, err + } + + mc, ok := b.clientCtx.Client.(cmtrpcclient.MempoolClient) + if !ok { + return nil, errors.New("mempool client not available") + } + + res, err := mc.UnconfirmedTxs(b.ctx, nil) + if err != nil { + return nil, err + } + + result := make([]*rpctypes.RPCTransaction, 0, len(res.Txs)) + for _, txBz := range res.Txs { + tx, err := b.clientCtx.TxConfig.TxDecoder()(txBz) + if err != nil { + return nil, err + } + + sdkCtx := sdk.UnwrapSDKContext(queryCtx) + ethTx, _, err := keeper.NewTxUtils(b.app.EVMKeeper).ConvertCosmosTxToEthereumTx(sdkCtx, tx) + if err != nil { + return nil, err + } + if ethTx != nil { + result = append( + result, + rpctypes.NewRPCTransaction(ethTx, common.Hash{}, 0, 0, chainID), + ) + } + } + + return result, nil +} + +// marshalReceipt marshals a transaction receipt into a JSON object. +func marshalReceipt(receipt *coretypes.Receipt, tx *rpctypes.RPCTransaction) map[string]interface{} { + fields := map[string]interface{}{ + "blockHash": tx.BlockHash, + "blockNumber": hexutil.Big(*tx.BlockNumber), + "transactionHash": tx.Hash, + "transactionIndex": hexutil.Uint64(*tx.TransactionIndex), + "from": tx.From, + "to": tx.To, + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": receipt.Logs, + "logsBloom": receipt.Bloom, + "type": hexutil.Uint(coretypes.LegacyTxType), + "effectiveGasPrice": (*hexutil.Big)(receipt.EffectiveGasPrice), + } + + // Assign receipt status or post state. + if len(receipt.PostState) > 0 { + fields["root"] = hexutil.Bytes(receipt.PostState) + } else { + fields["status"] = hexutil.Uint(receipt.Status) + } + if receipt.Logs == nil { + fields["logs"] = []*types.Log{} + } + + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if receipt.ContractAddress != (common.Address{}) { + fields["contractAddress"] = receipt.ContractAddress + } + + return fields +} diff --git a/jsonrpc/config/config.go b/jsonrpc/config/config.go new file mode 100644 index 0000000..b1620b2 --- /dev/null +++ b/jsonrpc/config/config.go @@ -0,0 +1,154 @@ +package config + +import ( + "time" + + "github.com/spf13/cast" + "github.com/spf13/cobra" + + servertypes "github.com/cosmos/cosmos-sdk/server/types" +) + +const ( + // DefaultEnable defines the default value for enabling the EVM RPC server. + DefaultEnable = true + // DefaultEnableUnsafeCORS defines the default value for enabling unsafe CORS. + DefaultEnableUnsafeCORS = false + // DefaultHTTPTimeout is the default read/write timeout of http json-rpc server. + DefaultHTTPTimeout = 10 * time.Second + // DefaultHTTPIdleTimeout is the default idle timeout of http json-rpc server. + DefaultHTTPIdleTimeout = 120 * time.Second + // DefaultMaxOpenConnections is the default maximum number of simultaneous connections + // for the server listener. + DefaultMaxOpenConnections = 100 + // DefaultLogsCap is the default max number of results can be returned from single `eth_getLogs` query. + DefaultLogsCap = 100 + // DefaultBlockRangeCap is the default max block range allowed for `eth_getLogs` query. + DefaultBlockRangeCap = 100 + // DefaultAddress defines the default HTTP server to listen on. + DefaultAddress = "127.0.0.1:8545" + // DefaultFilterCap + DefaultFilterCap int32 = 200 +) + +var ( + // DefaultAPIs defines the default list of JSON-RPC namespaces that should be enabled. + DefaultAPIs = []string{"eth" /*"txpool", "personal", "net", "debug", "web3"*/} +) + +const ( + flagJSONRPCEnable = "json-rpc.enable" + flagJSONRPCEnableUnsafeCORS = "json-rpc.enable-unsafe-cors" + flagJSONRPCAddress = "json-rpc.address" + flagJSONRPCAPIs = "json-rpc.apis" + flagJSONRPCLogsCap = "json-rpc.logs-cap" + flagJSONRPCFilterCap = "json-rpc.filter-cap" + flagJSONRPCBlockRangeCap = "json-rpc.block-range-cap" + flagJSONRPCHTTPTimeout = "json-rpc.http-timeout" + flagJSONRPCHTTPIdleTimeout = "json-rpc.http-idle-timeout" + flagJSONRPCMaxOpenConnections = "json-rpc.max-open-connections" +) + +// JSONRPCConfig defines configuration for the EVM RPC server. +type JSONRPCConfig struct { + // Enable defines if the EVM RPC server should be enabled. + Enable bool `mapstructure:"enable"` + // EnableUnsafeCORS defines if the EVM RPC server should enable unsafe CORS. + EnableUnsafeCORS bool `mapstructure:"enable-unsafe-cors"` + // Address defines the HTTP server to listen on + Address string `mapstructure:"address"` + // API defines a list of JSON-RPC namespaces that should be enabled + APIs []string `mapstructure:"apis"` + // FilterCap is the global cap for total number of filters that can be created. + FilterCap int32 `mapstructure:"filter-cap"` + // BlockRangeCap defines the max block range allowed for `eth_getLogs` query. + BlockRangeCap int32 `mapstructure:"block-range-cap"` + // HTTPTimeout is the read/write timeout of http json-rpc server. + HTTPTimeout time.Duration `mapstructure:"http-timeout"` + // HTTPIdleTimeout is the idle timeout of http json-rpc server. + HTTPIdleTimeout time.Duration `mapstructure:"http-idle-timeout"` + // MaxOpenConnections sets the maximum number of simultaneous connections + // for the server listener. + MaxOpenConnections int `mapstructure:"max-open-connections"` +} + +// DefaultJSONRPCConfig returns a default configuration for the EVM RPC server. +func DefaultJSONRPCConfig() JSONRPCConfig { + return JSONRPCConfig{ + Enable: DefaultEnable, + EnableUnsafeCORS: DefaultEnableUnsafeCORS, + Address: DefaultAddress, + APIs: DefaultAPIs, + FilterCap: DefaultFilterCap, + BlockRangeCap: DefaultBlockRangeCap, + HTTPTimeout: DefaultHTTPTimeout, + HTTPIdleTimeout: DefaultHTTPIdleTimeout, + MaxOpenConnections: DefaultMaxOpenConnections, + } +} + +// AddConfigFlags adds flags for a EVM RPC server to the StartCmd. +func AddConfigFlags(startCmd *cobra.Command) { + startCmd.Flags().Bool(flagJSONRPCEnable, DefaultEnable, "Enable the EVM RPC server") + startCmd.Flags().Bool(flagJSONRPCEnableUnsafeCORS, DefaultEnableUnsafeCORS, "Enable unsafe CORS") + startCmd.Flags().String(flagJSONRPCAddress, DefaultAddress, "Address to listen on for the EVM RPC server") + startCmd.Flags().StringSlice(flagJSONRPCAPIs, DefaultAPIs, "List of JSON-RPC namespaces that should be enabled") + startCmd.Flags().Int32(flagJSONRPCFilterCap, DefaultFilterCap, "Sets the global cap for total number of filters that can be created") + startCmd.Flags().Int32(flagJSONRPCBlockRangeCap, DefaultBlockRangeCap, "Max block range allowed for 'eth_getLogs' query") + startCmd.Flags().Duration(flagJSONRPCHTTPTimeout, DefaultHTTPTimeout, "Read/write timeout of http json-rpc server") + startCmd.Flags().Duration(flagJSONRPCHTTPIdleTimeout, DefaultHTTPIdleTimeout, "Idle timeout of http json-rpc server") + startCmd.Flags().Int(flagJSONRPCMaxOpenConnections, DefaultMaxOpenConnections, "Maximum number of simultaneous connections for the server listener") +} + +// GetConfig load config values from the app options +func GetConfig(appOpts servertypes.AppOptions) JSONRPCConfig { + return JSONRPCConfig{ + Enable: cast.ToBool(appOpts.Get(flagJSONRPCEnable)), + EnableUnsafeCORS: cast.ToBool(appOpts.Get(flagJSONRPCEnableUnsafeCORS)), + Address: cast.ToString(appOpts.Get(flagJSONRPCAddress)), + APIs: cast.ToStringSlice(appOpts.Get(flagJSONRPCAPIs)), + FilterCap: cast.ToInt32(appOpts.Get(flagJSONRPCFilterCap)), + BlockRangeCap: cast.ToInt32(appOpts.Get(flagJSONRPCBlockRangeCap)), + HTTPTimeout: cast.ToDuration(appOpts.Get(flagJSONRPCHTTPTimeout)), + HTTPIdleTimeout: cast.ToDuration(appOpts.Get(flagJSONRPCHTTPIdleTimeout)), + MaxOpenConnections: cast.ToInt(appOpts.Get(flagJSONRPCMaxOpenConnections)), + } +} + +// DefaultConfigTemplate defines the configuration template for the EVM RPC configuration +const DefaultConfigTemplate = ` +############################################################################### +### JSON RPC Configuration ### +############################################################################### + +[json-rpc] + +# Enable defines if the gRPC server should be enabled. +enable = {{ .JSONRPCConfig.Enable }} + +# Address defines the EVM RPC HTTP server address to bind to. +address = "{{ .JSONRPCConfig.Address }}" + +# EnableUnsafeCORS defines if the EVM RPC server should enable unsafe CORS. +enable-unsafe-cors = {{ .JSONRPCConfig.EnableUnsafeCORS }} + +# API defines a list of JSON-RPC namespaces that should be enabled +# Example: "eth,txpool,personal,net,debug,web3" +apis = "{{range $index, $elmt := .JSONRPCConfig.APIs}}{{if $index}},{{$elmt}}{{else}}{{$elmt}}{{end}}{{end}}" + +# FilterCap is the global cap for total number of filters that can be created. +filter-cap = {{ .JSONRPCConfig.FilterCap }} + +# BlockRangeCap defines the max block range allowed for 'eth_getLogs' query. +block-range-cap = {{ .JSONRPCConfig.BlockRangeCap }} + +# HTTPTimeout is the read/write timeout of http json-rpc server. +http-timeout = "{{ .JSONRPCConfig.HTTPTimeout }}" + +# HTTPIdleTimeout is the idle timeout of http json-rpc server. +http-idle-timeout = "{{ .JSONRPCConfig.HTTPIdleTimeout }}" + +# MaxOpenConnections sets the maximum number of simultaneous connections +# for the server listener. +max-open-connections = {{ .JSONRPCConfig.MaxOpenConnections }} +` diff --git a/jsonrpc/jsonrpc.go b/jsonrpc/jsonrpc.go new file mode 100644 index 0000000..2943013 --- /dev/null +++ b/jsonrpc/jsonrpc.go @@ -0,0 +1,159 @@ +package jsonrpc + +import ( + "context" + "net" + "net/http" + + "github.com/gorilla/mux" + ethns "github.com/initia-labs/minievm/jsonrpc/namespaces/eth" + "github.com/initia-labs/minievm/jsonrpc/namespaces/eth/filters" + + // "github.com/initia-labs/minievm/jsonrpc/namespaces/eth/filters" + netns "github.com/initia-labs/minievm/jsonrpc/namespaces/net" + "github.com/rs/cors" + "golang.org/x/net/netutil" + "golang.org/x/sync/errgroup" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/server" + + ethlog "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/initia-labs/minievm/app" + "github.com/initia-labs/minievm/jsonrpc/backend" + "github.com/initia-labs/minievm/jsonrpc/config" +) + +// RPC namespaces and API version +const ( + // TODO: implement commented apis in the namespaces for full Ethereum compatibility + EthNamespace = "eth" + NetNamespace = "net" + TxPoolNamespace = "txpool" + // TODO: support more namespaces + Web3Namespace = "web3" + PersonalNamespace = "personal" + DebugNamespace = "debug" + MinerNamespace = "miner" + + apiVersion = "1.0" +) + +func StartJSONRPC( + ctx context.Context, + g *errgroup.Group, + app *app.MinitiaApp, + svrCtx *server.Context, + clientCtx client.Context, + jsonRPCConfig config.JSONRPCConfig, +) error { + logger := svrCtx.Logger.With("module", "geth") + ethlog.SetDefault(ethlog.NewLogger(newLogger(logger))) + + rpcServer := rpc.NewServer() + bkd := backend.NewJSONRPCBackend(app, svrCtx, clientCtx, jsonRPCConfig) + apis := []rpc.API{ + { + Namespace: EthNamespace, + Version: apiVersion, + Service: ethns.NewEthAPI(svrCtx.Logger, bkd), + Public: true, + }, + { + Namespace: EthNamespace, + Version: apiVersion, + Service: filters.NewFilterAPI(app, bkd, svrCtx.Logger), + Public: true, + }, + { + Namespace: NetNamespace, + Version: apiVersion, + Service: netns.NewNetAPI(svrCtx.Logger, bkd), + Public: true, + }, + // TODO: implement more namespaces + //{ + // Namespace: TxPoolNamespace, + // Version: apiVersion, + // Service: txpool.NewTxPoolAPI(svrCtx.Logger, bkd), + // Public: true, + //}, + } + + for _, api := range apis { + if err := rpcServer.RegisterName(api.Namespace, api.Service); err != nil { + svrCtx.Logger.Error( + "failed to register service in JSON RPC namespace", + "namespace", api.Namespace, + "service", api.Service, + ) + return err + } + } + + r := mux.NewRouter() + r.HandleFunc("/", rpcServer.ServeHTTP).Methods("POST") + + handlerWithCors := cors.Default() + if jsonRPCConfig.EnableUnsafeCORS { + handlerWithCors = cors.AllowAll() + } + + httpSrv := &http.Server{ + Addr: jsonRPCConfig.Address, + Handler: handlerWithCors.Handler(r), + ReadHeaderTimeout: jsonRPCConfig.HTTPTimeout, + ReadTimeout: jsonRPCConfig.HTTPTimeout, + WriteTimeout: jsonRPCConfig.HTTPTimeout, + IdleTimeout: jsonRPCConfig.HTTPIdleTimeout, + } + + // httpSrv.Serve() + ln, err := listen(httpSrv.Addr, jsonRPCConfig) + if err != nil { + return err + } + + g.Go(func() error { + errCh := make(chan error) + + go func() { + svrCtx.Logger.Info("Starting JSON-RPC server", "address", jsonRPCConfig.Address) + errCh <- httpSrv.Serve(ln) + }() + + // Start a blocking select to wait for an indication to stop the server or that + // the server failed to start properly. + select { + case <-ctx.Done(): + // The calling process canceled or closed the provided context, so we must + // gracefully stop the gRPC server. + logger.Info("stopping Ethereum JSONRPC server...", "address", jsonRPCConfig.Address) + return httpSrv.Close() + + case err := <-errCh: + logger.Error("failed to start Ethereum JSONRPC server", "err", err) + return err + } + }) + + return nil +} + +// Listen starts a net.Listener on the tcp network on the given address. +// If there is a specified MaxOpenConnections in the config, it will also set the limitListener. +func listen(addr string, jsonRPCConfig config.JSONRPCConfig) (net.Listener, error) { + if addr == "" { + addr = ":http" + } + ln, err := net.Listen("tcp", addr) + if err != nil { + return nil, err + } + if jsonRPCConfig.MaxOpenConnections > 0 { + ln = netutil.LimitListener(ln, jsonRPCConfig.MaxOpenConnections) + } + return ln, err +} diff --git a/jsonrpc/logger.go b/jsonrpc/logger.go new file mode 100644 index 0000000..538ca18 --- /dev/null +++ b/jsonrpc/logger.go @@ -0,0 +1,57 @@ +package jsonrpc + +import ( + "context" + "log/slog" + + "cosmossdk.io/log" + + ethlog "github.com/ethereum/go-ethereum/log" +) + +var _ slog.Handler = (*logHandler)(nil) + +type logHandler struct { + log.Logger + group string + attrs []slog.Attr +} + +func newLogger(logger log.Logger) *logHandler { + return &logHandler{Logger: logger} +} + +// Enabled implements slog.Handler. +func (l *logHandler) Enabled(context.Context, slog.Level) bool { + return true +} + +// Handle implements slog.Handler. +func (l *logHandler) Handle(ctx context.Context, r slog.Record) error { + attrs := make([]any, 2*len(l.attrs)) + for i, attr := range l.attrs { + attrs[i*2] = attr.Key + attrs[i*2+1] = attr.Value + } + + switch r.Level { + case ethlog.LevelTrace, ethlog.LevelDebug: + l.Logger.Debug(r.Message, attrs...) + case ethlog.LevelInfo, ethlog.LevelWarn: + l.Logger.Info(r.Message, attrs...) + case ethlog.LevelError, ethlog.LevelCrit: + l.Logger.Error(r.Message, attrs...) + } + + return nil +} + +// WithAttrs implements slog.Handler. +func (l *logHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &logHandler{Logger: l.Logger, group: l.group, attrs: append(l.attrs, attrs...)} +} + +// WithGroup implements slog.Handler. +func (l *logHandler) WithGroup(name string) slog.Handler { + return &logHandler{Logger: l.Logger, group: name, attrs: l.attrs} +} diff --git a/jsonrpc/namespaces/eth/api.go b/jsonrpc/namespaces/eth/api.go new file mode 100644 index 0000000..5d2945d --- /dev/null +++ b/jsonrpc/namespaces/eth/api.go @@ -0,0 +1,488 @@ +package ethapi + +import ( + "context" + "encoding/hex" + "errors" + "strings" + + "cosmossdk.io/log" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/initia-labs/minievm/jsonrpc/backend" + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" +) + +var _ EthEthereumAPI = (*EthAPI)(nil) + +// EthEthereumAPI is a collection of eth namespaced APIs. +// Current it is used for tracking what APIs should be implemented for Ethereum compatibility. +// After fully implementing the Ethereum APIs, this interface can be removed. +type EthEthereumAPI interface { + // Getting Blocks + // + // Retrieves information from a particular block in the blockchain. + BlockNumber() hexutil.Uint64 + GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) + GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) + + // Reading Transactions + // + // Retrieves information on the state data for addresses regardless of whether + // it is a user or a smart contract. + GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) + GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) + GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) + GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) + GetTransactionByBlockNumberAndIndex(blockNum rpc.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) + GetBlockTransactionCountByHash(hash common.Hash) (*hexutil.Uint, error) + GetBlockTransactionCountByNumber(blockNum rpc.BlockNumber) (*hexutil.Uint, error) + GetRawTransactionByHash(hash common.Hash) (hexutil.Bytes, error) + GetRawTransactionByBlockHashAndIndex(blockHash common.Hash, index hexutil.Uint) hexutil.Bytes + + // eth_getBlockReceipts + + // Writing Transactions + // + // Allows developers to both send ETH from one address to another, write data + // on-chain, and interact with smart contracts. + SendRawTransaction(data hexutil.Bytes) (common.Hash, error) + //SendTransaction(args rpctypes.TransactionArgs) (common.Hash, error) + // eth_sendPrivateTransaction + // eth_cancel PrivateTransaction + + // Account Information + // + // Returns information regarding an address's stored on-chain data. + //Accounts() ([]common.Address, error) + GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) + GetStorageAt(address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) + GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) + // GetProof(address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*rpc.AccountResult, error) + + // EVM/Smart Contract Execution + // + // Allows developers to read data from the blockchain which includes executing + // smart contracts. However, no data is published to the Ethereum network. + Call(args rpctypes.TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, so *rpctypes.StateOverride, bo *rpctypes.BlockOverrides) (hexutil.Bytes, error) + + // // Chain Information + // // + // // Returns information on the Ethereum network and internal settings. + // ProtocolVersion() hexutil.Uint + GasPrice() (*hexutil.Big, error) + EstimateGas(args rpctypes.TransactionArgs, blockNrOptional *rpc.BlockNumberOrHash, so *rpctypes.StateOverride) (hexutil.Uint64, error) + // FeeHistory(blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*rpc.FeeHistoryResult, error) + MaxPriorityFeePerGas() (*hexutil.Big, error) + ChainId() *hexutil.Big + + // // Other + // Syncing() (interface{}, error) + // Coinbase() (string, error) + // Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) + // GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) + // SignTypedData(address common.Address, typedData apitypes.TypedData) (hexutil.Bytes, error) + // FillTransaction(args evmtypes.TransactionArgs) (*rpc.SignTransactionResult, error) + // Resend(args evmtypes.TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) + PendingTransactions() ([]*rpctypes.RPCTransaction, error) + // // eth_signTransaction (on Ethereum.org) + // // eth_getCompilers (on Ethereum.org) + // // eth_compileSolidity (on Ethereum.org) + // // eth_compileLLL (on Ethereum.org) + // // eth_compileSerpent (on Ethereum.org) + // // eth_getWork (on Ethereum.org) + // // eth_submitWork (on Ethereum.org) + // // eth_submitHashrate (on Ethereum.org) +} + +// EthAPI is the txpool namespace for the Ethereum JSON-RPC APIs. +type EthAPI struct { + ctx context.Context + logger log.Logger + backend *backend.JSONRPCBackend +} + +// NewEthAPI creates an instance of the public ETH Web3 API. +func NewEthAPI(logger log.Logger, backend *backend.JSONRPCBackend) *EthAPI { + api := &EthAPI{ + ctx: context.TODO(), + logger: logger.With("client", "json-rpc"), + backend: backend, + } + + return api +} + +// ************************************* +// * Blocks * +// ************************************* + +// BlockNumber returns the current block number. +func (api *EthAPI) BlockNumber() hexutil.Uint64 { + api.logger.Debug("eth_blockNumber") + blockNumber, err := api.backend.BlockNumber() + if err != nil { + api.logger.Error("eth_blockNumber", "error", err) + return 0 + } + return blockNumber +} + +// GetBlockByNumber returns the block identified by number. +func (api *EthAPI) GetBlockByNumber(ethBlockNum rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { + api.logger.Debug("eth_getBlockByNumber", "number", ethBlockNum, "full", fullTx) + return api.backend.GetBlockByNumber(ethBlockNum, fullTx) +} + +// GetBlockByHash returns the block identified by hash. +func (api *EthAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) { + api.logger.Debug("eth_getBlockByHash", "hash", hash.Hex(), "full", fullTx) + return api.backend.GetBlockByHash(hash, fullTx) +} + +// ************************************* +// * Read Txs * +// ************************************* + +// GetTransactionByHash returns the transaction identified by hash. +func (api *EthAPI) GetTransactionByHash(hash common.Hash) (*rpctypes.RPCTransaction, error) { + api.logger.Debug("eth_getTransactionByHash", "hash", hash.Hex()) + return api.backend.GetTransactionByHash(hash) +} + +// GetRawTransactionByHash returns the bytes of the transaction for the given tx hash. +func (api *EthAPI) GetRawTransactionByHash(blockHash common.Hash) (hexutil.Bytes, error) { + return api.backend.GetRawTransactionByHash(blockHash) +} + +// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. +func (api *EthAPI) GetRawTransactionByBlockHashAndIndex(blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { + rawTx, err := api.backend.GetRawTransactionByBlockHashAndIndex(blockHash, index) + if err != nil { + api.logger.Error("eth_getRawTransactionByBlockHashAndIndex", "error", err) + return nil + } + return rawTx +} + +// GetTransactionCount returns the number of transactions at the given address up to the given block number. +func (api *EthAPI) GetTransactionCount(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { + api.logger.Debug("eth_getTransactionCount", "address", address.Hex(), "block number or hash", blockNrOrHash) + return api.backend.GetTransactionCount(address, blockNrOrHash) +} + +// GetTransactionReceipt returns the transaction receipt identified by hash. +func (api *EthAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { + hexTx := hash.Hex() + api.logger.Debug("eth_getTransactionReceipt", "hash", hexTx) + return api.backend.GetTransactionReceipt(hash) +} + +// GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash. +func (api *EthAPI) GetBlockTransactionCountByHash(hash common.Hash) (*hexutil.Uint, error) { + api.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash.Hex()) + return api.backend.GetBlockTransactionCountByHash(hash) +} + +// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by number. +func (api *EthAPI) GetBlockTransactionCountByNumber(blockNum rpc.BlockNumber) (*hexutil.Uint, error) { + api.logger.Debug("eth_getBlockTransactionCountByNumber", "height", blockNum.Int64()) + return api.backend.GetBlockTransactionCountByNumber(blockNum) +} + +// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index. +func (api *EthAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { + api.logger.Debug("eth_getTransactionByBlockHashAndIndex", "hash", hash.Hex(), "index", idx) + return api.backend.GetTransactionByBlockHashAndIndex(hash, idx) +} + +// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index. +func (api *EthAPI) GetTransactionByBlockNumberAndIndex(blockNum rpc.BlockNumber, idx hexutil.Uint) (*rpctypes.RPCTransaction, error) { + api.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx) + return api.backend.GetTransactionByBlockNumberAndIndex(blockNum, idx) +} + +// ************************************* +// * Write Txs * +// ************************************* + +// SendRawTransaction send a raw Ethereum transaction. +func (api *EthAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) { + api.logger.Debug("eth_sendRawTransaction", "length", len(data)) + return api.backend.SendRawTransaction(data) +} + +// TODO: Implement eth_sendTransaction +//// SendTransaction sends an Ethereum transaction. +//func (e *EthAPI) SendTransaction(args rpctypes.TransactionArgs) (common.Hash, error) { +// e.logger.Debug("eth_sendTransaction", "args", args.String()) +// return e.backend.SendTransaction(args) +//} + +// ************************************* +// * Account Information * +// ************************************* + +// TODO: Implement eth_accounts +//// Accounts returns the list of accounts available to this node. +//func (e *EthAPI) Accounts() ([]common.Address, error) { +// e.logger.Debug("eth_accounts") +// return e.backend.Accounts() +//} + +// GetBalance returns the provided account's balance up to the provided block number. +func (api *EthAPI) GetBalance(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) { + api.logger.Debug("eth_getBalance", "address", address.String(), "block number or hash", blockNrOrHash) + return api.backend.GetBalance(address, blockNrOrHash) +} + +// GetStorageAt returns the contract storage at the given address, block number, and key. +func (api *EthAPI) GetStorageAt(address common.Address, hexKey string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + api.logger.Debug("eth_getStorageAt", "address", address.Hex(), "hexKey", hexKey, "block number or hash", blockNrOrHash) + key, _, err := decodeHash(hexKey) + if err != nil { + return hexutil.Bytes{}, err + } + return api.backend.GetStorageAt(address, key, blockNrOrHash) +} + +// GetCode returns the contract code at the given address and block number. +func (api *EthAPI) GetCode(address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) { + api.logger.Debug("eth_getCode", "address", address.Hex(), "block number or hash", blockNrOrHash) + return api.backend.GetCode(address, blockNrOrHash) +} + +// TODO: Implement eth_getProof +//// GetProof returns an account object with proof and any storage proofs +//func (e *EthAPI) GetProof(address common.Address, +// storageKeys []string, +// blockNrOrHash rpctypes.BlockNumberOrHash, +//) (*rpctypes.AccountResult, error) { +// e.logger.Debug("eth_getProof", "address", address.Hex(), "keys", storageKeys, "block number or hash", blockNrOrHash) +// return e.backend.GetProof(address, storageKeys, blockNrOrHash) +//} + +// ********************************************** +// * EVM/Smart Contract Execution * +// ********************************************** + +// Call performs a raw contract call. +func (api *EthAPI) Call( + args rpctypes.TransactionArgs, + blockNrOrHash *rpc.BlockNumberOrHash, + so *rpctypes.StateOverride, + bo *rpctypes.BlockOverrides, +) (hexutil.Bytes, error) { + api.logger.Debug("eth_call", "args", args.String(), "block number or hash", blockNrOrHash, "state override", so, "block override", bo) + return api.backend.Call(args, blockNrOrHash, so, bo) +} + +/////////////////////////////////////////////////////////////////////////////// +/// Event Logs /// +/////////////////////////////////////////////////////////////////////////////// +// FILTER API at ./filters/api.go + +/////////////////////////////////////////////////////////////////////////////// +/// Chain Information /// +/////////////////////////////////////////////////////////////////////////////// + +// TODO: Implement eth_protocolVersion +//// ProtocolVersion returns the supported Ethereum protocol version. +//func (e *EthAPI) ProtocolVersion() hexutil.Uint { +// e.logger.Debug("eth_protocolVersion") +// return hexutil.Uint(ethermint.ProtocolVersion) +//} + +// GasPrice returns the current gas price based on Ethermint's gas price oracle. +func (api *EthAPI) GasPrice() (*hexutil.Big, error) { + api.logger.Debug("eth_gasPrice") + return api.backend.GasPrice() +} + +// EstimateGas returns an estimate of gas usage for the given smart contract call. +func (api *EthAPI) EstimateGas( + args rpctypes.TransactionArgs, + blockNrOptional *rpc.BlockNumberOrHash, + so *rpctypes.StateOverride, +) (hexutil.Uint64, error) { + api.logger.Debug("eth_estimateGas") + return api.backend.EstimateGas(args, blockNrOptional, so) +} + +//// TODO: Implement eth_feeHistory +//// FeeHistory returns the fee history for the last blockCount blocks. +//func (e *EthAPI) FeeHistory(blockCount rpc.DecimalOrHex, +// lastBlock rpc.BlockNumber, +// rewardPercentiles []float64, +//) (*rpctypes.FeeHistoryResult, error) { +// e.logger.Debug("eth_feeHistory") +// return e.backend.FeeHistory(blockCount, lastBlock, rewardPercentiles) +//} + +// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions. +func (api *EthAPI) MaxPriorityFeePerGas() (*hexutil.Big, error) { + api.logger.Debug("eth_maxPriorityFeePerGas") + return api.backend.MaxPriorityFeePerGas() +} + +// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config. +func (api *EthAPI) ChainId() *hexutil.Big { //nolint + api.logger.Debug("eth_chainId") + chainId, err := api.backend.ChainID() + if err != nil { + return nil + } + return (*hexutil.Big)(chainId) +} + +/////////////////////////////////////////////////////////////////////////////// +/// Uncles /// +/////////////////////////////////////////////////////////////////////////////// + +// ************************************* +// * Uncles * +// ************************************* + +// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil. +func (api *EthAPI) GetUncleByBlockHashAndIndex(_ common.Hash, _ hexutil.Uint) map[string]interface{} { + return nil +} + +// GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns nil. +func (api *EthAPI) GetUncleByBlockNumberAndIndex(_, _ hexutil.Uint) map[string]interface{} { + return nil +} + +// GetUncleCountByBlockHash returns the number of uncles in the block identified by hash. Always zero. +func (api *EthAPI) GetUncleCountByBlockHash(_ common.Hash) hexutil.Uint { + return 0 +} + +// GetUncleCountByBlockNumber returns the number of uncles in the block identified by number. Always zero. +func (api *EthAPI) GetUncleCountByBlockNumber(_ rpc.BlockNumber) hexutil.Uint { + return 0 +} + +// ************************************* +// * pow(leagcy) * +// ************************************* + +// Hashrate returns the current node's hashrate. Always 0. +func (api *EthAPI) Hashrate() hexutil.Uint64 { + api.logger.Debug("eth_hashrate") + return 0 +} + +// Mining returns whether or not this node is currently mining. Always false. +func (api *EthAPI) Mining() bool { + api.logger.Debug("eth_mining") + return false +} + +// ************************************* +// * others * +// ************************************* + +// TODO: Implement eth_syncing +//// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not +//// yet received the latest block headers from its pears. In case it is synchronizing: +//// - startingBlock: block number this node started to synchronize from +//// - currentBlock: block number this node is currently importing +//// - highestBlock: block number of the highest block header this node has received from peers +//// - pulledStates: number of state entries processed until now +//// - knownStates: number of known state entries that still need to be pulled +//func (e *EthAPI) Syncing() (interface{}, error) { +// e.logger.Debug("eth_syncing") +// return e.backend.Syncing() +//} + +// TODO: Implement eth_coinbase +//// Coinbase is the address that staking rewards will be send to (alias for Etherbase). +//func (e *EthAPI) Coinbase() (string, error) { +// e.logger.Debug("eth_coinbase") +// +// coinbase, err := e.backend.GetCoinbase() +// if err != nil { +// return "", err +// } +// ethAddr := common.BytesToAddress(coinbase.Bytes()) +// return ethAddr.Hex(), nil +//} + +// TODO: Implement eth_sign +//// Sign signs the provided data using the private key of address via Geth's signature standard. +//func (e *EthAPI) Sign(address common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { +// e.logger.Debug("eth_sign", "address", address.Hex(), "data", common.Bytes2Hex(data)) +// return e.backend.Sign(address, data) +//} + +// TODO: Implement eth_signTypedData +//// SignTypedData signs EIP-712 conformant typed data +//func (e *EthAPI) SignTypedData(address common.Address, typedData apitypes.TypedData) (hexutil.Bytes, error) { +// e.logger.Debug("eth_signTypedData", "address", address.Hex(), "data", typedData) +// return e.backend.SignTypedData(address, typedData) +//} + +// TODO: Implement eth_fillTransaction +//// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields) +//// on a given unsigned transaction, and returns it to the caller for further +//// processing (signing + broadcast). +//func (e *EthAPI) FillTransaction(args rpctypes.TransactionArgs) (ethapi.SignTransactionResult, error) { +// // Set some sanity defaults and terminate on failure +// args, err := e.backend.SetTxDefaults(args) +// if err != nil { +// return nil, err +// } +// +// // Assemble the transaction and obtain rlp +// tx := args.ToTransaction().AsTransaction() +// +// data, err := tx.MarshalBinary() +// if err != nil { +// return nil, err +// } +// +// return ðapi.SignTransactionResult{ +// Raw: data, +// Tx: tx, +// }, nil +//} + +// TODO: Implement eth_resend +//// Resend accepts an existing transaction and a new gas price and limit. It will remove +//// the given transaction from the pool and reinsert it with the new gas price and limit. +//func (e *EthAPI) Resend(_ context.Context, +// args rpctypes.TransactionArgs, +// gasPrice *hexutil.Big, +// gasLimit *hexutil.Uint64, +//) (common.Hash, error) { +// e.logger.Debug("eth_resend", "args", args.String()) +// return e.backend.Resend(args, gasPrice, gasLimit) +//} + +// PendingTransactions returns the transactions that are in the transaction pool +// and have a from address that is one of the accounts this node manages. +func (api *EthAPI) PendingTransactions() ([]*rpctypes.RPCTransaction, error) { + api.logger.Debug("eth_pendingTransactions") + return api.backend.PendingTransactions() +} + +// decodeHash parses a hex-encoded 32-byte hash. The input may optionally +// be prefixed by 0x and can have a byte length up to 32. +func decodeHash(s string) (h common.Hash, inputLength int, err error) { + if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") { + s = s[2:] + } + if (len(s) & 1) > 0 { + s = "0" + s + } + b, err := hex.DecodeString(s) + if err != nil { + return common.Hash{}, 0, errors.New("hex string invalid") + } + if len(b) > 32 { + return common.Hash{}, len(b), errors.New("hex string too long, want at most 32 bytes") + } + return common.BytesToHash(b), len(b), nil +} diff --git a/jsonrpc/namespaces/eth/filters/api.go b/jsonrpc/namespaces/eth/filters/api.go new file mode 100644 index 0000000..1cd3c2c --- /dev/null +++ b/jsonrpc/namespaces/eth/filters/api.go @@ -0,0 +1,351 @@ +package filters + +import ( + "context" + "errors" + "sync" + "time" + + "cosmossdk.io/log" + + "github.com/initia-labs/minievm/app" + "github.com/initia-labs/minievm/jsonrpc/backend" + rpctypes "github.com/initia-labs/minievm/jsonrpc/types" + + "github.com/ethereum/go-ethereum/common" + coretypes "github.com/ethereum/go-ethereum/core/types" + ethfilters "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/rpc" +) + +var ( + errFilterNotFound = errors.New("filter not found") + errInvalidBlockRange = errors.New("invalid block range params") + errExceedMaxTopics = errors.New("exceed max topics") +) + +// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0 +const maxTopics = 4 + +type filter struct { + ty ethfilters.Type + hashes []common.Hash + fullTx bool + txs []*rpctypes.RPCTransaction + crit ethfilters.FilterCriteria + logs []*coretypes.Log + + // lastUsed is the time the filter was last used + lastUsed time.Time +} + +// FilterAPI is the eth_ filter namespace API +type FilterAPI struct { + app *app.MinitiaApp + backend *backend.JSONRPCBackend + + logger log.Logger + + filtersMu sync.Mutex + filters map[rpc.ID]*filter + + // channels for block and log events + blockChan chan *coretypes.Header + logsChan chan []*coretypes.Log + pendingChan chan *rpctypes.RPCTransaction +} + +// NewFiltersAPI returns a new instance +func NewFilterAPI(app *app.MinitiaApp, backend *backend.JSONRPCBackend, logger log.Logger) *FilterAPI { + logger = logger.With("api", "filter") + api := &FilterAPI{ + app: app, + backend: backend, + + logger: logger, + + filters: make(map[rpc.ID]*filter), + } + + go api.clearUnusedFilters() + + api.blockChan, api.logsChan, api.pendingChan = app.EVMIndexer().Subscribe() + go api.subscribeEvents() + + return api +} + +// clearUnusedFilters removes filters that have not been used for 5 minutes +func (api *FilterAPI) clearUnusedFilters() { + const timeout = 5 * time.Minute + + for { + time.Sleep(timeout) + api.filtersMu.Lock() + for id, f := range api.filters { + if time.Since(f.lastUsed) > 5*time.Minute { + delete(api.filters, id) + } + } + api.filtersMu.Unlock() + } +} + +func (api *FilterAPI) subscribeEvents() { + for { + select { + case block := <-api.blockChan: + api.filtersMu.Lock() + for _, f := range api.filters { + if f.ty == ethfilters.BlocksSubscription { + f.hashes = append(f.hashes, block.Hash()) + } + } + api.filtersMu.Unlock() + case logs := <-api.logsChan: + api.filtersMu.Lock() + for _, f := range api.filters { + if f.ty == ethfilters.LogsSubscription { + logs = filterLogs(logs, f.crit.FromBlock, f.crit.ToBlock, f.crit.Addresses, f.crit.Topics) + if len(logs) > 0 { + f.logs = append(f.logs, logs...) + } + } + } + api.filtersMu.Unlock() + case tx := <-api.pendingChan: + api.filtersMu.Lock() + for _, f := range api.filters { + if f.ty == ethfilters.PendingTransactionsSubscription { + if f.fullTx { + f.txs = append(f.txs, tx) + } else { + f.hashes = append(f.hashes, tx.Hash) + } + } + } + api.filtersMu.Unlock() + } + } +} + +// NewPendingTransactionFilter creates a filter that fetches pending transactions +// as transactions enter the pending state. +// +// It is part of the filter package because this filter can be used through the +// `eth_getFilterChanges` polling method that is also used for log filters. +func (api *FilterAPI) NewPendingTransactionFilter(fullTx *bool) rpc.ID { + id := rpc.NewID() + api.filtersMu.Lock() + api.filters[id] = &filter{ + ty: ethfilters.PendingTransactionsSubscription, + fullTx: fullTx != nil && *fullTx, + txs: make([]*rpctypes.RPCTransaction, 0), + hashes: make([]common.Hash, 0), + } + api.filtersMu.Unlock() + + return id +} + +// NewBlockFilter creates a filter that fetches blocks that are imported into the chain. +// It is part of the filter package since polling goes with eth_getFilterChanges. +func (api *FilterAPI) NewBlockFilter() rpc.ID { + id := rpc.NewID() + api.filtersMu.Lock() + api.filters[id] = &filter{ + ty: ethfilters.BlocksSubscription, + hashes: make([]common.Hash, 0), + } + api.filtersMu.Unlock() + + return id +} + +// NewFilter creates a new filter and returns the filter id. It can be +// used to retrieve logs when the state changes. This method cannot be +// used to fetch logs that are already stored in the state. +// +// Default criteria for the from and to block are "latest". +// Using "latest" as block number will return logs for mined blocks. +// +// In case "fromBlock" > "toBlock" an error is returned. +func (api *FilterAPI) NewFilter(crit ethfilters.FilterCriteria) (rpc.ID, error) { + if len(crit.Topics) > maxTopics { + return "", errExceedMaxTopics + } + + var from, to rpc.BlockNumber + if crit.FromBlock == nil { + from = rpc.LatestBlockNumber + } else { + from = rpc.BlockNumber(crit.FromBlock.Int64()) + } + if crit.ToBlock == nil { + to = rpc.LatestBlockNumber + } else { + to = rpc.BlockNumber(crit.ToBlock.Int64()) + } + + // we don't support pending logs + if !(from == rpc.LatestBlockNumber && to == rpc.LatestBlockNumber) && + !(from >= 0 && to >= 0 && to >= from) && + !(from >= 0 && to == rpc.LatestBlockNumber) { + return "", errInvalidBlockRange + } + + id := rpc.NewID() + api.filtersMu.Lock() + api.filters[id] = &filter{ + ty: ethfilters.LogsSubscription, + crit: crit, lastUsed: time.Now(), + logs: make([]*coretypes.Log, 0), + } + api.filtersMu.Unlock() + + return id, nil +} + +// GetLogs returns logs matching the given argument that are stored within the state. +func (api *FilterAPI) GetLogs(ctx context.Context, crit ethfilters.FilterCriteria) ([]*coretypes.Log, error) { + api.backend.RPCFilterCap() + if len(crit.Topics) > maxTopics { + return nil, errExceedMaxTopics + } + var filter *Filter + if crit.BlockHash != nil { + // Block filter requested, construct a single-shot filter + filter = newBlockFilter(api.logger, api.backend, *crit.BlockHash, crit.Addresses, crit.Topics) + } else { + // Convert the RPC block numbers into internal representations + begin := rpc.LatestBlockNumber.Int64() + if crit.FromBlock != nil { + begin = crit.FromBlock.Int64() + } + end := rpc.LatestBlockNumber.Int64() + if crit.ToBlock != nil { + end = crit.ToBlock.Int64() + } + if begin > 0 && end > 0 && begin > end { + return nil, errInvalidBlockRange + } + // Construct the range filter + filter = newRangeFilter(api.logger, api.backend, begin, end, crit.Addresses, crit.Topics) + } + + // Run the filter and return all the logs + logs, err := filter.Logs(ctx, int64(api.backend.RPCBlockRangeCap())) + if err != nil { + return nil, err + } + return returnLogs(logs), err +} + +// UninstallFilter removes the filter with the given filter id. +func (api *FilterAPI) UninstallFilter(id rpc.ID) bool { + api.filtersMu.Lock() + _, found := api.filters[id] + delete(api.filters, id) + api.filtersMu.Unlock() + return found +} + +// GetFilterLogs returns the logs for the filter with the given id. +// If the filter could not be found an empty array of logs is returned. +func (api *FilterAPI) GetFilterLogs(ctx context.Context, id rpc.ID) ([]*coretypes.Log, error) { + api.filtersMu.Lock() + f, found := api.filters[id] + api.filtersMu.Lock() + + if !found || f.ty != ethfilters.LogsSubscription { + return nil, errFilterNotFound + } + + var bloomFilter *Filter + if f.crit.BlockHash != nil { + // Block filter requested, construct a single-shot filter + bloomFilter = newBlockFilter(api.logger, api.backend, *f.crit.BlockHash, f.crit.Addresses, f.crit.Topics) + } else { + // Convert the RPC block numbers into internal representations + begin := rpc.LatestBlockNumber.Int64() + if f.crit.FromBlock != nil { + begin = f.crit.FromBlock.Int64() + } + end := rpc.LatestBlockNumber.Int64() + if f.crit.ToBlock != nil { + end = f.crit.ToBlock.Int64() + } + // Construct the range filter + bloomFilter = newRangeFilter(api.logger, api.backend, begin, end, f.crit.Addresses, f.crit.Topics) + } + + // Run the filter and return all the logs + logs, err := bloomFilter.Logs(ctx, int64(api.backend.RPCBlockRangeCap())) + if err != nil { + return nil, err + } + + return returnLogs(logs), nil +} + +// GetFilterChanges returns the logs for the filter with the given id since +// last time it was called. This can be used for polling. +// +// For pending transaction and block filters the result is []common.Hash. +// (pending)Log filters return []Log. +func (api *FilterAPI) GetFilterChanges(id rpc.ID) (interface{}, error) { + api.filtersMu.Lock() + defer api.filtersMu.Unlock() + + f, ok := api.filters[id] + if !ok { + return []interface{}{}, errFilterNotFound + } + + f.lastUsed = time.Now() + + switch f.ty { + case ethfilters.BlocksSubscription: + hashes := f.hashes + f.hashes = nil + + return returnHashes(hashes), nil + case ethfilters.LogsSubscription: + logs := f.logs + f.logs = nil + + return returnLogs(logs), nil + case ethfilters.PendingTransactionsSubscription: + if f.fullTx { + txs := f.txs + f.txs = nil + + return txs, nil + } + + hashes := f.hashes + f.hashes = nil + + return returnHashes(hashes), nil + } + + return []interface{}{}, errFilterNotFound +} + +// returnLogs is a helper that will return an empty log array in case the given logs array is nil, +// otherwise the given logs array is returned. +func returnLogs(logs []*coretypes.Log) []*coretypes.Log { + if logs == nil { + return []*coretypes.Log{} + } + return logs +} + +// returnHashes is a helper that will return an empty hash array case the given hash array is nil, +// otherwise the given hashes array is returned. +func returnHashes(hashes []common.Hash) []common.Hash { + if hashes == nil { + return []common.Hash{} + } + return hashes +} diff --git a/jsonrpc/namespaces/eth/filters/filter.go b/jsonrpc/namespaces/eth/filters/filter.go new file mode 100644 index 0000000..9879ab3 --- /dev/null +++ b/jsonrpc/namespaces/eth/filters/filter.go @@ -0,0 +1,282 @@ +package filters + +import ( + "context" + "errors" + "fmt" + "math/big" + + "cosmossdk.io/log" + + "github.com/ethereum/go-ethereum/common" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/initia-labs/minievm/jsonrpc/backend" +) + +// BloomIV represents the bit indexes and value inside the bloom filter that belong +// to some key. +type BloomIV struct { + I [3]uint + V [3]byte +} + +// Filter can be used to retrieve and filter logs. +type Filter struct { + logger log.Logger + backend *backend.JSONRPCBackend + + addresses []common.Address + topics [][]common.Hash + + block *common.Hash + begin, end int64 +} + +// newBlockFilter creates a new filter which directly inspects the contents of +// a block to figure out whether it is interesting or not. +func newBlockFilter(logger log.Logger, backend *backend.JSONRPCBackend, block common.Hash, addresses []common.Address, topics [][]common.Hash) *Filter { + filter := newFilter(logger, backend, addresses, topics) + filter.block = &block + + return filter +} + +// newRangeFilter creates a new filter which uses a bloom filter on blocks to +// figure out whether a particular block is interesting or not. +func newRangeFilter(logger log.Logger, backend *backend.JSONRPCBackend, begin, end int64, addresses []common.Address, topics [][]common.Hash) *Filter { + filter := newFilter(logger, backend, addresses, topics) + filter.begin = begin + filter.end = end + + return filter +} + +// newFilter returns a new Filter +func newFilter( + logger log.Logger, + backend *backend.JSONRPCBackend, + addresses []common.Address, + topics [][]common.Hash, +) *Filter { + return &Filter{ + logger: logger, + backend: backend, + addresses: addresses, + topics: topics, + } +} + +// Logs searches the blockchain for matching log entries, returning all from the +// first block that contains matches, updating the start of the filter accordingly. +func (f *Filter) Logs(ctx context.Context, blockLimit int64) ([]*coretypes.Log, error) { + var err error + + // If we're doing singleton block filtering, execute and return + if f.block != nil && *f.block != (common.Hash{}) { + header, err := f.backend.GetHeaderByHash(*f.block) + if err != nil { + return nil, fmt.Errorf("failed to fetch block header by hash %s: %w", f.block, err) + } + if header == nil { + return nil, errors.New("unknown block") + } + return f.blockLogs(header) + } + + // Figure out the limits of the filter range + header, err := f.backend.GetHeaderByNumber(rpc.LatestBlockNumber) + if err != nil { + return nil, fmt.Errorf("failed to fetch header by number (latest): %w", err) + } + if header == nil || header.Number == nil { + f.logger.Debug("header not found or has no number") + return nil, nil + } + + head := header.Number.Int64() + + // resolve special + if f.begin < 0 { + f.begin = head + } else if f.begin == 0 { + f.begin = 1 + } + if f.end < 0 { + f.end = head + } else if f.end == 0 { + f.end = 1 + } + if f.end < f.begin { + return nil, fmt.Errorf("invalid range [%d, %d]", f.begin, f.end) + } + if f.end-f.begin > blockLimit { + return nil, fmt.Errorf("maximum [begin, end] blocks distance: %d", blockLimit) + } + + // check bounds + if f.begin > head { + return []*coretypes.Log{}, nil + } else if f.end > head { + f.end = head + } + + logChan, errChan := f.rangeLogsAsync(ctx) + var logs []*coretypes.Log + for { + select { + case log := <-logChan: + logs = append(logs, log) + case err := <-errChan: + if err != nil { + // if an error occurs during extraction, we do return the extracted data + return logs, err + } + return logs, nil + } + } +} + +// rangeLogsAsync retrieves block-range logs that match the filter criteria asynchronously, +// it creates and returns two channels: one for delivering log data, and one for reporting errors. +func (f *Filter) rangeLogsAsync(ctx context.Context) (chan *coretypes.Log, chan error) { + var ( + logChan = make(chan *coretypes.Log) + errChan = make(chan error) + ) + + go func() { + defer func() { + close(errChan) + close(logChan) + }() + + // Gather all non indexed ones + if err := f.unindexedLogs(ctx, uint64(f.end), logChan); err != nil { + errChan <- err + return + } + + errChan <- nil + }() + + return logChan, errChan +} + +// unindexedLogs returns the logs matching the filter criteria based on raw block +// iteration and bloom matching. +func (f *Filter) unindexedLogs(ctx context.Context, end uint64, logChan chan *coretypes.Log) error { + for ; f.begin <= int64(end); f.begin++ { + header, err := f.backend.GetHeaderByNumber(rpc.BlockNumber(f.begin)) + if header == nil || err != nil { + return err + } + found, err := f.blockLogs(header) + if err != nil { + return err + } + for _, log := range found { + select { + case logChan <- log: + case <-ctx.Done(): + return ctx.Err() + } + } + } + return nil +} + +// blockLogs returns the logs matching the filter criteria within a single block. +func (f *Filter) blockLogs(header *coretypes.Header) ([]*coretypes.Log, error) { + if bloomFilter(header.Bloom, f.addresses, f.topics) { + return f.checkMatches(header) + } + return nil, nil +} + +// checkMatches checks if the receipts belonging to the given header contain any log events that +// match the filter criteria. This function is called when the bloom filter signals a potential match. +func (f *Filter) checkMatches(header *coretypes.Header) ([]*coretypes.Log, error) { + logs, err := f.backend.GetLogsByHeight(header.Number.Uint64()) + if err != nil { + return nil, err + } + + logs = filterLogs(logs, nil, nil, f.addresses, f.topics) + return logs, nil +} + +// filterLogs creates a slice of logs matching the given criteria. +func filterLogs(logs []*coretypes.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*coretypes.Log { + var check = func(log *coretypes.Log) bool { + if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber { + return false + } + if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber { + return false + } + if len(addresses) > 0 && !includes(addresses, log.Address) { + return false + } + // If the to filtered topics is greater than the amount of topics in logs, skip. + if len(topics) > len(log.Topics) { + return false + } + for i, sub := range topics { + if len(sub) == 0 { + continue // empty rule set == wildcard + } + if !includes(sub, log.Topics[i]) { + return false + } + } + return true + } + var ret []*coretypes.Log + for _, log := range logs { + if check(log) { + ret = append(ret, log) + } + } + return ret +} + +// includes returns true if the element is present in the list. +func includes[T comparable](things []T, element T) bool { + for _, thing := range things { + if thing == element { + return true + } + } + return false +} + +func bloomFilter(bloom coretypes.Bloom, addresses []common.Address, topics [][]common.Hash) bool { + if len(addresses) > 0 { + var included bool + for _, addr := range addresses { + if coretypes.BloomLookup(bloom, addr) { + included = true + break + } + } + if !included { + return false + } + } + + for _, sub := range topics { + included := len(sub) == 0 // empty rule set == wildcard + for _, topic := range sub { + if coretypes.BloomLookup(bloom, topic) { + included = true + break + } + } + if !included { + return false + } + } + return true +} diff --git a/jsonrpc/namespaces/net/api.go b/jsonrpc/namespaces/net/api.go new file mode 100644 index 0000000..557beaf --- /dev/null +++ b/jsonrpc/namespaces/net/api.go @@ -0,0 +1,52 @@ +package net + +import ( + "context" + + "cosmossdk.io/log" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/initia-labs/minievm/jsonrpc/backend" +) + +// NetEthereumAPI is the net namespace for the Ethereum JSON-RPC APIs. +// Current it is used for tracking what APIs should be implemented for Ethereum compatibility. +// After fully implementing the Ethereum APIs, this interface can be removed. +type NetEthereumAPI interface { + Listening() bool + PeerCount() hexutil.Uint + Version() string +} + +type NetAPI struct { + ctx context.Context + logger log.Logger + backend *backend.JSONRPCBackend +} + +// NewNetAPI creates a new net API instance +func NewNetAPI(logger log.Logger, backend *backend.JSONRPCBackend) *NetAPI { + return &NetAPI{ + ctx: context.TODO(), + logger: logger, + backend: backend, + } +} + +// TODO: implement net_listening +//func (api *NetAPI) Listening() bool { +// return true +//} + +// TODO: implement net_peerCount +//func (api *NetAPI) PeerCount() hexutil.Uint { +// return hexutil.Uint(0) +//} + +func (api *NetAPI) Version() string { + v, err := api.backend.Version() + if err != nil { + api.logger.Error("failed to get version", "err", err) + return "1" + } + return v +} diff --git a/jsonrpc/namespaces/txpool/api.go b/jsonrpc/namespaces/txpool/api.go new file mode 100644 index 0000000..f426006 --- /dev/null +++ b/jsonrpc/namespaces/txpool/api.go @@ -0,0 +1,57 @@ +package txpool + +import ( + "context" + + "cosmossdk.io/log" + "github.com/initia-labs/minievm/jsonrpc/backend" +) + +var _ TxpoolEthereumAPI = (*TxPoolAPI)(nil) + +// TxpoolEthereumAPI is the txpool namespace for the Ethereum JSON-RPC APIs. +// Current it is used for tracking what APIs should be implemented for Ethereum compatibility. +// After fully implementing the Ethereum APIs, this interface can be removed. +type TxpoolEthereumAPI interface { + // TODO: implement the following apis + //Content() map[string]map[string]map[string]*rpctypes.RPCTransaction + //ContentFrom() map[string]map[string]*rpctypes.RPCTransaction + //Inspect() map[string]map[string]map[string]string + //Status() map[string]hexutil.Uint +} + +// TxPoolAPI is the txpool namespace for the Ethereum JSON-RPC APIs. +type TxPoolAPI struct { + ctx context.Context + logger log.Logger + backend *backend.JSONRPCBackend +} + +// NewTxPoolAPI creates a new txpool API instance. +func NewTxPoolAPI(logger log.Logger, backend *backend.JSONRPCBackend) *TxPoolAPI { + return &TxPoolAPI{ + ctx: context.TODO(), + logger: logger, + backend: backend, + } +} + +// TODO: implement txpool_content +//func (api *TxPoolAPI) Content() map[string]map[string]map[string]*rpctypes.RPCTransaction { +// return nil +//} + +// TODO: implement txpool_contentFrom +//func (api *TxPoolAPI) ContentFrom() map[string]map[string]*rpctypes.RPCTransaction { +// return nil +//} + +// TODO: implement txpool_inspect +//func (api *TxPoolAPI) Inspect() map[string]map[string]map[string]string { +// return nil +//} + +// TODO: implement txpool_status +//func (api *TxPoolAPI) Status() map[string]hexutil.Uint { +// return nil +//} diff --git a/jsonrpc/types/overrides.go b/jsonrpc/types/overrides.go new file mode 100644 index 0000000..be2ed70 --- /dev/null +++ b/jsonrpc/types/overrides.go @@ -0,0 +1,113 @@ +package types + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/holiman/uint256" +) + +// OverrideAccount indicates the overriding fields of account during the execution +// of a message call. +// Note, state and stateDiff can't be specified at the same time. If state is +// set, message execution will only use the data in the given state. Otherwise +// if statDiff is set, all diff will be applied first and then execute the call +// message. +type OverrideAccount struct { + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance **hexutil.Big `json:"balance"` + State *map[common.Hash]common.Hash `json:"state"` + StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` +} + +// StateOverride is the collection of overridden accounts. +type StateOverride map[common.Address]OverrideAccount + +// Apply overrides the fields of specified accounts into the given state. +func (diff *StateOverride) Apply(statedb *state.StateDB) error { + if diff == nil { + return nil + } + for addr, account := range *diff { + // Override account nonce. + if account.Nonce != nil { + statedb.SetNonce(addr, uint64(*account.Nonce)) + } + // Override account(contract) code. + if account.Code != nil { + statedb.SetCode(addr, *account.Code) + } + // Override account balance. + if account.Balance != nil { + u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance)) + statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified) + } + if account.State != nil && account.StateDiff != nil { + return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) + } + // Replace entire state if caller requires. + if account.State != nil { + statedb.SetStorage(addr, *account.State) + } + // Apply state diff into specified accounts. + if account.StateDiff != nil { + for key, value := range *account.StateDiff { + statedb.SetState(addr, key, value) + } + } + } + // Now finalize the changes. Finalize is normally performed between transactions. + // By using finalize, the overrides are semantically behaving as + // if they were created in a transaction just before the tracing occur. + statedb.Finalise(false) + return nil +} + +// BlockOverrides is a set of header fields to override. +type BlockOverrides struct { + Number *hexutil.Big + Difficulty *hexutil.Big + Time *hexutil.Uint64 + GasLimit *hexutil.Uint64 + Coinbase *common.Address + Random *common.Hash + BaseFee *hexutil.Big + BlobBaseFee *hexutil.Big +} + +// Apply overrides the given header fields into the given block context. +func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) { + if diff == nil { + return + } + if diff.Number != nil { + blockCtx.BlockNumber = diff.Number.ToInt() + } + if diff.Difficulty != nil { + blockCtx.Difficulty = diff.Difficulty.ToInt() + } + if diff.Time != nil { + blockCtx.Time = uint64(*diff.Time) + } + if diff.GasLimit != nil { + blockCtx.GasLimit = uint64(*diff.GasLimit) + } + if diff.Coinbase != nil { + blockCtx.Coinbase = *diff.Coinbase + } + if diff.Random != nil { + blockCtx.Random = diff.Random + } + if diff.BaseFee != nil { + blockCtx.BaseFee = diff.BaseFee.ToInt() + } + if diff.BlobBaseFee != nil { + blockCtx.BlobBaseFee = diff.BlobBaseFee.ToInt() + } +} diff --git a/jsonrpc/types/transaction_args.go b/jsonrpc/types/transaction_args.go new file mode 100644 index 0000000..be8ae24 --- /dev/null +++ b/jsonrpc/types/transaction_args.go @@ -0,0 +1,66 @@ +package types + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" +) + +// TransactionArgs represents the arguments to construct a new transaction +// or a message call. +type TransactionArgs struct { + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Value *hexutil.Big `json:"value"` + Nonce *hexutil.Uint64 `json:"nonce"` + + // We accept "data" and "input" for backwards-compatibility reasons. + // "input" is the newer name and should be preferred by clients. + // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input"` +} + +// from retrieves the transaction sender address. +func (args *TransactionArgs) GetFrom() common.Address { + if args.From == nil { + return common.Address{} + } + return *args.From +} + +// data retrieves the transaction calldata. Input field is preferred. +func (args *TransactionArgs) GetData() []byte { + if args.Input != nil { + return *args.Input + } + if args.Data != nil { + return *args.Data + } + return nil +} + +// CallDefaults sanitizes the transaction arguments, often filling in zero values, +// for the purpose of eth_call class of RPC methods. +func (args *TransactionArgs) CallDefaults() { + if args.Nonce == nil { + args.Nonce = new(hexutil.Uint64) + } + if args.Value == nil { + args.Value = new(hexutil.Big) + } +} + +// String returns the struct in a string format. +func (args *TransactionArgs) String() string { + return fmt.Sprintf( + "TransactionArgs{From:%v, To:%v, Value:%v, Nonce:%v, Data:%v, Input:%v}", + args.From, + args.To, + args.Value, + args.Nonce, + args.Data, + args.Input, + ) +} diff --git a/jsonrpc/types/tx.go b/jsonrpc/types/tx.go new file mode 100644 index 0000000..070ee31 --- /dev/null +++ b/jsonrpc/types/tx.go @@ -0,0 +1,84 @@ +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + coretypes "github.com/ethereum/go-ethereum/core/types" +) + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *coretypes.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` + YParity *hexutil.Uint64 `json:"yParity,omitempty"` +} + +func NewRPCTransaction(tx *coretypes.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, chainID *big.Int) *RPCTransaction { + signer := coretypes.LatestSignerForChainID(chainID) + from, _ := coretypes.Sender(signer, tx) + v, r, s := tx.RawSignatureValues() + al := tx.AccessList() + yparity := hexutil.Uint64(v.Sign()) + + result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + From: from, + Gas: hexutil.Uint64(tx.Gas()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + GasFeeCap: (*hexutil.Big)(tx.GasFeeCap()), + GasTipCap: (*hexutil.Big)(tx.GasTipCap()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + ChainID: (*hexutil.Big)(chainID), + Accesses: &al, + YParity: &yparity, + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + + return result +} + +func (rpcTx RPCTransaction) ToTransaction() *coretypes.Transaction { + return coretypes.NewTx(&coretypes.LegacyTx{ + Nonce: uint64(rpcTx.Nonce), + GasPrice: rpcTx.GasPrice.ToInt(), + Gas: uint64(rpcTx.Gas), + To: rpcTx.To, + Value: rpcTx.Value.ToInt(), + Data: rpcTx.Input, + V: rpcTx.V.ToInt(), + R: rpcTx.R.ToInt(), + S: rpcTx.S.ToInt(), + }) +} diff --git a/proto/minievm/evm/v1/query.proto b/proto/minievm/evm/v1/query.proto index a1eb249..95ce6b6 100644 --- a/proto/minievm/evm/v1/query.proto +++ b/proto/minievm/evm/v1/query.proto @@ -22,10 +22,12 @@ service Query { option (google.api.http).get = "/minievm/evm/v1/states/{contract_addr}/{key}"; } + // ContractAddrByDenom gets the contract address by denom. rpc ContractAddrByDenom(QueryContractAddrByDenomRequest) returns (QueryContractAddrByDenomResponse) { option (google.api.http).get = "/minievm/evm/v1/contracts/by_denom"; } + // Denom gets the denom of the given contract address. rpc Denom(QueryDenomRequest) returns (QueryDenomResponse) { option (google.api.http).get = "/minievm/evm/v1/denoms/{contract_addr}"; } @@ -84,9 +86,15 @@ message QueryCallRequest { string contract_addr = 2; // hex encoded call input string input = 3; + // Value is the amount of fee denom token to transfer to the contract. + string value = 4 [ + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; // whether to trace the call // `nil` means no trace - TraceOptions trace_options = 4; + TraceOptions trace_options = 5; } // TraceOption is the option for tracing diff --git a/proto/minievm/evm/v1/tx.proto b/proto/minievm/evm/v1/tx.proto index e1af3fd..68bfea3 100644 --- a/proto/minievm/evm/v1/tx.proto +++ b/proto/minievm/evm/v1/tx.proto @@ -34,6 +34,14 @@ message MsgCreate { // Code is hex encoded raw contract bytes code. string code = 2; + + // Value is the amount of fee denom token to transfer to the contract. + string value = 3 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; } // MsgCreateResponse defines the Msg/Create response type. @@ -57,6 +65,14 @@ message MsgCreate2 { // Salt is a random value to distinguish contract creation. uint64 salt = 3; + + // Value is the amount of fee denom token to transfer to the contract. + string value = 4 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; } // MsgCreate2Response defines the Msg/Create2 response type. @@ -81,6 +97,14 @@ message MsgCall { // Hex encoded execution input bytes. string input = 3; + + // Value is the amount of fee denom token to transfer to the contract. + string value = 4 [ + (cosmos_proto.scalar) = "cosmos.Int", + (gogoproto.customtype) = "cosmossdk.io/math.Int", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; } // MsgCallResponse defines the Msg/Call response type. diff --git a/proto/minievm/evm/v1/types.proto b/proto/minievm/evm/v1/types.proto index cdcd2cb..b544752 100644 --- a/proto/minievm/evm/v1/types.proto +++ b/proto/minievm/evm/v1/types.proto @@ -30,7 +30,9 @@ message Params { (gogoproto.moretags) = "yaml:\"allowed_custom_erc20s\"", (amino.dont_omitempty) = true ]; - ; + + // fee_denom defines the fee denom for the evm transactions + string fee_denom = 5 [(gogoproto.moretags) = "yaml:\"fee_denom\""]; } // Log represents a contract log event. These events are generated by diff --git a/x/evm/contracts/counter/Counter.go b/x/evm/contracts/counter/Counter.go index f8e6fee..9fc30f2 100644 --- a/x/evm/contracts/counter/Counter.go +++ b/x/evm/contracts/counter/Counter.go @@ -31,8 +31,8 @@ var ( // CounterMetaData contains all meta data concerning the Counter contract. var CounterMetaData = &bind.MetaData{ - ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCount\",\"type\":\"uint256\"}],\"name\":\"increased\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"callback_id\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"ibc_ack\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"callback_id\",\"type\":\"uint64\"}],\"name\":\"ibc_timeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"increase\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"req\",\"type\":\"string\"}],\"name\":\"query_cosmos\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"result\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561000f575f80fd5b506107cb8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610055575f3560e01c806306661abd146100595780630d4f1f9d1461007757806331a503f014610093578063cad23554146100af578063e8927fbc146100df575b5f80fd5b6100616100e9565b60405161006e9190610259565b60405180910390f35b610091600480360381019061008c91906102f5565b6100ee565b005b6100ad60048036038101906100a89190610333565b610135565b005b6100c960048036038101906100c4919061049a565b610159565b6040516100d6919061058a565b60405180910390f35b6100e76101e2565b005b5f5481565b801561011a578167ffffffffffffffff165f8082825461010e91906105d7565b92505081905550610131565b5f8081548092919061012b9061060a565b91905055505b5050565b8067ffffffffffffffff165f8082825461014f91906105d7565b9250508190555050565b606060f173ffffffffffffffffffffffffffffffffffffffff1663cad2355484846040518363ffffffff1660e01b8152600401610197929190610651565b5f604051808303815f875af11580156101b2573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906101da91906106f4565b905092915050565b5f808154809291906101f39061060a565b91905055507f61996fe196f72cb598c483e896a1221263a28bb630480aa89495f737d4a8e3df60015f54610227919061073b565b5f5460405161023792919061076e565b60405180910390a1565b5f819050919050565b61025381610241565b82525050565b5f60208201905061026c5f83018461024a565b92915050565b5f604051905090565b5f80fd5b5f80fd5b5f67ffffffffffffffff82169050919050565b61029f81610283565b81146102a9575f80fd5b50565b5f813590506102ba81610296565b92915050565b5f8115159050919050565b6102d4816102c0565b81146102de575f80fd5b50565b5f813590506102ef816102cb565b92915050565b5f806040838503121561030b5761030a61027b565b5b5f610318858286016102ac565b9250506020610329858286016102e1565b9150509250929050565b5f602082840312156103485761034761027b565b5b5f610355848285016102ac565b91505092915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103ac82610366565b810181811067ffffffffffffffff821117156103cb576103ca610376565b5b80604052505050565b5f6103dd610272565b90506103e982826103a3565b919050565b5f67ffffffffffffffff82111561040857610407610376565b5b61041182610366565b9050602081019050919050565b828183375f83830152505050565b5f61043e610439846103ee565b6103d4565b90508281526020810184848401111561045a57610459610362565b5b61046584828561041e565b509392505050565b5f82601f8301126104815761048061035e565b5b813561049184826020860161042c565b91505092915050565b5f80604083850312156104b0576104af61027b565b5b5f83013567ffffffffffffffff8111156104cd576104cc61027f565b5b6104d98582860161046d565b925050602083013567ffffffffffffffff8111156104fa576104f961027f565b5b6105068582860161046d565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561054757808201518184015260208101905061052c565b5f8484015250505050565b5f61055c82610510565b610566818561051a565b935061057681856020860161052a565b61057f81610366565b840191505092915050565b5f6020820190508181035f8301526105a28184610552565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6105e182610241565b91506105ec83610241565b9250828201905080821115610604576106036105aa565b5b92915050565b5f61061482610241565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610646576106456105aa565b5b600182019050919050565b5f6040820190508181035f8301526106698185610552565b9050818103602083015261067d8184610552565b90509392505050565b5f610698610693846103ee565b6103d4565b9050828152602081018484840111156106b4576106b3610362565b5b6106bf84828561052a565b509392505050565b5f82601f8301126106db576106da61035e565b5b81516106eb848260208601610686565b91505092915050565b5f602082840312156107095761070861027b565b5b5f82015167ffffffffffffffff8111156107265761072561027f565b5b610732848285016106c7565b91505092915050565b5f61074582610241565b915061075083610241565b9250828203905081811115610768576107676105aa565b5b92915050565b5f6040820190506107815f83018561024a565b61078e602083018461024a565b939250505056fea2646970667358221220ab434f24f747faa9977ce70064417eedf27920874d368a34f49515b3a13e60ef64736f6c63430008180033", + ABI: "[{\"inputs\":[],\"stateMutability\":\"payable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"oldCount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"newCount\",\"type\":\"uint256\"}],\"name\":\"increased\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"count\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"callback_id\",\"type\":\"uint64\"},{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"name\":\"ibc_ack\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"callback_id\",\"type\":\"uint64\"}],\"name\":\"ibc_timeout\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"increase\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"path\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"req\",\"type\":\"string\"}],\"name\":\"query_cosmos\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"result\",\"type\":\"string\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60806040526107ef806100115f395ff3fe608060405260043610610049575f3560e01c806306661abd1461004d5780630d4f1f9d1461007757806331a503f01461009f578063cad23554146100c7578063e8927fbc14610103575b5f80fd5b348015610058575f80fd5b5061006161010d565b60405161006e919061027d565b60405180910390f35b348015610082575f80fd5b5061009d60048036038101906100989190610319565b610112565b005b3480156100aa575f80fd5b506100c560048036038101906100c09190610357565b610159565b005b3480156100d2575f80fd5b506100ed60048036038101906100e891906104be565b61017d565b6040516100fa91906105ae565b60405180910390f35b61010b610206565b005b5f5481565b801561013e578167ffffffffffffffff165f8082825461013291906105fb565b92505081905550610155565b5f8081548092919061014f9061062e565b91905055505b5050565b8067ffffffffffffffff165f8082825461017391906105fb565b9250508190555050565b606060f173ffffffffffffffffffffffffffffffffffffffff1663cad2355484846040518363ffffffff1660e01b81526004016101bb929190610675565b5f604051808303815f875af11580156101d6573d5f803e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906101fe9190610718565b905092915050565b5f808154809291906102179061062e565b91905055507f61996fe196f72cb598c483e896a1221263a28bb630480aa89495f737d4a8e3df60015f5461024b919061075f565b5f5460405161025b929190610792565b60405180910390a1565b5f819050919050565b61027781610265565b82525050565b5f6020820190506102905f83018461026e565b92915050565b5f604051905090565b5f80fd5b5f80fd5b5f67ffffffffffffffff82169050919050565b6102c3816102a7565b81146102cd575f80fd5b50565b5f813590506102de816102ba565b92915050565b5f8115159050919050565b6102f8816102e4565b8114610302575f80fd5b50565b5f81359050610313816102ef565b92915050565b5f806040838503121561032f5761032e61029f565b5b5f61033c858286016102d0565b925050602061034d85828601610305565b9150509250929050565b5f6020828403121561036c5761036b61029f565b5b5f610379848285016102d0565b91505092915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6103d08261038a565b810181811067ffffffffffffffff821117156103ef576103ee61039a565b5b80604052505050565b5f610401610296565b905061040d82826103c7565b919050565b5f67ffffffffffffffff82111561042c5761042b61039a565b5b6104358261038a565b9050602081019050919050565b828183375f83830152505050565b5f61046261045d84610412565b6103f8565b90508281526020810184848401111561047e5761047d610386565b5b610489848285610442565b509392505050565b5f82601f8301126104a5576104a4610382565b5b81356104b5848260208601610450565b91505092915050565b5f80604083850312156104d4576104d361029f565b5b5f83013567ffffffffffffffff8111156104f1576104f06102a3565b5b6104fd85828601610491565b925050602083013567ffffffffffffffff81111561051e5761051d6102a3565b5b61052a85828601610491565b9150509250929050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561056b578082015181840152602081019050610550565b5f8484015250505050565b5f61058082610534565b61058a818561053e565b935061059a81856020860161054e565b6105a38161038a565b840191505092915050565b5f6020820190508181035f8301526105c68184610576565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61060582610265565b915061061083610265565b9250828201905080821115610628576106276105ce565b5b92915050565b5f61063882610265565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361066a576106696105ce565b5b600182019050919050565b5f6040820190508181035f83015261068d8185610576565b905081810360208301526106a18184610576565b90509392505050565b5f6106bc6106b784610412565b6103f8565b9050828152602081018484840111156106d8576106d7610386565b5b6106e384828561054e565b509392505050565b5f82601f8301126106ff576106fe610382565b5b815161070f8482602086016106aa565b91505092915050565b5f6020828403121561072d5761072c61029f565b5b5f82015167ffffffffffffffff81111561074a576107496102a3565b5b610756848285016106eb565b91505092915050565b5f61076982610265565b915061077483610265565b925082820390508181111561078c5761078b6105ce565b5b92915050565b5f6040820190506107a55f83018561026e565b6107b2602083018461026e565b939250505056fea2646970667358221220430ddfd244f3b0cac1ffcd58548c7a45cf36c9755c8a73b361424d043147130e64736f6c63430008180033", } // CounterABI is the input ABI used to generate the binding from. @@ -277,21 +277,21 @@ func (_Counter *CounterTransactorSession) IbcTimeout(callback_id uint64) (*types // Increase is a paid mutator transaction binding the contract method 0xe8927fbc. // -// Solidity: function increase() returns() +// Solidity: function increase() payable returns() func (_Counter *CounterTransactor) Increase(opts *bind.TransactOpts) (*types.Transaction, error) { return _Counter.contract.Transact(opts, "increase") } // Increase is a paid mutator transaction binding the contract method 0xe8927fbc. // -// Solidity: function increase() returns() +// Solidity: function increase() payable returns() func (_Counter *CounterSession) Increase() (*types.Transaction, error) { return _Counter.Contract.Increase(&_Counter.TransactOpts) } // Increase is a paid mutator transaction binding the contract method 0xe8927fbc. // -// Solidity: function increase() returns() +// Solidity: function increase() payable returns() func (_Counter *CounterTransactorSession) Increase() (*types.Transaction, error) { return _Counter.Contract.Increase(&_Counter.TransactOpts) } diff --git a/x/evm/contracts/counter/Counter.sol b/x/evm/contracts/counter/Counter.sol index df89cb7..ccfc710 100644 --- a/x/evm/contracts/counter/Counter.sol +++ b/x/evm/contracts/counter/Counter.sol @@ -9,7 +9,9 @@ contract Counter is IIBCAsyncCallback { event increased(uint256 oldCount, uint256 newCount); - function increase() external { + constructor() payable {} + + function increase() external payable { count++; emit increased(count - 1, count); @@ -27,7 +29,10 @@ contract Counter is IIBCAsyncCallback { count += callback_id; } - function query_cosmos(string memory path, string memory req) external returns (string memory result) { + function query_cosmos( + string memory path, + string memory req + ) external returns (string memory result) { return COSMOS_CONTRACT.query_cosmos(path, req); } } diff --git a/x/evm/contracts/custom_erc20/CustomERC20.go b/x/evm/contracts/custom_erc20/CustomERC20.go index 8952eb2..63c074e 100644 --- a/x/evm/contracts/custom_erc20/CustomERC20.go +++ b/x/evm/contracts/custom_erc20/CustomERC20.go @@ -31,8 +31,8 @@ var ( // CustomErc20MetaData contains all meta data concerning the CustomErc20 contract. var CustomErc20MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801562000010575f80fd5b5060405162001a0138038062001a018339818101604052810190620000369190620002ef565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060f273ffffffffffffffffffffffffffffffffffffffff16635e6c57596040518163ffffffff1660e01b81526004016020604051808303815f875af1158015620000c1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620000e79190620003c0565b508260039081620000f9919062000627565b5081600490816200010b919062000627565b508060055f6101000a81548160ff021916908360ff1602179055505050506200070b565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620001908262000148565b810181811067ffffffffffffffff82111715620001b257620001b162000158565b5b80604052505050565b5f620001c66200012f565b9050620001d4828262000185565b919050565b5f67ffffffffffffffff821115620001f657620001f562000158565b5b620002018262000148565b9050602081019050919050565b5f5b838110156200022d57808201518184015260208101905062000210565b5f8484015250505050565b5f6200024e6200024884620001d9565b620001bb565b9050828152602081018484840111156200026d576200026c62000144565b5b6200027a8482856200020e565b509392505050565b5f82601f83011262000299576200029862000140565b5b8151620002ab84826020860162000238565b91505092915050565b5f60ff82169050919050565b620002cb81620002b4565b8114620002d6575f80fd5b50565b5f81519050620002e981620002c0565b92915050565b5f805f6060848603121562000309576200030862000138565b5b5f84015167ffffffffffffffff8111156200032957620003286200013c565b5b620003378682870162000282565b935050602084015167ffffffffffffffff8111156200035b576200035a6200013c565b5b620003698682870162000282565b92505060406200037c86828701620002d9565b9150509250925092565b5f8115159050919050565b6200039c8162000386565b8114620003a7575f80fd5b50565b5f81519050620003ba8162000391565b92915050565b5f60208284031215620003d857620003d762000138565b5b5f620003e784828501620003aa565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200043f57607f821691505b602082108103620004555762000454620003fa565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004b97fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200047c565b620004c586836200047c565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200050f620005096200050384620004dd565b620004e6565b620004dd565b9050919050565b5f819050919050565b6200052a83620004ef565b62000542620005398262000516565b84845462000488565b825550505050565b5f90565b620005586200054a565b620005658184846200051f565b505050565b5b818110156200058c57620005805f826200054e565b6001810190506200056b565b5050565b601f821115620005db57620005a5816200045b565b620005b0846200046d565b81016020851015620005c0578190505b620005d8620005cf856200046d565b8301826200056a565b50505b505050565b5f82821c905092915050565b5f620005fd5f1984600802620005e0565b1980831691505092915050565b5f620006178383620005ec565b9150826002028217905092915050565b6200063282620003f0565b67ffffffffffffffff8111156200064e576200064d62000158565b5b6200065a825462000427565b6200066782828562000590565b5f60209050601f8311600181146200069d575f841562000688578287015190505b6200069485826200060a565b86555062000703565b601f198416620006ad866200045b565b5f5b82811015620006d657848901518255600182019150602085019450602081019050620006af565b86831015620006f65784890151620006f2601f891682620005ec565b8355505b6001600288020188555050505b505050505050565b6112e880620007195f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac14610213578063a9059cbb1461022f578063dd62ed3e1461025f578063f2fde38b1461028f576100cd565b806370a08231146101a75780638da5cb5b146101d757806395d89b41146101f5576100cd565b806306fdde03146100d1578063095ea7b3146100ef57806318160ddd1461011f57806323b872dd1461013d578063313ce5671461016d57806340c10f191461018b575b5f80fd5b6100d96102ab565b6040516100e69190610f0e565b60405180910390f35b61010960048036038101906101049190610fbf565b610337565b6040516101169190611017565b60405180910390f35b610127610424565b604051610134919061103f565b60405180910390f35b61015760048036038101906101529190611058565b61042a565b6040516101649190611017565b60405180910390f35b6101756106ca565b60405161018291906110c3565b60405180910390f35b6101a560048036038101906101a09190610fbf565b6106dc565b005b6101c160048036038101906101bc91906110dc565b610740565b6040516101ce919061103f565b60405180910390f35b6101df610755565b6040516101ec9190611116565b60405180910390f35b6101fd610778565b60405161020a9190610f0e565b60405180910390f35b61022d60048036038101906102289190610fbf565b610804565b005b61024960048036038101906102449190610fbf565b610868565b6040516102569190611017565b60405180910390f35b6102796004803603810190610274919061112f565b610a79565b604051610286919061103f565b60405180910390f35b6102a960048036038101906102a491906110dc565b610a99565b005b600380546102b89061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546102e49061119a565b801561032f5780601f106103065761010080835404028352916020019161032f565b820191905f5260205f20905b81548152906001019060200180831161031257829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610412919061103f565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016104669190611116565b602060405180830381865afa158015610481573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a591906111f4565b6105255760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016104e39190611116565b6020604051808303815f875af11580156104ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052391906111f4565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ac919061124c565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ff919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610652919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516106b6919061103f565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610732575f80fd5b61073c8282610be1565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600480546107859061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546107b19061119a565b80156107fc5780601f106107d3576101008083540402835291602001916107fc565b820191905f5260205f20905b8154815290600101906020018083116107df57829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a575f80fd5b6108648282610db0565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016108a49190611116565b602060405180830381865afa1580156108bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108e391906111f4565b6109635760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109219190611116565b6020604051808303815f875af115801561093d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061096191906111f4565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546109af919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a02919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610a66919061103f565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aef575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b26575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610c1c9190611116565b602060405180830381865afa158015610c37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5b91906111f4565b610cdb5760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610c999190611116565b6020604051808303815f875af1158015610cb5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cd991906111f4565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610d27919061127f565b925050819055508160065f828254610d3f919061127f565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610da3919061103f565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610dfc919061124c565b925050819055508060065f828254610e14919061124c565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610e78919061103f565b60405180910390a35050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610ebb578082015181840152602081019050610ea0565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610ee082610e84565b610eea8185610e8e565b9350610efa818560208601610e9e565b610f0381610ec6565b840191505092915050565b5f6020820190508181035f830152610f268184610ed6565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f5b82610f32565b9050919050565b610f6b81610f51565b8114610f75575f80fd5b50565b5f81359050610f8681610f62565b92915050565b5f819050919050565b610f9e81610f8c565b8114610fa8575f80fd5b50565b5f81359050610fb981610f95565b92915050565b5f8060408385031215610fd557610fd4610f2e565b5b5f610fe285828601610f78565b9250506020610ff385828601610fab565b9150509250929050565b5f8115159050919050565b61101181610ffd565b82525050565b5f60208201905061102a5f830184611008565b92915050565b61103981610f8c565b82525050565b5f6020820190506110525f830184611030565b92915050565b5f805f6060848603121561106f5761106e610f2e565b5b5f61107c86828701610f78565b935050602061108d86828701610f78565b925050604061109e86828701610fab565b9150509250925092565b5f60ff82169050919050565b6110bd816110a8565b82525050565b5f6020820190506110d65f8301846110b4565b92915050565b5f602082840312156110f1576110f0610f2e565b5b5f6110fe84828501610f78565b91505092915050565b61111081610f51565b82525050565b5f6020820190506111295f830184611107565b92915050565b5f806040838503121561114557611144610f2e565b5b5f61115285828601610f78565b925050602061116385828601610f78565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806111b157607f821691505b6020821081036111c4576111c361116d565b5b50919050565b6111d381610ffd565b81146111dd575f80fd5b50565b5f815190506111ee816111ca565b92915050565b5f6020828403121561120957611208610f2e565b5b5f611216848285016111e0565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61125682610f8c565b915061126183610f8c565b92508282039050818111156112795761127861121f565b5b92915050565b5f61128982610f8c565b915061129483610f8c565b92508282019050808211156112ac576112ab61121f565b5b9291505056fea2646970667358221220aa0b9a634aaecddb4168bd8251192a84271901ee8fef23c1eb72ab5ed45e3ab364736f6c63430008180033", + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801562000010575f80fd5b5060405162001bae38038062001bae8339818101604052810190620000369190620002ef565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060f273ffffffffffffffffffffffffffffffffffffffff16635e6c57596040518163ffffffff1660e01b81526004016020604051808303815f875af1158015620000c1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620000e79190620003c0565b508260039081620000f9919062000627565b5081600490816200010b919062000627565b508060055f6101000a81548160ff021916908360ff1602179055505050506200070b565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b620001908262000148565b810181811067ffffffffffffffff82111715620001b257620001b162000158565b5b80604052505050565b5f620001c66200012f565b9050620001d4828262000185565b919050565b5f67ffffffffffffffff821115620001f657620001f562000158565b5b620002018262000148565b9050602081019050919050565b5f5b838110156200022d57808201518184015260208101905062000210565b5f8484015250505050565b5f6200024e6200024884620001d9565b620001bb565b9050828152602081018484840111156200026d576200026c62000144565b5b6200027a8482856200020e565b509392505050565b5f82601f83011262000299576200029862000140565b5b8151620002ab84826020860162000238565b91505092915050565b5f60ff82169050919050565b620002cb81620002b4565b8114620002d6575f80fd5b50565b5f81519050620002e981620002c0565b92915050565b5f805f6060848603121562000309576200030862000138565b5b5f84015167ffffffffffffffff8111156200032957620003286200013c565b5b620003378682870162000282565b935050602084015167ffffffffffffffff8111156200035b576200035a6200013c565b5b620003698682870162000282565b92505060406200037c86828701620002d9565b9150509250925092565b5f8115159050919050565b6200039c8162000386565b8114620003a7575f80fd5b50565b5f81519050620003ba8162000391565b92915050565b5f60208284031215620003d857620003d762000138565b5b5f620003e784828501620003aa565b91505092915050565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200043f57607f821691505b602082108103620004555762000454620003fa565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620004b97fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200047c565b620004c586836200047c565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f6200050f620005096200050384620004dd565b620004e6565b620004dd565b9050919050565b5f819050919050565b6200052a83620004ef565b62000542620005398262000516565b84845462000488565b825550505050565b5f90565b620005586200054a565b620005658184846200051f565b505050565b5b818110156200058c57620005805f826200054e565b6001810190506200056b565b5050565b601f821115620005db57620005a5816200045b565b620005b0846200046d565b81016020851015620005c0578190505b620005d8620005cf856200046d565b8301826200056a565b50505b505050565b5f82821c905092915050565b5f620005fd5f1984600802620005e0565b1980831691505092915050565b5f620006178383620005ec565b9150826002028217905092915050565b6200063282620003f0565b67ffffffffffffffff8111156200064e576200064d62000158565b5b6200065a825462000427565b6200066782828562000590565b5f60209050601f8311600181146200069d575f841562000688578287015190505b6200069485826200060a565b86555062000703565b601f198416620006ad866200045b565b5f5b82811015620006d657848901518255600182019150602085019450602081019050620006af565b86831015620006f65784890151620006f2601f891682620005ec565b8355505b6001600288020188555050505b505050505050565b61149580620007195f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac1461025e578063a9059cbb1461027a578063dd62ed3e146102aa578063f2fde38b146102da576100e8565b806370a08231146101f25780638da5cb5b1461022257806395d89b4114610240576100e8565b806318160ddd116100c657806318160ddd1461016a57806323b872dd14610188578063313ce567146101b857806340c10f19146101d6576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063095ea7b31461013a575b5f80fd5b6101066004803603810190610101919061100a565b6102f6565b604051610113919061104f565b60405180910390f35b61012461036f565b60405161013191906110f2565b60405180910390f35b610154600480360381019061014f919061119f565b6103fb565b604051610161919061104f565b60405180910390f35b6101726104e8565b60405161017f91906111ec565b60405180910390f35b6101a2600480360381019061019d9190611205565b6104ee565b6040516101af919061104f565b60405180910390f35b6101c061078e565b6040516101cd9190611270565b60405180910390f35b6101f060048036038101906101eb919061119f565b6107a0565b005b61020c60048036038101906102079190611289565b610804565b60405161021991906111ec565b60405180910390f35b61022a610819565b60405161023791906112c3565b60405180910390f35b61024861083c565b60405161025591906110f2565b60405180910390f35b6102786004803603810190610273919061119f565b6108c8565b005b610294600480360381019061028f919061119f565b61092c565b6040516102a1919061104f565b60405180910390f35b6102c460048036038101906102bf91906112dc565b610b3d565b6040516102d191906111ec565b60405180910390f35b6102f460048036038101906102ef9190611289565b610b5d565b005b5f7f942e8b22000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610368575061036782610ca5565b5b9050919050565b6003805461037c90611347565b80601f01602080910402602001604051908101604052809291908181526020018280546103a890611347565b80156103f35780601f106103ca576101008083540402835291602001916103f3565b820191905f5260205f20905b8154815290600101906020018083116103d657829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104d691906111ec565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161052a91906112c3565b602060405180830381865afa158015610545573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061056991906113a1565b6105e95760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016105a791906112c3565b6020604051808303815f875af11580156105c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e791906113a1565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461067091906113f9565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546106c391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610716919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161077a91906111ec565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107f6575f80fd5b6108008282610d0e565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6004805461084990611347565b80601f016020809104026020016040519081016040528092919081815260200182805461087590611347565b80156108c05780601f10610897576101008083540402835291602001916108c0565b820191905f5260205f20905b8154815290600101906020018083116108a357829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091e575f80fd5b6109288282610edd565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161096891906112c3565b602060405180830381865afa158015610983573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a791906113a1565b610a275760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109e591906112c3565b6020604051808303815f875af1158015610a01573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2591906113a1565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a7391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610ac6919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610b2a91906111ec565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bb3575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bea575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610d4991906112c3565b602060405180830381865afa158015610d64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8891906113a1565b610e085760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610dc691906112c3565b6020604051808303815f875af1158015610de2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0691906113a1565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e54919061142c565b925050819055508160065f828254610e6c919061142c565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ed091906111ec565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610f2991906113f9565b925050819055508060065f828254610f4191906113f9565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610fa591906111ec565b60405180910390a35050565b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610fe981610fb5565b8114610ff3575f80fd5b50565b5f8135905061100481610fe0565b92915050565b5f6020828403121561101f5761101e610fb1565b5b5f61102c84828501610ff6565b91505092915050565b5f8115159050919050565b61104981611035565b82525050565b5f6020820190506110625f830184611040565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561109f578082015181840152602081019050611084565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6110c482611068565b6110ce8185611072565b93506110de818560208601611082565b6110e7816110aa565b840191505092915050565b5f6020820190508181035f83015261110a81846110ba565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61113b82611112565b9050919050565b61114b81611131565b8114611155575f80fd5b50565b5f8135905061116681611142565b92915050565b5f819050919050565b61117e8161116c565b8114611188575f80fd5b50565b5f8135905061119981611175565b92915050565b5f80604083850312156111b5576111b4610fb1565b5b5f6111c285828601611158565b92505060206111d38582860161118b565b9150509250929050565b6111e68161116c565b82525050565b5f6020820190506111ff5f8301846111dd565b92915050565b5f805f6060848603121561121c5761121b610fb1565b5b5f61122986828701611158565b935050602061123a86828701611158565b925050604061124b8682870161118b565b9150509250925092565b5f60ff82169050919050565b61126a81611255565b82525050565b5f6020820190506112835f830184611261565b92915050565b5f6020828403121561129e5761129d610fb1565b5b5f6112ab84828501611158565b91505092915050565b6112bd81611131565b82525050565b5f6020820190506112d65f8301846112b4565b92915050565b5f80604083850312156112f2576112f1610fb1565b5b5f6112ff85828601611158565b925050602061131085828601611158565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061135e57607f821691505b6020821081036113715761137061131a565b5b50919050565b61138081611035565b811461138a575f80fd5b50565b5f8151905061139b81611377565b92915050565b5f602082840312156113b6576113b5610fb1565b5b5f6113c38482850161138d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6114038261116c565b915061140e8361116c565b9250828203905081811115611426576114256113cc565b5b92915050565b5f6114368261116c565b91506114418361116c565b9250828201905080821115611459576114586113cc565b5b9291505056fea2646970667358221220b4dd1d8802dffa0485bc89cd679dc48dda5cbc64073a4cd2bcc4ac0dc6cf8c8f64736f6c63430008180033", } // CustomErc20ABI is the input ABI used to generate the binding from. @@ -357,6 +357,37 @@ func (_CustomErc20 *CustomErc20CallerSession) Owner() (common.Address, error) { return _CustomErc20.Contract.Owner(&_CustomErc20.CallOpts) } +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_CustomErc20 *CustomErc20Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _CustomErc20.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_CustomErc20 *CustomErc20Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _CustomErc20.Contract.SupportsInterface(&_CustomErc20.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_CustomErc20 *CustomErc20CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _CustomErc20.Contract.SupportsInterface(&_CustomErc20.CallOpts, interfaceId) +} + // Symbol is a free data retrieval call binding the contract method 0x95d89b41. // // Solidity: function symbol() view returns(string) diff --git a/x/evm/contracts/custom_erc20/CustomERC20.sol b/x/evm/contracts/custom_erc20/CustomERC20.sol index 69f79e4..c955413 100644 --- a/x/evm/contracts/custom_erc20/CustomERC20.sol +++ b/x/evm/contracts/custom_erc20/CustomERC20.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.24; import "../i_erc20/IERC20.sol"; import "../ownable/Ownable.sol"; import "../erc20_registry/ERC20Registry.sol"; +import {ERC165, IERC165} from "../erc165/ERC165.sol"; -contract CustomERC20 is IERC20, Ownable, ERC20Registry { +contract CustomERC20 is IERC20, Ownable, ERC20Registry, ERC165 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, @@ -20,7 +21,22 @@ contract CustomERC20 is IERC20, Ownable, ERC20Registry { uint8 public decimals; uint256 public totalSupply; - constructor(string memory _name, string memory _symbol, uint8 _decimals) register_erc20 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(IERC165, ERC165) returns (bool) { + return + interfaceId == type(IERC20).interfaceId || + super.supportsInterface(interfaceId); + } + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) register_erc20 { name = _name; symbol = _symbol; decimals = _decimals; @@ -54,7 +70,10 @@ contract CustomERC20 is IERC20, Ownable, ERC20Registry { return true; } - function _mint(address to, uint256 amount) internal register_erc20_store(to) { + function _mint( + address to, + uint256 amount + ) internal register_erc20_store(to) { balanceOf[to] += amount; totalSupply += amount; emit Transfer(address(0), to, amount); @@ -66,7 +85,7 @@ contract CustomERC20 is IERC20, Ownable, ERC20Registry { emit Transfer(from, address(0), amount); } - function mint(address to, uint256 amount) external onlyOwner{ + function mint(address to, uint256 amount) external onlyOwner { _mint(to, amount); } diff --git a/x/evm/contracts/erc20/ERC20.go b/x/evm/contracts/erc20/ERC20.go index 06056d5..6ef3b2c 100644 --- a/x/evm/contracts/erc20/ERC20.go +++ b/x/evm/contracts/erc20/ERC20.go @@ -31,8 +31,8 @@ var ( // Erc20MetaData contains all meta data concerning the Erc20 contract. var Erc20MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801562000010575f80fd5b50604051620019243803806200192483398181016040528101906200003691906200027c565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600390816200008691906200054a565b5081600490816200009891906200054a565b508060055f6101000a81548160ff021916908360ff1602179055505050506200062e565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200011d82620000d5565b810181811067ffffffffffffffff821117156200013f576200013e620000e5565b5b80604052505050565b5f62000153620000bc565b905062000161828262000112565b919050565b5f67ffffffffffffffff821115620001835762000182620000e5565b5b6200018e82620000d5565b9050602081019050919050565b5f5b83811015620001ba5780820151818401526020810190506200019d565b5f8484015250505050565b5f620001db620001d58462000166565b62000148565b905082815260208101848484011115620001fa57620001f9620000d1565b5b620002078482856200019b565b509392505050565b5f82601f830112620002265762000225620000cd565b5b815162000238848260208601620001c5565b91505092915050565b5f60ff82169050919050565b620002588162000241565b811462000263575f80fd5b50565b5f8151905062000276816200024d565b92915050565b5f805f60608486031215620002965762000295620000c5565b5b5f84015167ffffffffffffffff811115620002b657620002b5620000c9565b5b620002c4868287016200020f565b935050602084015167ffffffffffffffff811115620002e857620002e7620000c9565b5b620002f6868287016200020f565b9250506040620003098682870162000266565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200036257607f821691505b6020821081036200037857620003776200031d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003dc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200039f565b620003e886836200039f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004326200042c620004268462000400565b62000409565b62000400565b9050919050565b5f819050919050565b6200044d8362000412565b620004656200045c8262000439565b848454620003ab565b825550505050565b5f90565b6200047b6200046d565b6200048881848462000442565b505050565b5b81811015620004af57620004a35f8262000471565b6001810190506200048e565b5050565b601f821115620004fe57620004c8816200037e565b620004d38462000390565b81016020851015620004e3578190505b620004fb620004f28562000390565b8301826200048d565b50505b505050565b5f82821c905092915050565b5f620005205f198460080262000503565b1980831691505092915050565b5f6200053a83836200050f565b9150826002028217905092915050565b620005558262000313565b67ffffffffffffffff811115620005715762000570620000e5565b5b6200057d82546200034a565b6200058a828285620004b3565b5f60209050601f831160018114620005c0575f8415620005ab578287015190505b620005b785826200052d565b86555062000626565b601f198416620005d0866200037e565b5f5b82811015620005f957848901518255600182019150602085019450602081019050620005d2565b8683101562000619578489015162000615601f8916826200050f565b8355505b6001600288020188555050505b505050505050565b6112e8806200063c5f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac14610213578063a9059cbb1461022f578063dd62ed3e1461025f578063f2fde38b1461028f576100cd565b806370a08231146101a75780638da5cb5b146101d757806395d89b41146101f5576100cd565b806306fdde03146100d1578063095ea7b3146100ef57806318160ddd1461011f57806323b872dd1461013d578063313ce5671461016d57806340c10f191461018b575b5f80fd5b6100d96102ab565b6040516100e69190610f0e565b60405180910390f35b61010960048036038101906101049190610fbf565b610337565b6040516101169190611017565b60405180910390f35b610127610424565b604051610134919061103f565b60405180910390f35b61015760048036038101906101529190611058565b61042a565b6040516101649190611017565b60405180910390f35b6101756106ca565b60405161018291906110c3565b60405180910390f35b6101a560048036038101906101a09190610fbf565b6106dc565b005b6101c160048036038101906101bc91906110dc565b610740565b6040516101ce919061103f565b60405180910390f35b6101df610755565b6040516101ec9190611116565b60405180910390f35b6101fd610778565b60405161020a9190610f0e565b60405180910390f35b61022d60048036038101906102289190610fbf565b610804565b005b61024960048036038101906102449190610fbf565b610868565b6040516102569190611017565b60405180910390f35b6102796004803603810190610274919061112f565b610a79565b604051610286919061103f565b60405180910390f35b6102a960048036038101906102a491906110dc565b610a99565b005b600380546102b89061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546102e49061119a565b801561032f5780601f106103065761010080835404028352916020019161032f565b820191905f5260205f20905b81548152906001019060200180831161031257829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610412919061103f565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016104669190611116565b602060405180830381865afa158015610481573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a591906111f4565b6105255760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016104e39190611116565b6020604051808303815f875af11580156104ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052391906111f4565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ac919061124c565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ff919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610652919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516106b6919061103f565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610732575f80fd5b61073c8282610be1565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600480546107859061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546107b19061119a565b80156107fc5780601f106107d3576101008083540402835291602001916107fc565b820191905f5260205f20905b8154815290600101906020018083116107df57829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a575f80fd5b6108648282610db0565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016108a49190611116565b602060405180830381865afa1580156108bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108e391906111f4565b6109635760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109219190611116565b6020604051808303815f875af115801561093d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061096191906111f4565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546109af919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a02919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610a66919061103f565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aef575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b26575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610c1c9190611116565b602060405180830381865afa158015610c37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5b91906111f4565b610cdb5760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610c999190611116565b6020604051808303815f875af1158015610cb5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cd991906111f4565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610d27919061127f565b925050819055508160065f828254610d3f919061127f565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610da3919061103f565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610dfc919061124c565b925050819055508060065f828254610e14919061124c565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610e78919061103f565b60405180910390a35050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610ebb578082015181840152602081019050610ea0565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610ee082610e84565b610eea8185610e8e565b9350610efa818560208601610e9e565b610f0381610ec6565b840191505092915050565b5f6020820190508181035f830152610f268184610ed6565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f5b82610f32565b9050919050565b610f6b81610f51565b8114610f75575f80fd5b50565b5f81359050610f8681610f62565b92915050565b5f819050919050565b610f9e81610f8c565b8114610fa8575f80fd5b50565b5f81359050610fb981610f95565b92915050565b5f8060408385031215610fd557610fd4610f2e565b5b5f610fe285828601610f78565b9250506020610ff385828601610fab565b9150509250929050565b5f8115159050919050565b61101181610ffd565b82525050565b5f60208201905061102a5f830184611008565b92915050565b61103981610f8c565b82525050565b5f6020820190506110525f830184611030565b92915050565b5f805f6060848603121561106f5761106e610f2e565b5b5f61107c86828701610f78565b935050602061108d86828701610f78565b925050604061109e86828701610fab565b9150509250925092565b5f60ff82169050919050565b6110bd816110a8565b82525050565b5f6020820190506110d65f8301846110b4565b92915050565b5f602082840312156110f1576110f0610f2e565b5b5f6110fe84828501610f78565b91505092915050565b61111081610f51565b82525050565b5f6020820190506111295f830184611107565b92915050565b5f806040838503121561114557611144610f2e565b5b5f61115285828601610f78565b925050602061116385828601610f78565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806111b157607f821691505b6020821081036111c4576111c361116d565b5b50919050565b6111d381610ffd565b81146111dd575f80fd5b50565b5f815190506111ee816111ca565b92915050565b5f6020828403121561120957611208610f2e565b5b5f611216848285016111e0565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61125682610f8c565b915061126183610f8c565b92508282039050818111156112795761127861121f565b5b92915050565b5f61128982610f8c565b915061129483610f8c565b92508282019050808211156112ac576112ab61121f565b5b9291505056fea26469706673582212200d99d18248e83d210e18f23ff87e4eb89c4a2794c313c7d44e6df4c88a1bb1f964736f6c63430008180033", + ABI: "[{\"inputs\":[{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"_decimals\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"burn\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"mint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801562000010575f80fd5b5060405162001ad138038062001ad183398181016040528101906200003691906200027c565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600390816200008691906200054a565b5081600490816200009891906200054a565b508060055f6101000a81548160ff021916908360ff1602179055505050506200062e565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200011d82620000d5565b810181811067ffffffffffffffff821117156200013f576200013e620000e5565b5b80604052505050565b5f62000153620000bc565b905062000161828262000112565b919050565b5f67ffffffffffffffff821115620001835762000182620000e5565b5b6200018e82620000d5565b9050602081019050919050565b5f5b83811015620001ba5780820151818401526020810190506200019d565b5f8484015250505050565b5f620001db620001d58462000166565b62000148565b905082815260208101848484011115620001fa57620001f9620000d1565b5b620002078482856200019b565b509392505050565b5f82601f830112620002265762000225620000cd565b5b815162000238848260208601620001c5565b91505092915050565b5f60ff82169050919050565b620002588162000241565b811462000263575f80fd5b50565b5f8151905062000276816200024d565b92915050565b5f805f60608486031215620002965762000295620000c5565b5b5f84015167ffffffffffffffff811115620002b657620002b5620000c9565b5b620002c4868287016200020f565b935050602084015167ffffffffffffffff811115620002e857620002e7620000c9565b5b620002f6868287016200020f565b9250506040620003098682870162000266565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200036257607f821691505b6020821081036200037857620003776200031d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003dc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200039f565b620003e886836200039f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004326200042c620004268462000400565b62000409565b62000400565b9050919050565b5f819050919050565b6200044d8362000412565b620004656200045c8262000439565b848454620003ab565b825550505050565b5f90565b6200047b6200046d565b6200048881848462000442565b505050565b5b81811015620004af57620004a35f8262000471565b6001810190506200048e565b5050565b601f821115620004fe57620004c8816200037e565b620004d38462000390565b81016020851015620004e3578190505b620004fb620004f28562000390565b8301826200048d565b50505b505050565b5f82821c905092915050565b5f620005205f198460080262000503565b1980831691505092915050565b5f6200053a83836200050f565b9150826002028217905092915050565b620005558262000313565b67ffffffffffffffff811115620005715762000570620000e5565b5b6200057d82546200034a565b6200058a828285620004b3565b5f60209050601f831160018114620005c0575f8415620005ab578287015190505b620005b785826200052d565b86555062000626565b601f198416620005d0866200037e565b5f5b82811015620005f957848901518255600182019150602085019450602081019050620005d2565b8683101562000619578489015162000615601f8916826200050f565b8355505b6001600288020188555050505b505050505050565b611495806200063c5f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac1461025e578063a9059cbb1461027a578063dd62ed3e146102aa578063f2fde38b146102da576100e8565b806370a08231146101f25780638da5cb5b1461022257806395d89b4114610240576100e8565b806318160ddd116100c657806318160ddd1461016a57806323b872dd14610188578063313ce567146101b857806340c10f19146101d6576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063095ea7b31461013a575b5f80fd5b6101066004803603810190610101919061100a565b6102f6565b604051610113919061104f565b60405180910390f35b61012461036f565b60405161013191906110f2565b60405180910390f35b610154600480360381019061014f919061119f565b6103fb565b604051610161919061104f565b60405180910390f35b6101726104e8565b60405161017f91906111ec565b60405180910390f35b6101a2600480360381019061019d9190611205565b6104ee565b6040516101af919061104f565b60405180910390f35b6101c061078e565b6040516101cd9190611270565b60405180910390f35b6101f060048036038101906101eb919061119f565b6107a0565b005b61020c60048036038101906102079190611289565b610804565b60405161021991906111ec565b60405180910390f35b61022a610819565b60405161023791906112c3565b60405180910390f35b61024861083c565b60405161025591906110f2565b60405180910390f35b6102786004803603810190610273919061119f565b6108c8565b005b610294600480360381019061028f919061119f565b61092c565b6040516102a1919061104f565b60405180910390f35b6102c460048036038101906102bf91906112dc565b610b3d565b6040516102d191906111ec565b60405180910390f35b6102f460048036038101906102ef9190611289565b610b5d565b005b5f7f942e8b22000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610368575061036782610ca5565b5b9050919050565b6003805461037c90611347565b80601f01602080910402602001604051908101604052809291908181526020018280546103a890611347565b80156103f35780601f106103ca576101008083540402835291602001916103f3565b820191905f5260205f20905b8154815290600101906020018083116103d657829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104d691906111ec565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161052a91906112c3565b602060405180830381865afa158015610545573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061056991906113a1565b6105e95760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016105a791906112c3565b6020604051808303815f875af11580156105c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e791906113a1565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461067091906113f9565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546106c391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610716919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161077a91906111ec565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107f6575f80fd5b6108008282610d0e565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6004805461084990611347565b80601f016020809104026020016040519081016040528092919081815260200182805461087590611347565b80156108c05780601f10610897576101008083540402835291602001916108c0565b820191905f5260205f20905b8154815290600101906020018083116108a357829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091e575f80fd5b6109288282610edd565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161096891906112c3565b602060405180830381865afa158015610983573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a791906113a1565b610a275760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109e591906112c3565b6020604051808303815f875af1158015610a01573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2591906113a1565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a7391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610ac6919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610b2a91906111ec565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bb3575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bea575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610d4991906112c3565b602060405180830381865afa158015610d64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8891906113a1565b610e085760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610dc691906112c3565b6020604051808303815f875af1158015610de2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0691906113a1565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e54919061142c565b925050819055508160065f828254610e6c919061142c565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ed091906111ec565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610f2991906113f9565b925050819055508060065f828254610f4191906113f9565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610fa591906111ec565b60405180910390a35050565b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610fe981610fb5565b8114610ff3575f80fd5b50565b5f8135905061100481610fe0565b92915050565b5f6020828403121561101f5761101e610fb1565b5b5f61102c84828501610ff6565b91505092915050565b5f8115159050919050565b61104981611035565b82525050565b5f6020820190506110625f830184611040565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561109f578082015181840152602081019050611084565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6110c482611068565b6110ce8185611072565b93506110de818560208601611082565b6110e7816110aa565b840191505092915050565b5f6020820190508181035f83015261110a81846110ba565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61113b82611112565b9050919050565b61114b81611131565b8114611155575f80fd5b50565b5f8135905061116681611142565b92915050565b5f819050919050565b61117e8161116c565b8114611188575f80fd5b50565b5f8135905061119981611175565b92915050565b5f80604083850312156111b5576111b4610fb1565b5b5f6111c285828601611158565b92505060206111d38582860161118b565b9150509250929050565b6111e68161116c565b82525050565b5f6020820190506111ff5f8301846111dd565b92915050565b5f805f6060848603121561121c5761121b610fb1565b5b5f61122986828701611158565b935050602061123a86828701611158565b925050604061124b8682870161118b565b9150509250925092565b5f60ff82169050919050565b61126a81611255565b82525050565b5f6020820190506112835f830184611261565b92915050565b5f6020828403121561129e5761129d610fb1565b5b5f6112ab84828501611158565b91505092915050565b6112bd81611131565b82525050565b5f6020820190506112d65f8301846112b4565b92915050565b5f80604083850312156112f2576112f1610fb1565b5b5f6112ff85828601611158565b925050602061131085828601611158565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061135e57607f821691505b6020821081036113715761137061131a565b5b50919050565b61138081611035565b811461138a575f80fd5b50565b5f8151905061139b81611377565b92915050565b5f602082840312156113b6576113b5610fb1565b5b5f6113c38482850161138d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6114038261116c565b915061140e8361116c565b9250828203905081811115611426576114256113cc565b5b92915050565b5f6114368261116c565b91506114418361116c565b9250828201905080821115611459576114586113cc565b5b9291505056fea264697066735822122067e09fb1c8f6c6d1f6c87e9baac07eeef8b81a3218e526c7e72f157bf344e58564736f6c63430008180033", } // Erc20ABI is the input ABI used to generate the binding from. @@ -357,6 +357,37 @@ func (_Erc20 *Erc20CallerSession) Owner() (common.Address, error) { return _Erc20.Contract.Owner(&_Erc20.CallOpts) } +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Erc20 *Erc20Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _Erc20.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Erc20 *Erc20Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc20.Contract.SupportsInterface(&_Erc20.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_Erc20 *Erc20CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _Erc20.Contract.SupportsInterface(&_Erc20.CallOpts, interfaceId) +} + // Symbol is a free data retrieval call binding the contract method 0x95d89b41. // // Solidity: function symbol() view returns(string) diff --git a/x/evm/contracts/erc20/ERC20.sol b/x/evm/contracts/erc20/ERC20.sol index 7e6037a..6730a3a 100644 --- a/x/evm/contracts/erc20/ERC20.sol +++ b/x/evm/contracts/erc20/ERC20.sol @@ -4,8 +4,9 @@ pragma solidity ^0.8.24; import "../i_erc20/IERC20.sol"; import "../ownable/Ownable.sol"; import "../erc20_registry/ERC20Registry.sol"; +import {ERC165, IERC165} from "../erc165/ERC165.sol"; -contract ERC20 is IERC20, Ownable, ERC20Registry { +contract ERC20 is IERC20, Ownable, ERC20Registry, ERC165 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval( address indexed owner, @@ -20,6 +21,17 @@ contract ERC20 is IERC20, Ownable, ERC20Registry { uint8 public decimals; uint256 public totalSupply; + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(IERC165, ERC165) returns (bool) { + return + interfaceId == type(IERC20).interfaceId || + super.supportsInterface(interfaceId); + } + // for custom erc20s, you should add `register_erc20` modifier to the constructor constructor(string memory _name, string memory _symbol, uint8 _decimals) { name = _name; @@ -55,7 +67,10 @@ contract ERC20 is IERC20, Ownable, ERC20Registry { return true; } - function _mint(address to, uint256 amount) internal register_erc20_store(to) { + function _mint( + address to, + uint256 amount + ) internal register_erc20_store(to) { balanceOf[to] += amount; totalSupply += amount; emit Transfer(address(0), to, amount); @@ -67,7 +82,7 @@ contract ERC20 is IERC20, Ownable, ERC20Registry { emit Transfer(from, address(0), amount); } - function mint(address to, uint256 amount) external onlyOwner{ + function mint(address to, uint256 amount) external onlyOwner { _mint(to, amount); } diff --git a/x/evm/contracts/erc20_factory/ERC20Factory.go b/x/evm/contracts/erc20_factory/ERC20Factory.go index 28e6568..f4f93d9 100644 --- a/x/evm/contracts/erc20_factory/ERC20Factory.go +++ b/x/evm/contracts/erc20_factory/ERC20Factory.go @@ -32,7 +32,7 @@ var ( // Erc20FactoryMetaData contains all meta data concerning the Erc20Factory contract. var Erc20FactoryMetaData = &bind.MetaData{ ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"erc20\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"}],\"name\":\"ERC20Created\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"}],\"name\":\"createERC20\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", - Bin: "0x608060405234801561000f575f80fd5b50611f3c8061001d5f395ff3fe608060405234801562000010575f80fd5b50600436106200002c575f3560e01c806306ef1a861462000030575b5f80fd5b6200004e6004803603810190620000489190620003a5565b62000066565b6040516200005d91906200047f565b60405180910390f35b5f808484846040516200007990620001f3565b62000087939291906200052f565b604051809103905ff080158015620000a1573d5f803e3d5ffd5b50905060f273ffffffffffffffffffffffffffffffffffffffff1663d126274a826040518263ffffffff1660e01b8152600401620000e091906200047f565b6020604051808303815f875af1158015620000fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001239190620005b2565b508073ffffffffffffffffffffffffffffffffffffffff1663f2fde38b336040518263ffffffff1660e01b81526004016200015f91906200047f565b5f604051808303815f87803b15801562000177575f80fd5b505af11580156200018a573d5f803e3d5ffd5b505050503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f85e892981b234101136bc30081e0a5c44345bebc0940193230c20a43b279e2d160405160405180910390a3809150509392505050565b61192480620005e383390190565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b62000262826200021a565b810181811067ffffffffffffffff821117156200028457620002836200022a565b5b80604052505050565b5f6200029862000201565b9050620002a6828262000257565b919050565b5f67ffffffffffffffff821115620002c857620002c76200022a565b5b620002d3826200021a565b9050602081019050919050565b828183375f83830152505050565b5f62000304620002fe84620002ab565b6200028d565b90508281526020810184848401111562000323576200032262000216565b5b62000330848285620002e0565b509392505050565b5f82601f8301126200034f576200034e62000212565b5b813562000361848260208601620002ee565b91505092915050565b5f60ff82169050919050565b62000381816200036a565b81146200038c575f80fd5b50565b5f813590506200039f8162000376565b92915050565b5f805f60608486031215620003bf57620003be6200020a565b5b5f84013567ffffffffffffffff811115620003df57620003de6200020e565b5b620003ed8682870162000338565b935050602084013567ffffffffffffffff8111156200041157620004106200020e565b5b6200041f8682870162000338565b925050604062000432868287016200038f565b9150509250925092565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f62000467826200043c565b9050919050565b62000479816200045b565b82525050565b5f602082019050620004945f8301846200046e565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015620004d3578082015181840152602081019050620004b6565b5f8484015250505050565b5f620004ea826200049a565b620004f68185620004a4565b935062000508818560208601620004b4565b62000513816200021a565b840191505092915050565b62000529816200036a565b82525050565b5f6060820190508181035f830152620005498186620004de565b905081810360208301526200055f8185620004de565b90506200057060408301846200051e565b949350505050565b5f8115159050919050565b6200058e8162000578565b811462000599575f80fd5b50565b5f81519050620005ac8162000583565b92915050565b5f60208284031215620005ca57620005c96200020a565b5b5f620005d9848285016200059c565b9150509291505056fe608060405234801562000010575f80fd5b50604051620019243803806200192483398181016040528101906200003691906200027c565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600390816200008691906200054a565b5081600490816200009891906200054a565b508060055f6101000a81548160ff021916908360ff1602179055505050506200062e565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200011d82620000d5565b810181811067ffffffffffffffff821117156200013f576200013e620000e5565b5b80604052505050565b5f62000153620000bc565b905062000161828262000112565b919050565b5f67ffffffffffffffff821115620001835762000182620000e5565b5b6200018e82620000d5565b9050602081019050919050565b5f5b83811015620001ba5780820151818401526020810190506200019d565b5f8484015250505050565b5f620001db620001d58462000166565b62000148565b905082815260208101848484011115620001fa57620001f9620000d1565b5b620002078482856200019b565b509392505050565b5f82601f830112620002265762000225620000cd565b5b815162000238848260208601620001c5565b91505092915050565b5f60ff82169050919050565b620002588162000241565b811462000263575f80fd5b50565b5f8151905062000276816200024d565b92915050565b5f805f60608486031215620002965762000295620000c5565b5b5f84015167ffffffffffffffff811115620002b657620002b5620000c9565b5b620002c4868287016200020f565b935050602084015167ffffffffffffffff811115620002e857620002e7620000c9565b5b620002f6868287016200020f565b9250506040620003098682870162000266565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200036257607f821691505b6020821081036200037857620003776200031d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003dc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200039f565b620003e886836200039f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004326200042c620004268462000400565b62000409565b62000400565b9050919050565b5f819050919050565b6200044d8362000412565b620004656200045c8262000439565b848454620003ab565b825550505050565b5f90565b6200047b6200046d565b6200048881848462000442565b505050565b5b81811015620004af57620004a35f8262000471565b6001810190506200048e565b5050565b601f821115620004fe57620004c8816200037e565b620004d38462000390565b81016020851015620004e3578190505b620004fb620004f28562000390565b8301826200048d565b50505b505050565b5f82821c905092915050565b5f620005205f198460080262000503565b1980831691505092915050565b5f6200053a83836200050f565b9150826002028217905092915050565b620005558262000313565b67ffffffffffffffff811115620005715762000570620000e5565b5b6200057d82546200034a565b6200058a828285620004b3565b5f60209050601f831160018114620005c0575f8415620005ab578287015190505b620005b785826200052d565b86555062000626565b601f198416620005d0866200037e565b5f5b82811015620005f957848901518255600182019150602085019450602081019050620005d2565b8683101562000619578489015162000615601f8916826200050f565b8355505b6001600288020188555050505b505050505050565b6112e8806200063c5f395ff3fe608060405234801561000f575f80fd5b50600436106100cd575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac14610213578063a9059cbb1461022f578063dd62ed3e1461025f578063f2fde38b1461028f576100cd565b806370a08231146101a75780638da5cb5b146101d757806395d89b41146101f5576100cd565b806306fdde03146100d1578063095ea7b3146100ef57806318160ddd1461011f57806323b872dd1461013d578063313ce5671461016d57806340c10f191461018b575b5f80fd5b6100d96102ab565b6040516100e69190610f0e565b60405180910390f35b61010960048036038101906101049190610fbf565b610337565b6040516101169190611017565b60405180910390f35b610127610424565b604051610134919061103f565b60405180910390f35b61015760048036038101906101529190611058565b61042a565b6040516101649190611017565b60405180910390f35b6101756106ca565b60405161018291906110c3565b60405180910390f35b6101a560048036038101906101a09190610fbf565b6106dc565b005b6101c160048036038101906101bc91906110dc565b610740565b6040516101ce919061103f565b60405180910390f35b6101df610755565b6040516101ec9190611116565b60405180910390f35b6101fd610778565b60405161020a9190610f0e565b60405180910390f35b61022d60048036038101906102289190610fbf565b610804565b005b61024960048036038101906102449190610fbf565b610868565b6040516102569190611017565b60405180910390f35b6102796004803603810190610274919061112f565b610a79565b604051610286919061103f565b60405180910390f35b6102a960048036038101906102a491906110dc565b610a99565b005b600380546102b89061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546102e49061119a565b801561032f5780601f106103065761010080835404028352916020019161032f565b820191905f5260205f20905b81548152906001019060200180831161031257829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92584604051610412919061103f565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016104669190611116565b602060405180830381865afa158015610481573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a591906111f4565b6105255760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016104e39190611116565b6020604051808303815f875af11580156104ff573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061052391906111f4565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ac919061124c565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546105ff919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610652919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516106b6919061103f565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610732575f80fd5b61073c8282610be1565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600480546107859061119a565b80601f01602080910402602001604051908101604052809291908181526020018280546107b19061119a565b80156107fc5780601f106107d3576101008083540402835291602001916107fc565b820191905f5260205f20905b8154815290600101906020018083116107df57829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461085a575f80fd5b6108648282610db0565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b81526004016108a49190611116565b602060405180830381865afa1580156108bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108e391906111f4565b6109635760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109219190611116565b6020604051808303815f875af115801561093d573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061096191906111f4565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546109af919061124c565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a02919061127f565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610a66919061103f565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610aef575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b26575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610c1c9190611116565b602060405180830381865afa158015610c37573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c5b91906111f4565b610cdb5760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610c999190611116565b6020604051808303815f875af1158015610cb5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cd991906111f4565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610d27919061127f565b925050819055508160065f828254610d3f919061127f565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610da3919061103f565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610dfc919061124c565b925050819055508060065f828254610e14919061124c565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610e78919061103f565b60405180910390a35050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015610ebb578082015181840152602081019050610ea0565b5f8484015250505050565b5f601f19601f8301169050919050565b5f610ee082610e84565b610eea8185610e8e565b9350610efa818560208601610e9e565b610f0381610ec6565b840191505092915050565b5f6020820190508181035f830152610f268184610ed6565b905092915050565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f610f5b82610f32565b9050919050565b610f6b81610f51565b8114610f75575f80fd5b50565b5f81359050610f8681610f62565b92915050565b5f819050919050565b610f9e81610f8c565b8114610fa8575f80fd5b50565b5f81359050610fb981610f95565b92915050565b5f8060408385031215610fd557610fd4610f2e565b5b5f610fe285828601610f78565b9250506020610ff385828601610fab565b9150509250929050565b5f8115159050919050565b61101181610ffd565b82525050565b5f60208201905061102a5f830184611008565b92915050565b61103981610f8c565b82525050565b5f6020820190506110525f830184611030565b92915050565b5f805f6060848603121561106f5761106e610f2e565b5b5f61107c86828701610f78565b935050602061108d86828701610f78565b925050604061109e86828701610fab565b9150509250925092565b5f60ff82169050919050565b6110bd816110a8565b82525050565b5f6020820190506110d65f8301846110b4565b92915050565b5f602082840312156110f1576110f0610f2e565b5b5f6110fe84828501610f78565b91505092915050565b61111081610f51565b82525050565b5f6020820190506111295f830184611107565b92915050565b5f806040838503121561114557611144610f2e565b5b5f61115285828601610f78565b925050602061116385828601610f78565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806111b157607f821691505b6020821081036111c4576111c361116d565b5b50919050565b6111d381610ffd565b81146111dd575f80fd5b50565b5f815190506111ee816111ca565b92915050565b5f6020828403121561120957611208610f2e565b5b5f611216848285016111e0565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f61125682610f8c565b915061126183610f8c565b92508282039050818111156112795761127861121f565b5b92915050565b5f61128982610f8c565b915061129483610f8c565b92508282019050808211156112ac576112ab61121f565b5b9291505056fea26469706673582212200d99d18248e83d210e18f23ff87e4eb89c4a2794c313c7d44e6df4c88a1bb1f964736f6c63430008180033a2646970667358221220104aed2e81c5fa422cb7af2267fdb086a78076322eb92fe4b1fb0bc7f603365c64736f6c63430008180033", + Bin: "0x608060405234801561000f575f80fd5b506120e98061001d5f395ff3fe608060405234801562000010575f80fd5b50600436106200002c575f3560e01c806306ef1a861462000030575b5f80fd5b6200004e6004803603810190620000489190620003a5565b62000066565b6040516200005d91906200047f565b60405180910390f35b5f808484846040516200007990620001f3565b62000087939291906200052f565b604051809103905ff080158015620000a1573d5f803e3d5ffd5b50905060f273ffffffffffffffffffffffffffffffffffffffff1663d126274a826040518263ffffffff1660e01b8152600401620000e091906200047f565b6020604051808303815f875af1158015620000fd573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001239190620005b2565b508073ffffffffffffffffffffffffffffffffffffffff1663f2fde38b336040518263ffffffff1660e01b81526004016200015f91906200047f565b5f604051808303815f87803b15801562000177575f80fd5b505af11580156200018a573d5f803e3d5ffd5b505050503373ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f85e892981b234101136bc30081e0a5c44345bebc0940193230c20a43b279e2d160405160405180910390a3809150509392505050565b611ad180620005e383390190565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b62000262826200021a565b810181811067ffffffffffffffff821117156200028457620002836200022a565b5b80604052505050565b5f6200029862000201565b9050620002a6828262000257565b919050565b5f67ffffffffffffffff821115620002c857620002c76200022a565b5b620002d3826200021a565b9050602081019050919050565b828183375f83830152505050565b5f62000304620002fe84620002ab565b6200028d565b90508281526020810184848401111562000323576200032262000216565b5b62000330848285620002e0565b509392505050565b5f82601f8301126200034f576200034e62000212565b5b813562000361848260208601620002ee565b91505092915050565b5f60ff82169050919050565b62000381816200036a565b81146200038c575f80fd5b50565b5f813590506200039f8162000376565b92915050565b5f805f60608486031215620003bf57620003be6200020a565b5b5f84013567ffffffffffffffff811115620003df57620003de6200020e565b5b620003ed8682870162000338565b935050602084013567ffffffffffffffff8111156200041157620004106200020e565b5b6200041f8682870162000338565b925050604062000432868287016200038f565b9150509250925092565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f62000467826200043c565b9050919050565b62000479816200045b565b82525050565b5f602082019050620004945f8301846200046e565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b83811015620004d3578082015181840152602081019050620004b6565b5f8484015250505050565b5f620004ea826200049a565b620004f68185620004a4565b935062000508818560208601620004b4565b62000513816200021a565b840191505092915050565b62000529816200036a565b82525050565b5f6060820190508181035f830152620005498186620004de565b905081810360208301526200055f8185620004de565b90506200057060408301846200051e565b949350505050565b5f8115159050919050565b6200058e8162000578565b811462000599575f80fd5b50565b5f81519050620005ac8162000583565b92915050565b5f60208284031215620005ca57620005c96200020a565b5b5f620005d9848285016200059c565b9150509291505056fe608060405234801562000010575f80fd5b5060405162001ad138038062001ad183398181016040528101906200003691906200027c565b335f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600390816200008691906200054a565b5081600490816200009891906200054a565b508060055f6101000a81548160ff021916908360ff1602179055505050506200062e565b5f604051905090565b5f80fd5b5f80fd5b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6200011d82620000d5565b810181811067ffffffffffffffff821117156200013f576200013e620000e5565b5b80604052505050565b5f62000153620000bc565b905062000161828262000112565b919050565b5f67ffffffffffffffff821115620001835762000182620000e5565b5b6200018e82620000d5565b9050602081019050919050565b5f5b83811015620001ba5780820151818401526020810190506200019d565b5f8484015250505050565b5f620001db620001d58462000166565b62000148565b905082815260208101848484011115620001fa57620001f9620000d1565b5b620002078482856200019b565b509392505050565b5f82601f830112620002265762000225620000cd565b5b815162000238848260208601620001c5565b91505092915050565b5f60ff82169050919050565b620002588162000241565b811462000263575f80fd5b50565b5f8151905062000276816200024d565b92915050565b5f805f60608486031215620002965762000295620000c5565b5b5f84015167ffffffffffffffff811115620002b657620002b5620000c9565b5b620002c4868287016200020f565b935050602084015167ffffffffffffffff811115620002e857620002e7620000c9565b5b620002f6868287016200020f565b9250506040620003098682870162000266565b9150509250925092565b5f81519050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f60028204905060018216806200036257607f821691505b6020821081036200037857620003776200031d565b5b50919050565b5f819050815f5260205f209050919050565b5f6020601f8301049050919050565b5f82821b905092915050565b5f60088302620003dc7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200039f565b620003e886836200039f565b95508019841693508086168417925050509392505050565b5f819050919050565b5f819050919050565b5f620004326200042c620004268462000400565b62000409565b62000400565b9050919050565b5f819050919050565b6200044d8362000412565b620004656200045c8262000439565b848454620003ab565b825550505050565b5f90565b6200047b6200046d565b6200048881848462000442565b505050565b5b81811015620004af57620004a35f8262000471565b6001810190506200048e565b5050565b601f821115620004fe57620004c8816200037e565b620004d38462000390565b81016020851015620004e3578190505b620004fb620004f28562000390565b8301826200048d565b50505b505050565b5f82821c905092915050565b5f620005205f198460080262000503565b1980831691505092915050565b5f6200053a83836200050f565b9150826002028217905092915050565b620005558262000313565b67ffffffffffffffff811115620005715762000570620000e5565b5b6200057d82546200034a565b6200058a828285620004b3565b5f60209050601f831160018114620005c0575f8415620005ab578287015190505b620005b785826200052d565b86555062000626565b601f198416620005d0866200037e565b5f5b82811015620005f957848901518255600182019150602085019450602081019050620005d2565b8683101562000619578489015162000615601f8916826200050f565b8355505b6001600288020188555050505b505050505050565b611495806200063c5f395ff3fe608060405234801561000f575f80fd5b50600436106100e8575f3560e01c806370a082311161008a5780639dc29fac116100645780639dc29fac1461025e578063a9059cbb1461027a578063dd62ed3e146102aa578063f2fde38b146102da576100e8565b806370a08231146101f25780638da5cb5b1461022257806395d89b4114610240576100e8565b806318160ddd116100c657806318160ddd1461016a57806323b872dd14610188578063313ce567146101b857806340c10f19146101d6576100e8565b806301ffc9a7146100ec57806306fdde031461011c578063095ea7b31461013a575b5f80fd5b6101066004803603810190610101919061100a565b6102f6565b604051610113919061104f565b60405180910390f35b61012461036f565b60405161013191906110f2565b60405180910390f35b610154600480360381019061014f919061119f565b6103fb565b604051610161919061104f565b60405180910390f35b6101726104e8565b60405161017f91906111ec565b60405180910390f35b6101a2600480360381019061019d9190611205565b6104ee565b6040516101af919061104f565b60405180910390f35b6101c061078e565b6040516101cd9190611270565b60405180910390f35b6101f060048036038101906101eb919061119f565b6107a0565b005b61020c60048036038101906102079190611289565b610804565b60405161021991906111ec565b60405180910390f35b61022a610819565b60405161023791906112c3565b60405180910390f35b61024861083c565b60405161025591906110f2565b60405180910390f35b6102786004803603810190610273919061119f565b6108c8565b005b610294600480360381019061028f919061119f565b61092c565b6040516102a1919061104f565b60405180910390f35b6102c460048036038101906102bf91906112dc565b610b3d565b6040516102d191906111ec565b60405180910390f35b6102f460048036038101906102ef9190611289565b610b5d565b005b5f7f942e8b22000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161480610368575061036782610ca5565b5b9050919050565b6003805461037c90611347565b80601f01602080910402602001604051908101604052809291908181526020018280546103a890611347565b80156103f35780601f106103ca576101008083540402835291602001916103f3565b820191905f5260205f20905b8154815290600101906020018083116103d657829003601f168201915b505050505081565b5f8160025f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f20819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104d691906111ec565b60405180910390a36001905092915050565b60065481565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161052a91906112c3565b602060405180830381865afa158015610545573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061056991906113a1565b6105e95760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016105a791906112c3565b6020604051808303815f875af11580156105c3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105e791906113a1565b505b8260025f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f82825461067091906113f9565b925050819055508260015f8773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f8282546106c391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610716919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161077a91906111ec565b60405180910390a360019150509392505050565b60055f9054906101000a900460ff1681565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146107f6575f80fd5b6108008282610d0e565b5050565b6001602052805f5260405f205f915090505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6004805461084990611347565b80601f016020809104026020016040519081016040528092919081815260200182805461087590611347565b80156108c05780601f10610897576101008083540402835291602001916108c0565b820191905f5260205f20905b8154815290600101906020018083116108a357829003601f168201915b505050505081565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161461091e575f80fd5b6109288282610edd565b5050565b5f8260f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b815260040161096891906112c3565b602060405180830381865afa158015610983573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109a791906113a1565b610a275760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b81526004016109e591906112c3565b6020604051808303815f875af1158015610a01573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a2591906113a1565b505b8260015f3373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610a7391906113f9565b925050819055508260015f8673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610ac6919061142c565b925050819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef85604051610b2a91906111ec565b60405180910390a3600191505092915050565b6002602052815f5260405f20602052805f5260405f205f91509150505481565b5f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610bb3575f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bea575f80fd5b8073ffffffffffffffffffffffffffffffffffffffff165f8054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3805f806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b5f7f01ffc9a7000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916827bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916149050919050565b8160f273ffffffffffffffffffffffffffffffffffffffff16634e25ab64826040518263ffffffff1660e01b8152600401610d4991906112c3565b602060405180830381865afa158015610d64573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d8891906113a1565b610e085760f273ffffffffffffffffffffffffffffffffffffffff1663ceeae52a826040518263ffffffff1660e01b8152600401610dc691906112c3565b6020604051808303815f875af1158015610de2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0691906113a1565b505b8160015f8573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610e54919061142c565b925050819055508160065f828254610e6c919061142c565b925050819055508273ffffffffffffffffffffffffffffffffffffffff165f73ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610ed091906111ec565b60405180910390a3505050565b8060015f8473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020015f205f828254610f2991906113f9565b925050819055508060065f828254610f4191906113f9565b925050819055505f73ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610fa591906111ec565b60405180910390a35050565b5f80fd5b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b610fe981610fb5565b8114610ff3575f80fd5b50565b5f8135905061100481610fe0565b92915050565b5f6020828403121561101f5761101e610fb1565b5b5f61102c84828501610ff6565b91505092915050565b5f8115159050919050565b61104981611035565b82525050565b5f6020820190506110625f830184611040565b92915050565b5f81519050919050565b5f82825260208201905092915050565b5f5b8381101561109f578082015181840152602081019050611084565b5f8484015250505050565b5f601f19601f8301169050919050565b5f6110c482611068565b6110ce8185611072565b93506110de818560208601611082565b6110e7816110aa565b840191505092915050565b5f6020820190508181035f83015261110a81846110ba565b905092915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f61113b82611112565b9050919050565b61114b81611131565b8114611155575f80fd5b50565b5f8135905061116681611142565b92915050565b5f819050919050565b61117e8161116c565b8114611188575f80fd5b50565b5f8135905061119981611175565b92915050565b5f80604083850312156111b5576111b4610fb1565b5b5f6111c285828601611158565b92505060206111d38582860161118b565b9150509250929050565b6111e68161116c565b82525050565b5f6020820190506111ff5f8301846111dd565b92915050565b5f805f6060848603121561121c5761121b610fb1565b5b5f61122986828701611158565b935050602061123a86828701611158565b925050604061124b8682870161118b565b9150509250925092565b5f60ff82169050919050565b61126a81611255565b82525050565b5f6020820190506112835f830184611261565b92915050565b5f6020828403121561129e5761129d610fb1565b5b5f6112ab84828501611158565b91505092915050565b6112bd81611131565b82525050565b5f6020820190506112d65f8301846112b4565b92915050565b5f80604083850312156112f2576112f1610fb1565b5b5f6112ff85828601611158565b925050602061131085828601611158565b9150509250929050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b5f600282049050600182168061135e57607f821691505b6020821081036113715761137061131a565b5b50919050565b61138081611035565b811461138a575f80fd5b50565b5f8151905061139b81611377565b92915050565b5f602082840312156113b6576113b5610fb1565b5b5f6113c38482850161138d565b91505092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6114038261116c565b915061140e8361116c565b9250828203905081811115611426576114256113cc565b5b92915050565b5f6114368261116c565b91506114418361116c565b9250828201905080821115611459576114586113cc565b5b9291505056fea264697066735822122067e09fb1c8f6c6d1f6c87e9baac07eeef8b81a3218e526c7e72f157bf344e58564736f6c63430008180033a2646970667358221220012e95eae571f8b8aa7d90dba694698d6bbe3e987c2b4c972f8e03c0a07e47fe64736f6c63430008180033", } // Erc20FactoryABI is the input ABI used to generate the binding from. diff --git a/x/evm/contracts/i_erc20/IERC20.go b/x/evm/contracts/i_erc20/IERC20.go index f435766..c330704 100644 --- a/x/evm/contracts/i_erc20/IERC20.go +++ b/x/evm/contracts/i_erc20/IERC20.go @@ -31,7 +31,7 @@ var ( // IErc20MetaData contains all meta data concerning the IErc20 contract. var IErc20MetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes4\",\"name\":\"interfaceId\",\"type\":\"bytes4\"}],\"name\":\"supportsInterface\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", } // IErc20ABI is the input ABI used to generate the binding from. @@ -304,6 +304,37 @@ func (_IErc20 *IErc20CallerSession) Name() (string, error) { return _IErc20.Contract.Name(&_IErc20.CallOpts) } +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IErc20 *IErc20Caller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { + var out []interface{} + err := _IErc20.contract.Call(opts, &out, "supportsInterface", interfaceId) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IErc20 *IErc20Session) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IErc20.Contract.SupportsInterface(&_IErc20.CallOpts, interfaceId) +} + +// SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. +// +// Solidity: function supportsInterface(bytes4 interfaceId) view returns(bool) +func (_IErc20 *IErc20CallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { + return _IErc20.Contract.SupportsInterface(&_IErc20.CallOpts, interfaceId) +} + // Symbol is a free data retrieval call binding the contract method 0x95d89b41. // // Solidity: function symbol() view returns(string) diff --git a/x/evm/contracts/i_erc20/IERC20.sol b/x/evm/contracts/i_erc20/IERC20.sol index 17bd22b..5636654 100644 --- a/x/evm/contracts/i_erc20/IERC20.sol +++ b/x/evm/contracts/i_erc20/IERC20.sol @@ -1,7 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -interface IERC20 { +import {IERC165} from "../i_erc165/IERC165.sol"; + +interface IERC20 is IERC165 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); diff --git a/x/evm/keeper/common_test.go b/x/evm/keeper/common_test.go index e3f7755..8fcd8ee 100644 --- a/x/evm/keeper/common_test.go +++ b/x/evm/keeper/common_test.go @@ -2,17 +2,15 @@ package keeper_test import ( "context" - "encoding/binary" "testing" "time" "github.com/stretchr/testify/require" - "github.com/cometbft/cometbft/crypto" - "github.com/cometbft/cometbft/crypto/ed25519" tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "cosmossdk.io/log" + "cosmossdk.io/math" "cosmossdk.io/store" "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" @@ -23,6 +21,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codecaddress "github.com/cosmos/cosmos-sdk/codec/address" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" @@ -40,6 +39,7 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/gogoproto/proto" + "github.com/initia-labs/initia/crypto/ethsecp256k1" custombankkeeper "github.com/initia-labs/minievm/x/bank/keeper" "github.com/initia-labs/minievm/x/evm" evmconfig "github.com/initia-labs/minievm/x/evm/config" @@ -161,16 +161,10 @@ func createTestInput(t testing.TB, isCheckTx, withInitialize bool) (sdk.Context, return _createTestInput(t, isCheckTx, withInitialize, dbm.NewMemDB()) } -var keyCounter uint64 - // we need to make this deterministic (same every test run), as encoded address size and thus gas cost, // depends on the actual bytes (due to ugly CanonicalAddress encoding) -func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) { - keyCounter++ - seed := make([]byte, 8) - binary.BigEndian.PutUint64(seed, keyCounter) - - key := ed25519.GenPrivKeyFromSecret(seed) +func keyPubAddr() (cryptotypes.PrivKey, cryptotypes.PubKey, sdk.AccAddress) { + key := ethsecp256k1.GenerateKey() pub := key.PubKey() addr := sdk.AccAddress(pub.Address()) return key, pub, addr @@ -271,17 +265,18 @@ func _createTestInput( }, ) + // set erc20 keeper + *erc20Keeper = *evmKeeper.ERC20Keeper().(*evmkeeper.ERC20Keeper) + faucet := NewTestFaucet(t, ctx, bankKeeper, authtypes.Minter) + if withInitialize { evmParams := evmtypes.DefaultParams() evmParams.AllowCustomERC20 = false require.NoError(t, evmKeeper.Params.Set(ctx, evmParams)) require.NoError(t, evmKeeper.Initialize(ctx)) - } - - // set erc20 keeper - *erc20Keeper = *evmKeeper.ERC20Keeper().(*evmkeeper.ERC20Keeper) - faucet := NewTestFaucet(t, ctx, bankKeeper, authtypes.Minter) + faucet.NewFundedAccount(ctx, sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1_000_000))) + } keepers := TestKeepers{ AccountKeeper: accountKeeper, diff --git a/x/evm/keeper/context.go b/x/evm/keeper/context.go index 6375378..0045f95 100644 --- a/x/evm/keeper/context.go +++ b/x/evm/keeper/context.go @@ -3,7 +3,6 @@ package keeper import ( "context" "encoding/json" - "fmt" "math" "math/big" @@ -34,20 +33,85 @@ func (k Keeper) computeGasLimit(sdkCtx sdk.Context) uint64 { return gasLimit } -func (k Keeper) buildBlockContext(ctx context.Context) vm.BlockContext { +type callableEVM interface { + Call(vm.ContractRef, common.Address, []byte, uint64, *uint256.Int) ([]byte, uint64, error) + StaticCall(vm.ContractRef, common.Address, []byte, uint64) ([]byte, uint64, error) +} + +func (k Keeper) buildBlockContext(ctx context.Context, evm callableEVM) (vm.BlockContext, error) { sdkCtx := sdk.UnwrapSDKContext(ctx) headerHash := sdkCtx.HeaderHash() if len(headerHash) == 0 { headerHash = make([]byte, 32) } + var contractAddr common.Address + if !k.initializing { + params, err := k.Params.Get(ctx) + if err != nil { + return vm.BlockContext{}, err + } + + contractAddr, err = types.DenomToContractAddr(ctx, k, params.FeeDenom) + if err != nil { + return vm.BlockContext{}, err + } + } + + // TODO: should we charge gas for CanTransfer and Transfer? + // + // In order to charge gas, we need to fork the EVM and add gas charge + // logic to the CanTransfer and Transfer functions. + // return vm.BlockContext{ GasLimit: k.computeGasLimit(sdkCtx), BlockNumber: big.NewInt(sdkCtx.BlockHeight()), Time: uint64(sdkCtx.BlockTime().Unix()), - CanTransfer: func(sd vm.StateDB, a common.Address, i *uint256.Int) bool { return true }, - Transfer: func(sd vm.StateDB, a1, a2 common.Address, i *uint256.Int) {}, - GetHash: func(u uint64) common.Hash { return common.Hash{} }, + CanTransfer: func(sd vm.StateDB, a common.Address, i *uint256.Int) bool { + if i == nil || i.IsZero() { + return true + } + + inputBz, err := k.erc20Keeper.GetERC20ABI().Pack("balanceOf", a) + if err != nil { + return false + } + + retBz, _, err := evm.StaticCall(vm.AccountRef(types.NullAddress), contractAddr, inputBz, 100000) + if err != nil { + k.Logger(ctx).Warn("failed to check balance", "error", err) + return false + } + + res, err := k.erc20Keeper.GetERC20ABI().Unpack("balanceOf", retBz) + if err != nil { + return false + } + + balance, ok := res[0].(*big.Int) + if !ok { + return false + } + + return i.CmpBig(balance) <= 0 + }, + Transfer: func(sd vm.StateDB, a1, a2 common.Address, i *uint256.Int) { + if i == nil || i.IsZero() { + return + } + + inputBz, err := k.erc20Keeper.GetERC20ABI().Pack("transfer", a2, i.ToBig()) + if err != nil { + panic(err) + } + + _, _, err = evm.Call(vm.AccountRef(a1), contractAddr, inputBz, 100000, uint256.NewInt(0)) + if err != nil { + k.Logger(ctx).Warn("failed to transfer token", "error", err) + panic(err) + } + }, + GetHash: func(u uint64) common.Hash { return common.Hash{} }, // unused fields Coinbase: common.Address{}, Difficulty: nil, @@ -55,8 +119,7 @@ func (k Keeper) buildBlockContext(ctx context.Context) vm.BlockContext { BlobBaseFee: nil, // put header hash to bypass isMerge check in evm Random: (*common.Hash)(headerHash), - } - + }, nil } func (k Keeper) buildTxContext(_ context.Context, caller common.Address) vm.TxContext { @@ -75,7 +138,12 @@ func (k Keeper) createEVM(ctx context.Context, caller common.Address, tracer *tr return ctx, nil, err } - blockContext := k.buildBlockContext(ctx) + evm := &vm.EVM{} + blockContext, err := k.buildBlockContext(ctx, evm) + if err != nil { + return ctx, nil, err + } + txContext := k.buildTxContext(ctx, caller) stateDB, err := k.newStateDB(ctx) if err != nil { @@ -90,11 +158,11 @@ func (k Keeper) createEVM(ctx context.Context, caller common.Address, tracer *tr // set cosmos messages to context ctx = sdk.UnwrapSDKContext(ctx).WithValue(types.CONTEXT_KEY_COSMOS_MESSAGES, &[]sdk.Msg{}) - evm := vm.NewEVMWithPrecompiles( + *evm = *vm.NewEVMWithPrecompiles( blockContext, txContext, stateDB, - types.DefaultChainConfig(), + types.DefaultChainConfig(ctx), vmConfig, k.precompiles.toMap(ctx), ) @@ -169,37 +237,39 @@ func (k Keeper) EVMStaticCallWithTracer(ctx context.Context, caller common.Addre } // EVMCall executes an EVM call with the given input data. -func (k Keeper) EVMCall(ctx context.Context, caller common.Address, contractAddr common.Address, inputBz []byte) ([]byte, types.Logs, error) { - return k.EVMCallWithTracer(ctx, caller, contractAddr, inputBz, nil) +func (k Keeper) EVMCall(ctx context.Context, caller common.Address, contractAddr common.Address, inputBz []byte, value *uint256.Int) ([]byte, types.Logs, error) { + return k.EVMCallWithTracer(ctx, caller, contractAddr, inputBz, value, nil) } // EVMCallWithTracer executes an EVM call with the given input data and tracer. -func (k Keeper) EVMCallWithTracer(ctx context.Context, caller common.Address, contractAddr common.Address, inputBz []byte, tracer *tracing.Hooks) ([]byte, types.Logs, error) { +func (k Keeper) EVMCallWithTracer(ctx context.Context, caller common.Address, contractAddr common.Address, inputBz []byte, value *uint256.Int, tracer *tracing.Hooks) ([]byte, types.Logs, error) { ctx, evm, err := k.createEVM(ctx, caller, tracer) if err != nil { return nil, nil, err } - // check the contract is empty or not - if !types.IsPrecompileAddress(contractAddr) && evm.StateDB.GetCodeSize(contractAddr) == 0 { - return nil, nil, types.ErrEmptyContractAddress.Wrap(contractAddr.String()) - } - sdkCtx := sdk.UnwrapSDKContext(ctx) gasBalance := k.computeGasLimit(sdkCtx) + if value == nil { + value = uint256.NewInt(0) + } retBz, gasRemaining, err := evm.Call( vm.AccountRef(caller), contractAddr, inputBz, gasBalance, - uint256.NewInt(0), + value, ) // London enforced gasUsed := types.CalGasUsed(gasBalance, gasRemaining, evm.StateDB.GetRefund()) sdkCtx.GasMeter().ConsumeGas(gasUsed, "EVM gas consumption") if err != nil { + if err == vm.ErrExecutionReverted { + err = types.NewRevertError(common.CopyBytes(retBz)) + } + return nil, nil, types.ErrEVMCallFailed.Wrap(err.Error()) } @@ -258,26 +328,29 @@ func (k Keeper) EVMCallWithTracer(ctx context.Context, caller common.Address, co } // EVMCreate creates a new contract with the given code. -func (k Keeper) EVMCreate(ctx context.Context, caller common.Address, codeBz []byte) ([]byte, common.Address, error) { - return k.EVMCreateWithTracer(ctx, caller, codeBz, nil, nil) +func (k Keeper) EVMCreate(ctx context.Context, caller common.Address, codeBz []byte, value *uint256.Int) ([]byte, common.Address, types.Logs, error) { + return k.EVMCreateWithTracer(ctx, caller, codeBz, value, nil, nil) } // EVMCreate creates a new contract with the given code. -func (k Keeper) EVMCreate2(ctx context.Context, caller common.Address, codeBz []byte, salt uint64) ([]byte, common.Address, error) { - return k.EVMCreateWithTracer(ctx, caller, codeBz, &salt, nil) +func (k Keeper) EVMCreate2(ctx context.Context, caller common.Address, codeBz []byte, value *uint256.Int, salt uint64) ([]byte, common.Address, types.Logs, error) { + return k.EVMCreateWithTracer(ctx, caller, codeBz, value, &salt, nil) } // EVMCreateWithTracer creates a new contract with the given code and tracer. // if salt is nil, it will create a contract with the CREATE opcode. // if salt is not nil, it will create a contract with the CREATE2 opcode. -func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, codeBz []byte, salt *uint64, tracer *tracing.Hooks) (retBz []byte, contractAddr common.Address, err error) { +func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, codeBz []byte, value *uint256.Int, salt *uint64, tracer *tracing.Hooks) (retBz []byte, contractAddr common.Address, logs types.Logs, err error) { ctx, evm, err := k.createEVM(ctx, caller, tracer) if err != nil { - return nil, common.Address{}, err + return nil, common.Address{}, nil, err } sdkCtx := sdk.UnwrapSDKContext(ctx) gasBalance := k.computeGasLimit(sdkCtx) + if value == nil { + value = uint256.NewInt(0) + } var gasRemaining uint64 if salt == nil { @@ -285,14 +358,14 @@ func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, vm.AccountRef(caller), codeBz, gasBalance, - uint256.NewInt(0), + value, ) } else { retBz, contractAddr, gasRemaining, err = evm.Create2( vm.AccountRef(caller), codeBz, gasBalance, - uint256.NewInt(0), + value, uint256.NewInt(*salt), ) } @@ -301,31 +374,35 @@ func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, gasUsed := types.CalGasUsed(gasBalance, gasRemaining, evm.StateDB.GetRefund()) sdkCtx.GasMeter().ConsumeGas(gasUsed, "EVM gas consumption") if err != nil { - return nil, common.Address{}, types.ErrEVMCreateFailed.Wrap(err.Error()) + if err == vm.ErrExecutionReverted { + err = types.NewRevertError(common.CopyBytes(retBz)) + } + + return nil, common.Address{}, nil, types.ErrEVMCreateFailed.Wrap(err.Error()) } // commit state transition stateDB := evm.StateDB.(*state.StateDB) stateRoot, err := stateDB.Commit(evm.Context.BlockNumber.Uint64(), true) if err != nil { - return nil, common.Address{}, err + return nil, common.Address{}, nil, err } // commit trie db if stateRoot != coretypes.EmptyRootHash { err := stateDB.Database().TrieDB().Commit(stateRoot, false) if err != nil { - return nil, common.Address{}, err + return nil, common.Address{}, nil, err } } // update state root if err := k.VMRoot.Set(ctx, stateRoot[:]); err != nil { - return nil, common.Address{}, err + return nil, common.Address{}, nil, err } retHex := hexutil.Encode(retBz) - logs := types.NewLogs(stateDB.Logs()) + logs = types.NewLogs(stateDB.Logs()) // emit action events sdkCtx.EventManager().EmitEvent(sdk.NewEvent( @@ -339,7 +416,7 @@ func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, for i, log := range logs { jsonBz, err := json.Marshal(log) if err != nil { - return nil, common.Address{}, types.ErrFailedToEncodeLogs.Wrap(err.Error()) + return nil, common.Address{}, nil, types.ErrFailedToEncodeLogs.Wrap(err.Error()) } attrs[i] = sdk.NewAttribute(types.AttributeKeyLog, string(jsonBz)) @@ -352,10 +429,10 @@ func (k Keeper) EVMCreateWithTracer(ctx context.Context, caller common.Address, // handle cosmos messages messages := sdkCtx.Value(types.CONTEXT_KEY_COSMOS_MESSAGES).(*[]sdk.Msg) if err := k.dispatchMessages(sdkCtx, *messages); err != nil { - return nil, common.Address{}, err + return nil, common.Address{}, nil, err } - return retBz, contractAddr, nil + return retBz, contractAddr, logs, nil } // nextContractAddress returns the next contract address which will be created by the given caller @@ -390,7 +467,6 @@ func (k Keeper) dispatchMessages(ctx context.Context, msgs []sdk.Msg) error { // and execute it res, err := handler(sdkCtx, msg) if err != nil { - fmt.Println(err) return err } diff --git a/x/evm/keeper/context_test.go b/x/evm/keeper/context_test.go index 829853b..8831967 100644 --- a/x/evm/keeper/context_test.go +++ b/x/evm/keeper/context_test.go @@ -1,15 +1,20 @@ package keeper_test import ( + "strings" "testing" + "cosmossdk.io/math" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/holiman/uint256" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/initia-labs/minievm/x/evm/contracts/counter" "github.com/initia-labs/minievm/x/evm/contracts/erc20" + "github.com/initia-labs/minievm/x/evm/types" "github.com/stretchr/testify/require" ) @@ -22,21 +27,54 @@ func Test_Create(t *testing.T) { require.NoError(t, err) caller := common.BytesToAddress(addr.Bytes()) - retBz, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz) + retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil) require.NoError(t, err) require.NotEmpty(t, retBz) require.Len(t, contractAddr, 20) } +func Test_CreateWithValue(t *testing.T) { + ctx, input := createDefaultTestInput(t) + _, _, addr := keyPubAddr() + + // fund addr + input.Faucet.Fund(ctx, addr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000000)) + + counterBz, err := hexutil.Decode(counter.CounterBin) + require.NoError(t, err) + + caller := common.BytesToAddress(addr.Bytes()) + tracerOutput := new(strings.Builder) + tracer := logger.NewJSONLogger(&logger.Config{ + EnableMemory: false, + DisableStack: false, + DisableStorage: false, + EnableReturnData: true, + }, tracerOutput) + + retBz, contractAddr, _, err := input.EVMKeeper.EVMCreateWithTracer(ctx, caller, counterBz, uint256.NewInt(100), nil, tracer) + require.NoError(t, err) + require.NotEmpty(t, retBz) + require.Len(t, contractAddr, 20) + + // check balance + balance, err := input.EVMKeeper.ERC20Keeper().GetBalance(ctx, contractAddr.Bytes(), sdk.DefaultBondDenom) + require.NoError(t, err) + require.Equal(t, balance, math.NewInt(100)) +} + func Test_Call(t *testing.T) { ctx, input := createDefaultTestInput(t) _, _, addr := keyPubAddr() + // fund addr + input.Faucet.Fund(ctx, addr, sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000000)) + counterBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) caller := common.BytesToAddress(addr.Bytes()) - retBz, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz) + retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil) require.NoError(t, err) require.NotEmpty(t, retBz) require.Len(t, contractAddr, 20) @@ -47,7 +85,7 @@ func Test_Call(t *testing.T) { queryInputBz, err := parsed.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -55,12 +93,18 @@ func Test_Call(t *testing.T) { inputBz, err := parsed.Pack("increase") require.NoError(t, err) - res, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz) + // call with value + res, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, inputBz, uint256.NewInt(100)) require.NoError(t, err) require.Empty(t, res) require.NotEmpty(t, logs) - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz) + // check balance + balance, err := input.EVMKeeper.ERC20Keeper().GetBalance(ctx, contractAddr.Bytes(), sdk.DefaultBondDenom) + require.NoError(t, err) + require.Equal(t, balance, math.NewInt(100)) + + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -72,6 +116,6 @@ func Test_Call(t *testing.T) { queryInputBz, err = erc20ABI.Pack("balanceOf", caller) require.NoError(t, err) - _, _, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz) - require.ErrorContains(t, err, vm.ErrExecutionReverted.Error()) + _, _, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil) + require.ErrorContains(t, err, types.ErrReverted.Error()) } diff --git a/x/evm/keeper/erc20.go b/x/evm/keeper/erc20.go index 936f451..39aebfc 100644 --- a/x/evm/keeper/erc20.go +++ b/x/evm/keeper/erc20.go @@ -47,6 +47,11 @@ func NewERC20Keeper(k *Keeper) (types.IERC20Keeper, error) { return &ERC20Keeper{k, erc20Bin, erc20ABI, factoryABI}, nil } +// GetERC20ABI implements IERC20Keeper. +func (k ERC20Keeper) GetERC20ABI() *abi.ABI { + return k.ERC20ABI +} + // BurnCoins implements IERC20Keeper. func (k ERC20Keeper) BurnCoins(ctx context.Context, addr sdk.AccAddress, amount sdk.Coins) error { evmAddr, err := k.convertToEVMAddress(ctx, addr, false) @@ -77,7 +82,7 @@ func (k ERC20Keeper) BurnCoins(ctx context.Context, addr sdk.AccAddress, amount } // ignore the return values - _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz, nil) if err != nil { return err } @@ -307,7 +312,7 @@ func (k ERC20Keeper) MintCoins(ctx context.Context, addr sdk.AccAddress, amount return types.ErrFailedToPackABI.Wrap(err.Error()) } - ret, _, err := k.EVMCall(ctx, types.StdAddress, types.ERC20FactoryAddress(), inputBz) + ret, _, err := k.EVMCall(ctx, types.StdAddress, types.ERC20FactoryAddress(), inputBz, nil) if err != nil { return err } @@ -333,7 +338,7 @@ func (k ERC20Keeper) MintCoins(ctx context.Context, addr sdk.AccAddress, amount } // ignore the return values - _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz, nil) if err != nil { return err } @@ -365,7 +370,7 @@ func (k ERC20Keeper) SendCoins(ctx context.Context, fromAddr sdk.AccAddress, toA } // ignore the return values - _, _, err = k.EVMCall(ctx, evmFromAddr, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, evmFromAddr, contractAddr, inputBz, nil) if err != nil { return err } @@ -470,6 +475,15 @@ func (k ERC20Keeper) symbol(ctx context.Context, contractAddr common.Address) (s return symbol, nil } +func (k ERC20Keeper) GetDecimals(ctx context.Context, denom string) (uint8, error) { + contractAddr, err := types.DenomToContractAddr(ctx, k, denom) + if err != nil { + return 0, err + } + + return k.decimals(ctx, contractAddr) +} + func (k ERC20Keeper) decimals(ctx context.Context, contractAddr common.Address) (uint8, error) { inputBz, err := k.ERC20ABI.Pack("decimals") if err != nil { diff --git a/x/evm/keeper/erc20_stores_test.go b/x/evm/keeper/erc20_stores_test.go index 74055bd..26ef5d9 100644 --- a/x/evm/keeper/erc20_stores_test.go +++ b/x/evm/keeper/erc20_stores_test.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/holiman/uint256" "github.com/stretchr/testify/require" sdk "github.com/cosmos/cosmos-sdk/types" @@ -24,7 +25,7 @@ func deployCustomERC20(t *testing.T, ctx sdk.Context, input TestKeepers, caller inputBz, err := abi.Pack("", denom, denom, uint8(6)) require.NoError(t, err) - _, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, caller, append(bin, inputBz...)) + _, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, append(bin, inputBz...), uint256.NewInt(0)) if success { require.NoError(t, err) } else { diff --git a/x/evm/keeper/erc20_test.go b/x/evm/keeper/erc20_test.go index 265c6ec..4e7ab8e 100644 --- a/x/evm/keeper/erc20_test.go +++ b/x/evm/keeper/erc20_test.go @@ -23,7 +23,7 @@ func deployERC20(t *testing.T, ctx sdk.Context, input TestKeepers, caller common inputBz, err := abi.Pack("createERC20", denom, denom, uint8(6)) require.NoError(t, err) - ret, _, err := input.EVMKeeper.EVMCall(ctx, caller, types.ERC20FactoryAddress(), inputBz) + ret, _, err := input.EVMKeeper.EVMCall(ctx, caller, types.ERC20FactoryAddress(), inputBz, nil) require.NoError(t, err) return common.BytesToAddress(ret[12:]) @@ -39,7 +39,7 @@ func mintERC20(t *testing.T, ctx sdk.Context, input TestKeepers, caller, recipie erc20ContractAddr, err := types.DenomToContractAddr(ctx, &input.EVMKeeper, amount.Denom) require.NoError(t, err) - _, _, err = input.EVMKeeper.EVMCall(ctx, caller, erc20ContractAddr, inputBz) + _, _, err = input.EVMKeeper.EVMCall(ctx, caller, erc20ContractAddr, inputBz, nil) require.NoError(t, err) } @@ -182,12 +182,14 @@ func Test_GetSupply(t *testing.T) { require.True(t, has) erc20Keeper.IterateSupply(ctx, func(supply sdk.Coin) (bool, error) { - require.True(t, supply.Denom == "bar" || supply.Denom == fooDenom) + require.True(t, supply.Denom == "bar" || supply.Denom == fooDenom || supply.Denom == sdk.DefaultBondDenom) switch supply.Denom { case "bar": require.Equal(t, math.NewInt(200), supply.Amount) case fooDenom: require.Equal(t, math.NewInt(100), supply.Amount) + case sdk.DefaultBondDenom: + require.Equal(t, math.NewInt(1_000_000), supply.Amount) } return false, nil }) @@ -197,6 +199,7 @@ func Test_GetSupply(t *testing.T) { require.Equal(t, sdk.NewCoins( sdk.NewCoin("bar", math.NewInt(200)), sdk.NewCoin(fooDenom, math.NewInt(100)), + sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1_000_000)), ), supply) } diff --git a/x/evm/keeper/erc721.go b/x/evm/keeper/erc721.go index f9fd324..e05b9e6 100644 --- a/x/evm/keeper/erc721.go +++ b/x/evm/keeper/erc721.go @@ -54,7 +54,7 @@ func (k ERC721Keeper) CreateOrUpdateClass(ctx context.Context, classId, classUri return types.ErrFailedToPackABI.Wrap(err.Error()) } - ret, contractAddr, err := k.EVMCreate(ctx, types.StdAddress, append(k.ERC721Bin, inputBz...)) + ret, contractAddr, _, err := k.EVMCreate(ctx, types.StdAddress, append(k.ERC721Bin, inputBz...), nil) if err != nil { return err } @@ -118,7 +118,7 @@ func (k ERC721Keeper) Transfers(ctx context.Context, sender, receiver sdk.AccAdd } // ignore the return values - _, _, err = k.EVMCall(ctx, senderAddr, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, senderAddr, contractAddr, inputBz, nil) if err != nil { return err } @@ -135,7 +135,7 @@ func (k ERC721Keeper) Burn( return types.ErrFailedToPackABI.Wrap(err.Error()) } - _, _, err = k.EVMCall(ctx, owner, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, owner, contractAddr, inputBz, nil) if err != nil { return err } @@ -187,7 +187,7 @@ func (k ERC721Keeper) Mint( return types.ErrFailedToPackABI.Wrap(err.Error()) } - _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz) + _, _, err = k.EVMCall(ctx, types.StdAddress, contractAddr, inputBz, nil) if err != nil { return err } diff --git a/x/evm/keeper/genesis.go b/x/evm/keeper/genesis.go index 9c94eb0..ee560ce 100644 --- a/x/evm/keeper/genesis.go +++ b/x/evm/keeper/genesis.go @@ -20,7 +20,8 @@ func (k Keeper) Initialize(ctx context.Context) error { return err } - _, _, err = k.EVMCreate2(ctx, types.StdAddress, code, types.ERC20FactorySalt) + k.initializing = true + _, _, _, err = k.EVMCreate2(ctx, types.StdAddress, code, nil, types.ERC20FactorySalt) if err != nil { return err } diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 514cde6..92ae13c 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -55,6 +55,9 @@ type Keeper struct { precompiles precompiles queryCosmosWhitelist types.QueryCosmosWhitelist + + // flag to check if the keeper is in the process of initialization + initializing bool } func NewKeeper( diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index fcd70b8..e785da5 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -4,6 +4,7 @@ import ( "context" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/holiman/uint256" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -38,6 +39,10 @@ func (ms *msgServerImpl) Create(ctx context.Context, msg *types.MsgCreate) (*typ if err != nil { return nil, types.ErrInvalidHexString.Wrap(err.Error()) } + value, overflow := uint256.FromBig(msg.Value.BigInt()) + if overflow { + return nil, types.ErrInvalidValue.Wrap("value is out of range") + } // check the sender is allowed publisher params, err := ms.Params.Get(ctx) @@ -62,7 +67,7 @@ func (ms *msgServerImpl) Create(ctx context.Context, msg *types.MsgCreate) (*typ } // deploy a contract - retBz, contractAddr, err := ms.EVMCreate(ctx, caller, codeBz) + retBz, contractAddr, _, err := ms.EVMCreate(ctx, caller, codeBz, value) if err != nil { return nil, types.ErrEVMCallFailed.Wrap(err.Error()) } @@ -92,6 +97,10 @@ func (ms *msgServerImpl) Create2(ctx context.Context, msg *types.MsgCreate2) (*t if err != nil { return nil, types.ErrInvalidHexString.Wrap(err.Error()) } + value, overflow := uint256.FromBig(msg.Value.BigInt()) + if overflow { + return nil, types.ErrInvalidValue.Wrap("value is out of range") + } // check the sender is allowed publisher params, err := ms.Params.Get(ctx) @@ -116,7 +125,7 @@ func (ms *msgServerImpl) Create2(ctx context.Context, msg *types.MsgCreate2) (*t } // deploy a contract - retBz, contractAddr, err := ms.EVMCreate2(ctx, caller, codeBz, msg.Salt) + retBz, contractAddr, _, err := ms.EVMCreate2(ctx, caller, codeBz, value, msg.Salt) if err != nil { return nil, types.ErrEVMCallFailed.Wrap(err.Error()) } @@ -148,10 +157,14 @@ func (ms *msgServerImpl) Call(ctx context.Context, msg *types.MsgCall) (*types.M if err != nil { return nil, types.ErrInvalidHexString.Wrap(err.Error()) } + value, overflow := uint256.FromBig(msg.Value.BigInt()) + if overflow { + return nil, types.ErrInvalidValue.Wrap("value is out of range") + } - retBz, logs, err := ms.EVMCall(ctx, caller, contractAddr, inputBz) + retBz, logs, err := ms.EVMCall(ctx, caller, contractAddr, inputBz, value) if err != nil { - return nil, types.ErrEVMCreateFailed.Wrap(err.Error()) + return nil, types.ErrEVMCallFailed.Wrap(err.Error()) } return &types.MsgCallResponse{Result: hexutil.Encode(retBz), Logs: logs}, nil diff --git a/x/evm/keeper/msg_server_test.go b/x/evm/keeper/msg_server_test.go index 1960caa..35b21cc 100644 --- a/x/evm/keeper/msg_server_test.go +++ b/x/evm/keeper/msg_server_test.go @@ -83,7 +83,7 @@ func Test_MsgServer_Call(t *testing.T) { counterBz, err := hexutil.Decode(counter.CounterBin) require.NoError(t, err) - retBz, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz) + retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil) require.NoError(t, err) require.NotEmpty(t, retBz) require.Len(t, contractAddr, 20) @@ -94,7 +94,7 @@ func Test_MsgServer_Call(t *testing.T) { queryInputBz, err := parsed.Pack("count") require.NoError(t, err) - queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz) + queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) @@ -112,7 +112,7 @@ func Test_MsgServer_Call(t *testing.T) { require.Equal(t, "0x", res.Result) require.NotEmpty(t, res.Logs) - queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz) + queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil) require.NoError(t, err) require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes)) require.Empty(t, logs) diff --git a/x/evm/keeper/precompiles_test.go b/x/evm/keeper/precompiles_test.go index 038f6e9..6ea24ea 100644 --- a/x/evm/keeper/precompiles_test.go +++ b/x/evm/keeper/precompiles_test.go @@ -49,7 +49,7 @@ func Test_ExecuteCosmosMessage(t *testing.T) { `, addr, addr2)) require.NoError(t, err) - _, _, err = input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz) + _, _, err = input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz, nil) require.NoError(t, err) balance := input.BankKeeper.GetBalance(ctx, addr2, "bar") @@ -79,7 +79,7 @@ func Test_QueryCosmosMessage(t *testing.T) { }`, addr)) require.NoError(t, err) - retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz) + retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz, nil) require.NoError(t, err) unpackedRet, err := abi.Methods["query_cosmos"].Outputs.Unpack(retBz) @@ -109,7 +109,7 @@ func Test_QueryCosmosFromContract(t *testing.T) { require.NoError(t, err) caller := common.BytesToAddress(addr.Bytes()) - retBz, contractAddr, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz) + retBz, contractAddr, _, err := input.EVMKeeper.EVMCreate(ctx, caller, counterBz, nil) require.NoError(t, err) require.NotEmpty(t, retBz) require.Len(t, contractAddr, 20) @@ -123,7 +123,7 @@ func Test_QueryCosmosFromContract(t *testing.T) { }`, addr)) require.NoError(t, err) - retBz, _, err = input.EVMKeeper.EVMCall(ctx, contractAddr, types.CosmosPrecompileAddress, inputBz) + retBz, _, err = input.EVMKeeper.EVMCall(ctx, contractAddr, types.CosmosPrecompileAddress, inputBz, nil) require.NoError(t, err) unpackedRet, err := abi.Methods["query_cosmos"].Outputs.Unpack(retBz) @@ -159,7 +159,7 @@ func Test_ToDenom(t *testing.T) { inputBz, err := abi.Pack("to_denom", contractAddr) require.NoError(t, err) - retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz) + retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz, nil) require.NoError(t, err) unpackedRet, err := abi.Methods["to_denom"].Outputs.Unpack(retBz) @@ -191,7 +191,7 @@ func Test_ToERC20(t *testing.T) { inputBz, err := abi.Pack("to_erc20", "bar") require.NoError(t, err) - retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz) + retBz, _, err := input.EVMKeeper.EVMCall(ctx, evmAddr, types.CosmosPrecompileAddress, inputBz, nil) require.NoError(t, err) unpackedRet, err := abi.Methods["to_erc20"].Outputs.Unpack(retBz) diff --git a/x/evm/keeper/query_server.go b/x/evm/keeper/query_server.go index 28c250c..b3da1f7 100644 --- a/x/evm/keeper/query_server.go +++ b/x/evm/keeper/query_server.go @@ -7,6 +7,7 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/holiman/uint256" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -34,14 +35,22 @@ func (qs *queryServerImpl) Call(ctx context.Context, req *types.QueryCallRequest sdkCtx := sdk.UnwrapSDKContext(ctx) - sender, err := qs.ac.StringToBytes(req.Sender) - if err != nil { - return nil, err + caller := common.Address{} + if req.Sender != "" { + senderBz, err := qs.ac.StringToBytes(req.Sender) + if err != nil { + return nil, err + } + + caller = common.BytesToAddress(senderBz) } - contractAddr, err := types.ContractAddressFromString(qs.ac, req.ContractAddr) - if err != nil { - return nil, err + contractAddr := common.Address{} + if req.ContractAddr != "" { + contractAddr, err = types.ContractAddressFromString(qs.ac, req.ContractAddr) + if err != nil { + return nil, err + } } inputBz, err := hexutil.Decode(req.Input) @@ -49,6 +58,11 @@ func (qs *queryServerImpl) Call(ctx context.Context, req *types.QueryCallRequest return nil, err } + value, overflow := uint256.FromBig(req.Value.BigInt()) + if overflow { + return nil, types.ErrInvalidValue.Wrap("value is out of range") + } + var tracer *tracing.Hooks tracerOutput := new(strings.Builder) if req.TraceOptions != nil { @@ -62,8 +76,17 @@ func (qs *queryServerImpl) Call(ctx context.Context, req *types.QueryCallRequest // use cache context to rollback writes sdkCtx, _ = sdkCtx.CacheContext() - caller := common.BytesToAddress(sender) - retBz, logs, err := qs.EVMCallWithTracer(sdkCtx, caller, contractAddr, inputBz, tracer) + + var retBz []byte + var logs []types.Log + if contractAddr == (common.Address{}) { + // if contract address is not provided, then it's a contract creation + retBz, _, logs, err = qs.EVMCreateWithTracer(sdkCtx, caller, inputBz, value, nil, tracer) + } else { + retBz, logs, err = qs.EVMCallWithTracer(sdkCtx, caller, contractAddr, inputBz, value, tracer) + + } + if err != nil { return &types.QueryCallResponse{ Error: err.Error(), diff --git a/x/evm/keeper/txutils.go b/x/evm/keeper/txutils.go new file mode 100644 index 0000000..01785fd --- /dev/null +++ b/x/evm/keeper/txutils.go @@ -0,0 +1,334 @@ +package keeper + +import ( + "context" + "encoding/json" + "fmt" + "math/big" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/initia-labs/initia/crypto/ethsecp256k1" + "github.com/initia-labs/minievm/x/evm/types" +) + +const SignMode_SIGN_MODE_ETHEREUM = signing.SignMode(9999) + +type TxUtils struct { + *Keeper +} + +func NewTxUtils(k *Keeper) *TxUtils { + return &TxUtils{ + Keeper: k, + } +} + +func computeGasFeeAmount(gasFeeCap *big.Int, gas uint64, decimals uint8) *big.Int { + if gasFeeCap.Cmp(big.NewInt(0)) == 0 { + return big.NewInt(0) + } + + gasFeeCap = new(big.Int).Mul(gasFeeCap, new(big.Int).SetUint64(gas)) + gasFeeAmount := types.FromEthersUnit(decimals, gasFeeCap) + + // add 1 to the gas fee amount to avoid rounding errors + return new(big.Int).Add(gasFeeAmount, big.NewInt(1)) +} + +func (u *TxUtils) ConvertEthereumTxToCosmosTx(ctx context.Context, ethTx *coretypes.Transaction) (sdk.Tx, error) { + params, err := u.Params.Get(ctx) + if err != nil { + return nil, err + } + + feeDenom := params.FeeDenom + decimals, err := u.ERC20Keeper().GetDecimals(ctx, feeDenom) + if err != nil { + return nil, err + } + + gasFeeCap := ethTx.GasFeeCap() + if gasFeeCap == nil { + gasFeeCap = big.NewInt(0) + } + gasTipCap := ethTx.GasTipCap() + if gasTipCap == nil { + gasTipCap = big.NewInt(0) + } + + // convert gas fee unit from wei to cosmos fee unit + gasLimit := ethTx.Gas() + gasFeeAmount := computeGasFeeAmount(gasFeeCap, gasLimit, decimals) + feeAmount := sdk.NewCoins(sdk.NewCoin(params.FeeDenom, math.NewIntFromUint64(gasFeeAmount.Uint64()))) + + // convert value unit from wei to cosmos fee unit + value := types.FromEthersUnit(decimals, ethTx.Value()) + + // check if the value is correctly converted without dropping any precision + if types.ToEthersUint(decimals, value).Cmp(ethTx.Value()) != 0 { + return nil, types.ErrInvalidValue.Wrap("failed to convert value to token unit without dropping precision") + } + + // signer + chainID := sdk.UnwrapSDKContext(ctx).ChainID() + ethChainID := types.ConvertCosmosChainIDToEthereumChainID(chainID) + signer := coretypes.LatestSignerForChainID(ethChainID) + + // sig bytes + v, r, s := ethTx.RawSignatureValues() + + sigBytes := make([]byte, 65) + switch ethTx.Type() { + case coretypes.LegacyTxType: + sigBytes[64] = byte(new(big.Int).Sub(v, new(big.Int).Add(new(big.Int).Add(ethChainID, ethChainID), big.NewInt(35))).Uint64()) + case coretypes.DynamicFeeTxType: + sigBytes[64] = byte(v.Uint64()) + default: + return nil, sdkerrors.ErrorInvalidSigner.Wrapf("unsupported tx type: %d", ethTx.Type()) + } + + copy(sigBytes[32-len(r.Bytes()):32], r.Bytes()) + copy(sigBytes[64-len(s.Bytes()):64], s.Bytes()) + + sigData := &signing.SingleSignatureData{ + SignMode: SignMode_SIGN_MODE_ETHEREUM, + Signature: sigBytes, + } + + // recover pubkey + pubKeyBz, err := crypto.Ecrecover(signer.Hash(ethTx).Bytes(), sigBytes) + if err != nil { + return nil, sdkerrors.ErrorInvalidSigner.Wrapf("failed to recover pubkey: %v", err.Error()) + } + + // compress pubkey + compressedPubKey, err := ethsecp256k1.NewPubKeyFromBytes(pubKeyBz) + if err != nil { + return nil, sdkerrors.ErrorInvalidSigner.Wrapf("failed to create pubkey: %v", err.Error()) + } + + // construct signature + sig := signing.SignatureV2{ + PubKey: compressedPubKey, + Data: sigData, + Sequence: ethTx.Nonce(), + } + + // convert sender to string + sender, err := u.ac.BytesToString(compressedPubKey.Address().Bytes()) + if err != nil { + return nil, err + } + + sdkMsgs := []sdk.Msg{} + if ethTx.To() == nil { + sdkMsgs = append(sdkMsgs, &types.MsgCreate{ + Sender: sender, + Code: hexutil.Encode(ethTx.Data()), + Value: math.NewIntFromBigInt(value), + }) + } else { + sdkMsgs = append(sdkMsgs, &types.MsgCall{ + Sender: sender, + ContractAddr: ethTx.To().String(), + Input: hexutil.Encode(ethTx.Data()), + Value: math.NewIntFromBigInt(value), + }) + } + + txBuilder := authtx.NewTxConfig(u.cdc, authtx.DefaultSignModes).NewTxBuilder() + txBuilder.SetMsgs(sdkMsgs...) + txBuilder.SetFeeAmount(feeAmount) + txBuilder.SetGasLimit(gasLimit) + txBuilder.SetSignatures(sig) + + // set memo + memo, err := json.Marshal(metadata{ + Type: ethTx.Type(), + GasFeeCap: gasFeeCap.String(), + GasTipCap: gasTipCap.String(), + }) + if err != nil { + return nil, err + } + txBuilder.SetMemo(string(memo)) + + return txBuilder.GetTx(), nil +} + +type metadata struct { + Type uint8 `json:"type"` + GasFeeCap string `json:"gas_fee_cap"` + GasTipCap string `json:"gas_tip_cap"` +} + +// ConvertCosmosTxToEthereumTx converts a Cosmos SDK transaction to an Ethereum transaction. +// It returns nil if the transaction is not an EVM transaction. +func (u *TxUtils) ConvertCosmosTxToEthereumTx(ctx context.Context, sdkTx sdk.Tx) (*coretypes.Transaction, *common.Address, error) { + msgs := sdkTx.GetMsgs() + if len(msgs) != 1 { + return nil, nil, nil + } + + authTx := sdkTx.(authsigning.Tx) + memo := authTx.GetMemo() + if len(memo) == 0 { + return nil, nil, nil + } + md := metadata{} + if err := json.Unmarshal([]byte(memo), &md); err != nil { + return nil, nil, nil + } + + sigs, err := authTx.GetSignaturesV2() + if err != nil { + return nil, nil, err + } + if len(sigs) != 1 { + return nil, nil, nil + } + + fees := authTx.GetFee() + params, err := u.Params.Get(ctx) + if err != nil { + return nil, nil, err + } + decimals, err := u.ERC20Keeper().GetDecimals(ctx, params.FeeDenom) + if err != nil { + return nil, nil, err + } + + if len(fees) > 0 && fees[0].Denom != params.FeeDenom { + return nil, nil, nil + } + + var tx *coretypes.Transaction + + msg := msgs[0] + gas := authTx.GetGas() + typeUrl := sdk.MsgTypeURL(msg) + + sig := sigs[0] + cosmosSender := sig.PubKey.Address() + if len(cosmosSender.Bytes()) != common.AddressLength { + return nil, nil, nil + } + + sender := common.BytesToAddress(sig.PubKey.Address()) + sigData, ok := sig.Data.(*signing.SingleSignatureData) + if !ok { + return nil, nil, nil + } + + // filter out non-EVM transactions + if sigData.SignMode != SignMode_SIGN_MODE_ETHEREUM { + return nil, nil, nil + } + + var v, r, s []byte + if len(sigData.Signature) == 65 { + v, r, s = sigData.Signature[64:], sigData.Signature[:32], sigData.Signature[32:64] + } else if len(sigData.Signature) == 64 { + v, r, s = []byte{}, sigData.Signature[:32], sigData.Signature[32:64] + } else { + return nil, nil, nil + } + + gasFeeCap, ok := new(big.Int).SetString(md.GasFeeCap, 10) + if !ok { + return nil, nil, err + } + + gasTipCap, ok := new(big.Int).SetString(md.GasTipCap, 10) + if !ok { + return nil, nil, err + } + + var to *common.Address + var input []byte + var value *big.Int + switch typeUrl { + case "/minievm.evm.v1.MsgCall": + callMsg := msg.(*types.MsgCall) + contractAddr, err := types.ContractAddressFromString(u.ac, callMsg.ContractAddr) + if err != nil { + return nil, nil, err + } + + data, err := hexutil.Decode(callMsg.Input) + if err != nil { + return nil, nil, err + } + + to = &contractAddr + input = data + // When ethereum tx is converted into cosmos tx by ConvertEthereumTxToCosmosTx, + // the value is converted to cosmos fee unit from wei. + // So we need to convert it back to wei to get original ethereum tx and verify signature. + value = types.ToEthersUint(decimals, callMsg.Value.BigInt()) + case "/minievm.evm.v1.MsgCreate": + createMsg := msg.(*types.MsgCreate) + data, err := hexutil.Decode(createMsg.Code) + if err != nil { + return nil, nil, err + } + + to = nil + input = data + // Same as above (MsgCall) + value = types.ToEthersUint(decimals, createMsg.Value.BigInt()) + case "/minievm.evm.v1.MsgCreate2": + // create2 is not supported + return nil, nil, nil + } + + chainID := sdk.UnwrapSDKContext(ctx).ChainID() + ethChainID := types.ConvertCosmosChainIDToEthereumChainID(chainID) + + var txData coretypes.TxData + switch md.Type { + case coretypes.LegacyTxType: + txData = &coretypes.LegacyTx{ + Nonce: sig.Sequence, + Gas: gas, + To: to, + Data: input, + GasPrice: gasFeeCap, + Value: value, + R: new(big.Int).SetBytes(r), + S: new(big.Int).SetBytes(s), + V: new(big.Int).Add(new(big.Int).SetBytes(v), new(big.Int).SetUint64(35+ethChainID.Uint64()*2)), + } + case coretypes.DynamicFeeTxType: + txData = &coretypes.DynamicFeeTx{ + ChainID: types.ConvertCosmosChainIDToEthereumChainID(sdk.UnwrapSDKContext(ctx).ChainID()), + Nonce: sig.Sequence, + GasTipCap: gasTipCap, + GasFeeCap: gasFeeCap, + Gas: gas, + To: to, + Data: input, + Value: value, + R: new(big.Int).SetBytes(r), + S: new(big.Int).SetBytes(s), + V: new(big.Int).SetBytes(v), + } + default: + return nil, nil, fmt.Errorf("unsupported tx type: %d", md.Type) + } + + tx = coretypes.NewTx(txData) + + return tx, &sender, nil +} diff --git a/x/evm/keeper/txutils_test.go b/x/evm/keeper/txutils_test.go new file mode 100644 index 0000000..e078483 --- /dev/null +++ b/x/evm/keeper/txutils_test.go @@ -0,0 +1,213 @@ +package keeper_test + +import ( + "bytes" + "crypto/ecdsa" + "crypto/rand" + "math/big" + "testing" + + "cosmossdk.io/math" + "github.com/stretchr/testify/require" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx/signing" + authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/ethereum/go-ethereum/common/hexutil" + coretypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/initia-labs/initia/crypto/ethsecp256k1" + "github.com/initia-labs/minievm/x/evm/contracts/erc20_factory" + "github.com/initia-labs/minievm/x/evm/keeper" + "github.com/initia-labs/minievm/x/evm/types" +) + +func Test_DynamicFeeTxConversion(t *testing.T) { + ctx, input := createDefaultTestInput(t) + + _, _, addr := keyPubAddr() + input.Faucet.Mint(ctx, addr, sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000000000000))) + + feeAmount := int64(150000) + gasLimit := uint64(1000000) + ethFactoryAddr := types.ERC20FactoryAddress() + + abi, err := erc20_factory.Erc20FactoryMetaData.GetAbi() + require.NoError(t, err) + + inputBz, err := abi.Pack("createERC20", "bar", "bar", uint8(6)) + require.NoError(t, err) + + gasFeeCap := types.ToEthersUint(0, big.NewInt(feeAmount)) + gasFeeCap = gasFeeCap.Quo(gasFeeCap, new(big.Int).SetUint64(gasLimit)) + value := types.ToEthersUint(0, big.NewInt(100)) + + ethChainID := types.ConvertCosmosChainIDToEthereumChainID(ctx.ChainID()) + ethTx := coretypes.NewTx(&coretypes.DynamicFeeTx{ + ChainID: types.ConvertCosmosChainIDToEthereumChainID(ctx.ChainID()), + Nonce: 100, + GasTipCap: big.NewInt(100), + GasFeeCap: gasFeeCap, + Gas: gasLimit, + To: ðFactoryAddr, + Data: inputBz, + Value: value, + }) + + signer := coretypes.LatestSignerForChainID(ethChainID) + + randBytes := make([]byte, 64) + _, err = rand.Read(randBytes) + require.NoError(t, err) + reader := bytes.NewReader(randBytes) + + privKey, err := ecdsa.GenerateKey(crypto.S256(), reader) + require.NoError(t, err) + signedTx, err := coretypes.SignTx(ethTx, signer, privKey) + require.NoError(t, err) + + cosmosKey := ethsecp256k1.PrivKey{ + Key: crypto.FromECDSA(privKey), + } + addrBz := cosmosKey.PubKey().Address() + + // Convert to cosmos tx + sdkTx, err := keeper.NewTxUtils(&input.EVMKeeper).ConvertEthereumTxToCosmosTx(ctx, signedTx) + require.NoError(t, err) + + msgs := sdkTx.GetMsgs() + require.Len(t, msgs, 1) + msg, ok := msgs[0].(*types.MsgCall) + require.True(t, ok) + require.Equal(t, msg, &types.MsgCall{ + Sender: sdk.AccAddress(addrBz).String(), + ContractAddr: ethFactoryAddr.Hex(), + Input: hexutil.Encode(inputBz), + Value: math.NewInt(100), + }) + + authTx := sdkTx.(authsigning.Tx) + require.Equal(t, authTx.GetFee(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(feeAmount+1)))) + + sigs, err := authTx.GetSignaturesV2() + require.NoError(t, err) + require.Len(t, sigs, 1) + + sig := sigs[0] + require.Equal(t, sig.PubKey, cosmosKey.PubKey()) + require.Equal(t, sig.Sequence, uint64(100)) + + v, r, s := signedTx.RawSignatureValues() + sigData := sig.Data.(*signing.SingleSignatureData) + require.Equal(t, sigData.SignMode, keeper.SignMode_SIGN_MODE_ETHEREUM) + require.Equal(t, sigData.Signature, append(append(r.Bytes(), s.Bytes()...), byte(v.Uint64()))) + + // Convert back to ethereum tx + ethTx2, _, err := keeper.NewTxUtils(&input.EVMKeeper).ConvertCosmosTxToEthereumTx(ctx, sdkTx) + require.NoError(t, err) + EqualEthTransaction(t, signedTx, ethTx2) +} + +func Test_LegacyTxConversion(t *testing.T) { + ctx, input := createDefaultTestInput(t) + + _, _, addr := keyPubAddr() + input.Faucet.Mint(ctx, addr, sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1000000000000000000))) + + feeAmount := int64(150000) + gasLimit := uint64(1000000) + ethFactoryAddr := types.ERC20FactoryAddress() + + abi, err := erc20_factory.Erc20FactoryMetaData.GetAbi() + require.NoError(t, err) + + inputBz, err := abi.Pack("createERC20", "bar", "bar", uint8(6)) + require.NoError(t, err) + + gasFeeCap := types.ToEthersUint(0, big.NewInt(feeAmount)) + gasFeeCap = gasFeeCap.Quo(gasFeeCap, new(big.Int).SetUint64(gasLimit)) + value := types.ToEthersUint(0, big.NewInt(100)) + + ethChainID := types.ConvertCosmosChainIDToEthereumChainID(ctx.ChainID()) + ethTx := coretypes.NewTx(&coretypes.LegacyTx{ + Nonce: 100, + GasPrice: gasFeeCap, + Gas: gasLimit, + To: ðFactoryAddr, + Data: inputBz, + Value: value, + }) + + signer := coretypes.LatestSignerForChainID(ethChainID) + + randBytes := make([]byte, 64) + _, err = rand.Read(randBytes) + require.NoError(t, err) + reader := bytes.NewReader(randBytes) + + privKey, err := ecdsa.GenerateKey(crypto.S256(), reader) + require.NoError(t, err) + signedTx, err := coretypes.SignTx(ethTx, signer, privKey) + require.NoError(t, err) + + cosmosKey := ethsecp256k1.PrivKey{ + Key: crypto.FromECDSA(privKey), + } + addrBz := cosmosKey.PubKey().Address() + + // Convert to cosmos tx + sdkTx, err := keeper.NewTxUtils(&input.EVMKeeper).ConvertEthereumTxToCosmosTx(ctx, signedTx) + require.NoError(t, err) + + msgs := sdkTx.GetMsgs() + require.Len(t, msgs, 1) + msg, ok := msgs[0].(*types.MsgCall) + require.True(t, ok) + require.Equal(t, msg, &types.MsgCall{ + Sender: sdk.AccAddress(addrBz).String(), + ContractAddr: ethFactoryAddr.Hex(), + Input: hexutil.Encode(inputBz), + Value: math.NewInt(100), + }) + + authTx := sdkTx.(authsigning.Tx) + require.Equal(t, authTx.GetFee(), sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(feeAmount+1)))) + + sigs, err := authTx.GetSignaturesV2() + require.NoError(t, err) + require.Len(t, sigs, 1) + + sig := sigs[0] + require.Equal(t, sig.PubKey, cosmosKey.PubKey()) + require.Equal(t, sig.Sequence, uint64(100)) + + v, r, s := signedTx.RawSignatureValues() + sigData := sig.Data.(*signing.SingleSignatureData) + require.Equal(t, sigData.SignMode, keeper.SignMode_SIGN_MODE_ETHEREUM) + + sigBytes := make([]byte, 65) + copy(sigBytes[32-len(r.Bytes()):32], r.Bytes()) + copy(sigBytes[64-len(s.Bytes()):64], s.Bytes()) + sigBytes[64] = byte(v.Uint64() - (35 + ethChainID.Uint64()*2)) + + require.Equal(t, sigData.Signature, sigBytes) + + // Convert back to ethereum tx + ethTx2, _, err := keeper.NewTxUtils(&input.EVMKeeper).ConvertCosmosTxToEthereumTx(ctx, sdkTx) + require.NoError(t, err) + EqualEthTransaction(t, signedTx, ethTx2) + +} + +func EqualEthTransaction(t *testing.T, expected, actual *coretypes.Transaction) { + require.Equal(t, expected.ChainId(), actual.ChainId()) + require.Equal(t, expected.Nonce(), actual.Nonce()) + require.Equal(t, expected.GasTipCap(), actual.GasTipCap()) + require.Equal(t, expected.GasFeeCap(), actual.GasFeeCap()) + require.Equal(t, expected.Gas(), actual.Gas()) + require.Equal(t, expected.To(), actual.To()) + require.Equal(t, expected.Data(), actual.Data()) + require.Equal(t, expected.Value(), actual.Value()) + require.Equal(t, expected.Type(), actual.Type()) +} diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 27daa12..df95593 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -1,19 +1,41 @@ package types import ( + "context" + "encoding/binary" "math/big" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/params" + "golang.org/x/crypto/sha3" ) -func DefaultChainConfig() *params.ChainConfig { +func ConvertCosmosChainIDToEthereumChainID(chainID string) *big.Int { + hasher := sha3.NewLegacyKeccak256() + hasher.Write([]byte(chainID)) + hash := hasher.Sum(nil) + + // metamask max + metamaskMax := uint64(4503599627370476) + ethChainID := binary.BigEndian.Uint64(hash[:8]) % metamaskMax + return new(big.Int).SetUint64(ethChainID) +} + +func chainID(ctx context.Context) *big.Int { + sdkCtx := sdk.UnwrapSDKContext(ctx) + chainID := sdkCtx.ChainID() + + return ConvertCosmosChainIDToEthereumChainID(chainID) +} + +func DefaultChainConfig(ctx context.Context) *params.ChainConfig { shanghaiTime := uint64(0) cancunTime := uint64(0) pragueTime := uint64(0) verkleTime := uint64(0) return ¶ms.ChainConfig{ - ChainID: nil, + ChainID: chainID(ctx), HomesteadBlock: big.NewInt(0), DAOForkBlock: big.NewInt(0), DAOForkSupport: true, diff --git a/x/evm/types/chain_config_test.go b/x/evm/types/chain_config_test.go new file mode 100644 index 0000000..8f04b65 --- /dev/null +++ b/x/evm/types/chain_config_test.go @@ -0,0 +1,16 @@ +package types_test + +import ( + "math/big" + "testing" + + "github.com/initia-labs/minievm/x/evm/types" + "github.com/stretchr/testify/require" +) + +func Test_ConvertChainIdBiDirectional(t *testing.T) { + chainID := "minievm" + expectedEthChainID := new(big.Int).SetUint64(3212557983074529) + ethChainID := types.ConvertCosmosChainIDToEthereumChainID(chainID) + require.Equal(t, ethChainID, (expectedEthChainID)) +} diff --git a/x/evm/types/decimals.go b/x/evm/types/decimals.go new file mode 100644 index 0000000..a88eac0 --- /dev/null +++ b/x/evm/types/decimals.go @@ -0,0 +1,75 @@ +package types + +import "math/big" + +const ( + EtherDecimals = uint8(18) + GweiDecimals = uint8(9) +) + +func ToEthersUint(decimals uint8, val *big.Int) *big.Int { + if decimals == EtherDecimals { + return new(big.Int).Set(val) + } + + if decimals > EtherDecimals { + decimalDiff := decimals - EtherDecimals + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Div(val, exp) + } + + decimalDiff := EtherDecimals - decimals + + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Mul(val, exp) +} + +func ToGweiUint(decimals uint8, val *big.Int) *big.Int { + if decimals == GweiDecimals { + return new(big.Int).Set(val) + } + + if decimals > GweiDecimals { + decimalDiff := decimals - GweiDecimals + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Div(val, exp) + } + + decimalDiff := GweiDecimals - decimals + + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Mul(val, exp) +} + +func FromGweiUnit(decimals uint8, val *big.Int) *big.Int { + if decimals == GweiDecimals { + return new(big.Int).Set(val) + } + + if decimals > GweiDecimals { + decimalDiff := decimals - GweiDecimals + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Mul(val, exp) + } + + decimalDiff := GweiDecimals - decimals + + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Div(val, exp) +} + +func FromEthersUnit(decimals uint8, val *big.Int) *big.Int { + if decimals == EtherDecimals { + return new(big.Int).Set(val) + } + + if decimals > EtherDecimals { + decimalDiff := decimals - EtherDecimals + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Mul(val, exp) + } + + decimalDiff := EtherDecimals - decimals + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimalDiff)), nil) + return new(big.Int).Div(val, exp) +} diff --git a/x/evm/types/errors.go b/x/evm/types/errors.go index 7ca914c..448d81c 100644 --- a/x/evm/types/errors.go +++ b/x/evm/types/errors.go @@ -2,6 +2,8 @@ package types import ( errorsmod "cosmossdk.io/errors" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common/hexutil" ) // EVM Errors @@ -20,7 +22,6 @@ var ( ErrNonReadOnlyMethod = errorsmod.Register(ModuleName, 12, "Failed to call precompile in readonly mode") ErrAddressAlreadyExists = errorsmod.Register(ModuleName, 13, "Address already exists") ErrFailedToEncodeLogs = errorsmod.Register(ModuleName, 14, "Failed to encode logs") - ErrEmptyContractAddress = errorsmod.Register(ModuleName, 15, "Empty contract address") ErrPrecompileFailed = errorsmod.Register(ModuleName, 16, "Precompile failed") ErrNotSupportedCosmosMessage = errorsmod.Register(ModuleName, 17, "Not supported cosmos message") ErrNotSupportedCosmosQuery = errorsmod.Register(ModuleName, 18, "Not supported cosmos query") @@ -28,4 +29,17 @@ var ( ErrInvalidClassId = errorsmod.Register(ModuleName, 20, "Invalid class id") ErrCustomERC20NotAllowed = errorsmod.Register(ModuleName, 21, "Custom ERC20 is not allowed") ErrInvalidERC20FactoryAddr = errorsmod.Register(ModuleName, 22, "Invalid ERC20 factory address") + ErrReverted = errorsmod.Register(ModuleName, 23, "Reverted") + ErrInvalidValue = errorsmod.Register(ModuleName, 24, "Invalid value") ) + +func NewRevertError(revert []byte) error { + err := ErrReverted + + reason, errUnpack := abi.UnpackRevert(revert) + if errUnpack == nil { + return err.Wrapf("reason: %v, revert: %v", reason, hexutil.Encode(revert)) + } + + return err.Wrapf("revert: %v", hexutil.Encode(revert)) +} diff --git a/x/evm/types/expected_keeper.go b/x/evm/types/expected_keeper.go index bab7c4c..c4155f9 100644 --- a/x/evm/types/expected_keeper.go +++ b/x/evm/types/expected_keeper.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/query" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" ) @@ -55,6 +56,12 @@ type IERC20Keeper interface { // fungible asset GetMetadata(ctx context.Context, denom string) (banktypes.Metadata, error) + + // ABI + GetERC20ABI() *abi.ABI + + // erc20 queries + GetDecimals(ctx context.Context, denom string) (uint8, error) } type IERC721Keeper interface { diff --git a/x/evm/types/log.go b/x/evm/types/log.go index 5a9eb86..29ac14c 100644 --- a/x/evm/types/log.go +++ b/x/evm/types/log.go @@ -1,6 +1,7 @@ package types import ( + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" coretypes "github.com/ethereum/go-ethereum/core/types" ) @@ -23,8 +24,30 @@ func NewLog(ethLog *coretypes.Log) Log { } return Log{ - Address: ethLog.Address.String(), + Address: ethLog.Address.Hex(), Topics: topics, Data: hexutil.Encode(ethLog.Data), } } + +func (l Logs) ToEthLogs() []*coretypes.Log { + logs := make([]*coretypes.Log, len(l)) + for i, log := range l { + logs[i] = log.ToEthLog() + } + + return logs +} + +func (l Log) ToEthLog() *coretypes.Log { + topics := make([]common.Hash, len(l.Topics)) + for i, topic := range l.Topics { + topics[i] = common.HexToHash(topic) + } + + return &coretypes.Log{ + Address: common.HexToAddress(l.Address), + Topics: topics, + Data: hexutil.MustDecode(l.Data), + } +} diff --git a/x/evm/types/params.go b/x/evm/types/params.go index 8c65d4a..b639cd9 100644 --- a/x/evm/types/params.go +++ b/x/evm/types/params.go @@ -2,12 +2,15 @@ package types import ( "cosmossdk.io/core/address" + sdk "github.com/cosmos/cosmos-sdk/types" + "gopkg.in/yaml.v3" ) func DefaultParams() Params { return Params{ AllowCustomERC20: true, + FeeDenom: sdk.DefaultBondDenom, } } diff --git a/x/evm/types/query.pb.go b/x/evm/types/query.pb.go index 7486e97..b04d763 100644 --- a/x/evm/types/query.pb.go +++ b/x/evm/types/query.pb.go @@ -5,6 +5,7 @@ package types import ( context "context" + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/cosmos-sdk/types/tx/amino" _ "github.com/cosmos/gogoproto/gogoproto" @@ -200,9 +201,11 @@ type QueryCallRequest struct { ContractAddr string `protobuf:"bytes,2,opt,name=contract_addr,json=contractAddr,proto3" json:"contract_addr,omitempty"` // hex encoded call input Input string `protobuf:"bytes,3,opt,name=input,proto3" json:"input,omitempty"` + // Value is the amount of fee denom token to transfer to the contract. + Value cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value"` // whether to trace the call // `nil` means no trace - TraceOptions *TraceOptions `protobuf:"bytes,4,opt,name=trace_options,json=traceOptions,proto3" json:"trace_options,omitempty"` + TraceOptions *TraceOptions `protobuf:"bytes,5,opt,name=trace_options,json=traceOptions,proto3" json:"trace_options,omitempty"` } func (m *QueryCallRequest) Reset() { *m = QueryCallRequest{} } @@ -580,62 +583,64 @@ func init() { func init() { proto.RegisterFile("minievm/evm/v1/query.proto", fileDescriptor_2bf9e0bee7cfd1a4) } var fileDescriptor_2bf9e0bee7cfd1a4 = []byte{ - // 873 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4f, 0x8f, 0xdb, 0x44, - 0x14, 0x8f, 0x77, 0x9d, 0x34, 0xfb, 0xb2, 0xad, 0xb6, 0xb3, 0xd1, 0xca, 0xb5, 0x8a, 0x93, 0xba, - 0xfc, 0x89, 0x56, 0x6c, 0xdc, 0x86, 0x4a, 0x45, 0xbd, 0x35, 0x54, 0x42, 0x82, 0x22, 0xc0, 0xe5, - 0xc4, 0x25, 0x9a, 0x8d, 0x47, 0xae, 0xb5, 0xb1, 0x27, 0xeb, 0x19, 0x07, 0x42, 0x55, 0x0e, 0x88, - 0x0f, 0x80, 0xe0, 0xc8, 0x85, 0x03, 0x87, 0x3d, 0x72, 0xe3, 0x2b, 0xec, 0xb1, 0x12, 0x17, 0x4e, - 0x08, 0xb2, 0x48, 0xf0, 0x31, 0xd0, 0x3c, 0x8f, 0xdb, 0xc4, 0xf9, 0xa3, 0xe5, 0x90, 0x68, 0xde, - 0x9b, 0xdf, 0x9b, 0xdf, 0x6f, 0xde, 0x7b, 0xf3, 0x0c, 0x76, 0x1c, 0x25, 0x11, 0x9b, 0xc4, 0x9e, - 0xfa, 0x4d, 0xee, 0x7a, 0xa7, 0x19, 0x4b, 0xa7, 0xdd, 0x71, 0xca, 0x25, 0x27, 0xd7, 0xf4, 0x5e, - 0x57, 0xfd, 0x26, 0x77, 0xed, 0xeb, 0x34, 0x8e, 0x12, 0xee, 0xe1, 0x7f, 0x0e, 0xb1, 0x9b, 0x21, - 0x0f, 0x39, 0x2e, 0x3d, 0xb5, 0xd2, 0xde, 0x9b, 0x21, 0xe7, 0xe1, 0x88, 0x79, 0x74, 0x1c, 0x79, - 0x34, 0x49, 0xb8, 0xa4, 0x32, 0xe2, 0x89, 0xd0, 0xbb, 0x65, 0x4a, 0x39, 0x1d, 0x33, 0xbd, 0xe7, - 0xde, 0x87, 0xbd, 0x4f, 0x95, 0x82, 0xf7, 0x78, 0xc0, 0x7c, 0x76, 0x9a, 0x31, 0x21, 0xc9, 0x6d, - 0xb8, 0x3a, 0xe4, 0x89, 0x4c, 0xe9, 0x50, 0x0e, 0x68, 0x10, 0xa4, 0x96, 0xd1, 0x36, 0x3a, 0x3b, - 0xfe, 0x6e, 0xe1, 0x7c, 0x18, 0x04, 0xa9, 0x7b, 0x04, 0xd7, 0xe7, 0x02, 0xc5, 0x98, 0x27, 0x82, - 0x11, 0x02, 0xe6, 0x90, 0x07, 0x4c, 0x07, 0xe0, 0xfa, 0x81, 0xf9, 0xef, 0x4f, 0x2d, 0xc3, 0xfd, - 0x40, 0xc3, 0x9f, 0x48, 0x2a, 0xff, 0x17, 0x11, 0xd9, 0x83, 0xed, 0x13, 0x36, 0xb5, 0xb6, 0x70, - 0x4b, 0x2d, 0xdd, 0x3b, 0x40, 0xe6, 0xcf, 0xd2, 0xdc, 0x4d, 0xa8, 0x4e, 0xe8, 0x28, 0x2b, 0xc8, - 0x73, 0x43, 0xb3, 0x9f, 0x19, 0xc5, 0x35, 0xe9, 0x68, 0x54, 0xb0, 0x1f, 0x40, 0x4d, 0xb0, 0x24, - 0x60, 0x05, 0xad, 0xb6, 0x96, 0x55, 0x6d, 0xad, 0x50, 0xd5, 0x84, 0x6a, 0x94, 0x8c, 0x33, 0x69, - 0x6d, 0xe7, 0x6c, 0x68, 0x90, 0x87, 0x70, 0x55, 0x41, 0xd8, 0x80, 0x8f, 0xb1, 0x00, 0x96, 0xd9, - 0x36, 0x3a, 0x8d, 0xde, 0xcd, 0xee, 0x62, 0x61, 0xbb, 0x9f, 0x29, 0xd0, 0xc7, 0x39, 0xc6, 0xdf, - 0x95, 0x73, 0x96, 0xfb, 0xa3, 0x01, 0xbb, 0xf3, 0xdb, 0xa4, 0x05, 0x8d, 0x2f, 0x22, 0xf9, 0x74, - 0x10, 0xb3, 0x98, 0xa7, 0x53, 0xd4, 0x5a, 0xf7, 0x41, 0xb9, 0x3e, 0x42, 0x0f, 0x79, 0x0d, 0xd0, - 0x1a, 0x08, 0x49, 0x87, 0x27, 0x28, 0xb6, 0xee, 0xef, 0x28, 0xcf, 0x13, 0xe5, 0x20, 0xb7, 0x60, - 0x57, 0x6f, 0xf3, 0x94, 0x86, 0x0c, 0x05, 0xd7, 0xfd, 0x46, 0x0e, 0x40, 0x17, 0xe9, 0xc0, 0x1e, - 0x42, 0x52, 0x26, 0xb3, 0x34, 0x19, 0x04, 0x54, 0x52, 0x54, 0x5e, 0xf7, 0xaf, 0x29, 0xbf, 0x8f, - 0xee, 0x47, 0x54, 0x52, 0xf7, 0x57, 0xa3, 0x28, 0x3b, 0x26, 0x52, 0xa7, 0xde, 0x86, 0x7a, 0xaa, - 0xd7, 0x3a, 0x97, 0x2f, 0x6d, 0x72, 0x03, 0xea, 0x99, 0x60, 0xc1, 0x20, 0xa4, 0x02, 0xb5, 0x99, - 0xfe, 0x15, 0x65, 0xbf, 0x4f, 0x05, 0xe9, 0x81, 0x39, 0xe2, 0xa1, 0xb0, 0xb6, 0xdb, 0xdb, 0x9d, - 0x46, 0x6f, 0xbf, 0x9c, 0xa4, 0xc7, 0x3c, 0xec, 0xef, 0x9c, 0xff, 0xd1, 0xaa, 0x9c, 0xfd, 0xf3, - 0xcb, 0xa1, 0xe1, 0x23, 0x56, 0xdd, 0x46, 0x67, 0x38, 0x93, 0x2a, 0xfd, 0x26, 0xd2, 0x35, 0xf2, - 0x14, 0xa2, 0x4b, 0x95, 0x86, 0xa5, 0x29, 0x4f, 0xad, 0x6a, 0x5e, 0x1a, 0x34, 0xdc, 0xfb, 0xd0, - 0xd2, 0xfd, 0xfa, 0xaa, 0x8a, 0xfd, 0xe9, 0x23, 0x96, 0xf0, 0xb8, 0x68, 0x88, 0x26, 0x54, 0x03, - 0x65, 0x17, 0x1d, 0x84, 0x86, 0xdb, 0x87, 0xf6, 0xfa, 0x40, 0x7d, 0x49, 0x0b, 0xae, 0xa8, 0x4e, - 0x61, 0x42, 0xe8, 0xd8, 0xc2, 0xd4, 0xfd, 0xf7, 0xae, 0xce, 0xda, 0x02, 0xdd, 0xa5, 0x9e, 0x59, - 0xd1, 0xeb, 0x8b, 0x7c, 0x2b, 0x95, 0x6a, 0xae, 0xa6, 0x8e, 0xf8, 0x84, 0xa6, 0x34, 0x16, 0x9a, - 0xcc, 0xfd, 0x10, 0xf6, 0x17, 0xbc, 0xfa, 0xa0, 0x7b, 0x50, 0x1b, 0xa3, 0x07, 0x4f, 0x6a, 0xf4, - 0x0e, 0xca, 0x45, 0xc8, 0xf1, 0x7d, 0x53, 0xd5, 0xc1, 0xd7, 0xd8, 0xde, 0xf7, 0x35, 0xa8, 0xe2, - 0x69, 0xe4, 0x2b, 0x30, 0xd5, 0x00, 0x20, 0xed, 0x72, 0x5c, 0x79, 0xa8, 0xd8, 0xb7, 0x36, 0x20, - 0x72, 0x31, 0xee, 0xd1, 0x37, 0xbf, 0xfd, 0xfd, 0xc3, 0xd6, 0x5b, 0xe4, 0x0d, 0xaf, 0x34, 0xb0, - 0xd4, 0x1c, 0x11, 0xde, 0xb3, 0x85, 0x6c, 0x3d, 0x27, 0xdf, 0x1a, 0x50, 0xc5, 0x11, 0x40, 0x56, - 0x9f, 0x3d, 0x3f, 0x6a, 0x6c, 0x77, 0x13, 0x44, 0xf3, 0xdf, 0x43, 0xfe, 0x2e, 0x79, 0xbb, 0xcc, - 0x2f, 0x14, 0x6c, 0x49, 0x80, 0xf7, 0xec, 0x84, 0x4d, 0x9f, 0x93, 0x9f, 0x0d, 0xd8, 0x5f, 0xd1, - 0x1b, 0xc4, 0x5b, 0x73, 0xe1, 0x75, 0xed, 0x67, 0xdf, 0xb9, 0x7c, 0x80, 0x16, 0x7c, 0x88, 0x82, - 0x5f, 0x27, 0xee, 0x72, 0xc2, 0xf2, 0x20, 0xe1, 0x1d, 0x4f, 0x07, 0xd8, 0x1c, 0xe4, 0x6b, 0xa8, - 0xe6, 0xba, 0x56, 0x27, 0x6b, 0x41, 0x89, 0xbb, 0x09, 0xa2, 0xb9, 0xbb, 0xc8, 0xdd, 0x21, 0x6f, - 0x96, 0xb9, 0x91, 0x6e, 0xb9, 0x5a, 0x23, 0x30, 0xd5, 0xcc, 0x58, 0xd7, 0x29, 0xaf, 0xe6, 0xf2, - 0xba, 0x4e, 0x99, 0x1b, 0x38, 0x6e, 0x0b, 0xc9, 0x6f, 0x3c, 0x30, 0x0e, 0xdd, 0xe6, 0xd2, 0xdd, - 0x15, 0xcb, 0x29, 0xd4, 0xf2, 0xce, 0x25, 0xab, 0xef, 0xb2, 0xf0, 0x38, 0xec, 0xdb, 0x1b, 0x31, - 0x9a, 0xd3, 0x41, 0x4e, 0x8b, 0x1c, 0x94, 0x09, 0xf3, 0x47, 0xd1, 0x7f, 0x7c, 0xfe, 0x97, 0x53, - 0x39, 0x9b, 0x39, 0x95, 0xf3, 0x99, 0x63, 0xbc, 0x98, 0x39, 0xc6, 0x9f, 0x33, 0xc7, 0xf8, 0xee, - 0xc2, 0xa9, 0xbc, 0xb8, 0x70, 0x2a, 0xbf, 0x5f, 0x38, 0x95, 0xcf, 0x0f, 0xc3, 0x48, 0x3e, 0xcd, - 0x8e, 0xbb, 0x43, 0x1e, 0x7b, 0x51, 0x12, 0xc9, 0x88, 0x1e, 0x8d, 0xe8, 0xb1, 0x78, 0x79, 0xde, - 0x97, 0x78, 0x22, 0x7e, 0x9d, 0x8f, 0x6b, 0xf8, 0x79, 0x7e, 0xe7, 0xbf, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x00, 0xf9, 0x6b, 0x54, 0x2f, 0x08, 0x00, 0x00, + // 907 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xf7, 0x26, 0xb6, 0xeb, 0x3c, 0xa7, 0x55, 0x3a, 0x31, 0x91, 0x6b, 0x95, 0xb5, 0x3b, 0xe5, + 0x8f, 0x15, 0x91, 0xdd, 0xd6, 0x54, 0x6a, 0xd5, 0x5b, 0x4d, 0x25, 0x04, 0x14, 0x01, 0x5b, 0x4e, + 0x5c, 0xac, 0x89, 0x77, 0xb4, 0x59, 0xc5, 0xbb, 0xe3, 0xec, 0xcc, 0x06, 0x4c, 0x55, 0x0e, 0x88, + 0x0f, 0x80, 0xe0, 0xc8, 0x85, 0x03, 0x87, 0x1e, 0xb9, 0xf1, 0x15, 0x72, 0xac, 0xc4, 0x05, 0x71, + 0xa8, 0xc0, 0x41, 0x82, 0x8f, 0x81, 0xe6, 0xed, 0x6c, 0x6b, 0xaf, 0xff, 0xa8, 0x3d, 0xd8, 0x9a, + 0xf7, 0xe6, 0xf7, 0xde, 0xef, 0xfd, 0x9b, 0xb7, 0xd0, 0x8a, 0xc2, 0x38, 0xe4, 0xa7, 0x91, 0xab, + 0x7f, 0xa7, 0x37, 0xdd, 0x93, 0x94, 0x27, 0x13, 0x67, 0x9c, 0x08, 0x25, 0xc8, 0x25, 0x73, 0xe7, + 0xe8, 0xdf, 0xe9, 0xcd, 0xd6, 0x65, 0x16, 0x85, 0xb1, 0x70, 0xf1, 0x3f, 0x83, 0xb4, 0x1a, 0x81, + 0x08, 0x04, 0x1e, 0x5d, 0x7d, 0x32, 0xda, 0xab, 0x81, 0x10, 0xc1, 0x88, 0xbb, 0x6c, 0x1c, 0xba, + 0x2c, 0x8e, 0x85, 0x62, 0x2a, 0x14, 0xb1, 0x34, 0xb7, 0x45, 0x4a, 0x35, 0x19, 0x73, 0x73, 0x47, + 0x6f, 0xc3, 0xce, 0x67, 0x3a, 0x82, 0xf7, 0x84, 0xcf, 0x3d, 0x7e, 0x92, 0x72, 0xa9, 0xc8, 0x75, + 0xb8, 0x38, 0x14, 0xb1, 0x4a, 0xd8, 0x50, 0x0d, 0x98, 0xef, 0x27, 0x4d, 0xab, 0x63, 0x75, 0xb7, + 0xbc, 0xed, 0x5c, 0x79, 0xcf, 0xf7, 0x13, 0x7a, 0x00, 0x97, 0x67, 0x0c, 0xe5, 0x58, 0xc4, 0x92, + 0x13, 0x02, 0xe5, 0xa1, 0xf0, 0xb9, 0x31, 0xc0, 0xf3, 0xdd, 0xf2, 0x7f, 0x3f, 0xb7, 0x2d, 0xfa, + 0xa1, 0x81, 0x3f, 0x54, 0x4c, 0xbd, 0x12, 0x11, 0xd9, 0x81, 0xcd, 0x63, 0x3e, 0x69, 0x6e, 0xe0, + 0x95, 0x3e, 0xd2, 0x1b, 0x40, 0x66, 0x7d, 0x19, 0xee, 0x06, 0x54, 0x4e, 0xd9, 0x28, 0xcd, 0xc9, + 0x33, 0xc1, 0xb0, 0x4f, 0xad, 0x3c, 0x4d, 0x36, 0x1a, 0xe5, 0xec, 0x7b, 0x50, 0x95, 0x3c, 0xf6, + 0x79, 0x4e, 0x6b, 0xa4, 0xc5, 0xa8, 0x36, 0x96, 0x44, 0xd5, 0x80, 0x4a, 0x18, 0x8f, 0x53, 0xd5, + 0xdc, 0xcc, 0xd8, 0x50, 0x20, 0x77, 0xf2, 0x18, 0xca, 0x5a, 0xdb, 0xa7, 0x67, 0xcf, 0xda, 0xa5, + 0x3f, 0x9f, 0xb5, 0x5f, 0x1b, 0x0a, 0x19, 0x09, 0x29, 0xfd, 0x63, 0x27, 0x14, 0x6e, 0xc4, 0xd4, + 0x91, 0xf3, 0x41, 0xac, 0x9e, 0xfc, 0xfb, 0xeb, 0xbe, 0x65, 0xe2, 0x24, 0xf7, 0xe0, 0xa2, 0x76, + 0xce, 0x07, 0x62, 0x8c, 0xad, 0x6b, 0x56, 0x3a, 0x56, 0xb7, 0xde, 0xbb, 0xea, 0xcc, 0x8f, 0x84, + 0xf3, 0xb9, 0x06, 0x7d, 0x92, 0x61, 0xbc, 0x6d, 0x35, 0x23, 0xd1, 0x9f, 0x2c, 0xd8, 0x9e, 0xbd, + 0x26, 0x6d, 0xa8, 0x7f, 0x19, 0xaa, 0xa3, 0x41, 0xc4, 0x23, 0x91, 0x4c, 0x30, 0xcb, 0x9a, 0x07, + 0x5a, 0xf5, 0x31, 0x6a, 0xc8, 0xeb, 0x80, 0xd2, 0x40, 0x2a, 0x36, 0x3c, 0xc6, 0x34, 0x6b, 0xde, + 0x96, 0xd6, 0x3c, 0xd4, 0x0a, 0x72, 0x0d, 0xb6, 0xcd, 0xb5, 0x48, 0x58, 0xc0, 0x31, 0xd5, 0x9a, + 0x57, 0xcf, 0x00, 0xa8, 0x22, 0x5d, 0xd8, 0x41, 0x48, 0xc2, 0x55, 0x9a, 0xc4, 0x03, 0x9f, 0x29, + 0x86, 0xb9, 0xd7, 0xbc, 0x4b, 0x5a, 0xef, 0xa1, 0xfa, 0x3e, 0x53, 0x8c, 0xfe, 0x66, 0xe5, 0x03, + 0x83, 0x2d, 0x30, 0x4d, 0x6b, 0x41, 0x2d, 0x31, 0x67, 0xd3, 0x85, 0xe7, 0x32, 0xb9, 0x02, 0xb5, + 0x54, 0x72, 0x7f, 0x10, 0x30, 0x89, 0xb1, 0x95, 0xbd, 0x0b, 0x5a, 0x7e, 0x9f, 0x49, 0xd2, 0x83, + 0xf2, 0x48, 0x04, 0xb2, 0xb9, 0xd9, 0xd9, 0xec, 0xd6, 0x7b, 0xbb, 0xc5, 0x22, 0x3d, 0x10, 0x41, + 0x7f, 0x4b, 0xd7, 0x3e, 0x2b, 0x31, 0x62, 0x75, 0x36, 0xa6, 0xc2, 0xa9, 0xd2, 0x8d, 0xc3, 0x16, + 0x79, 0xf5, 0xac, 0x84, 0xa8, 0xd2, 0x4d, 0xe5, 0x49, 0x22, 0x12, 0x2c, 0xfe, 0x96, 0x97, 0x09, + 0xf4, 0x36, 0xb4, 0xcd, 0xa4, 0xbf, 0xe8, 0x7f, 0x7f, 0x72, 0x9f, 0xc7, 0x22, 0xca, 0x47, 0xa9, + 0x01, 0x15, 0x5f, 0xcb, 0xf9, 0xec, 0xa1, 0x40, 0xfb, 0xd0, 0x59, 0x6d, 0x68, 0x92, 0x6c, 0xc2, + 0x05, 0x3d, 0x63, 0x5c, 0x4a, 0x63, 0x9b, 0x8b, 0x66, 0x72, 0xef, 0x98, 0xaa, 0xcd, 0xd1, 0xbd, + 0xd4, 0x03, 0xcd, 0x5f, 0xc9, 0x3c, 0xdf, 0xd2, 0x48, 0x0d, 0x57, 0xc3, 0x58, 0x7c, 0xca, 0x12, + 0x16, 0x49, 0x43, 0x46, 0x3f, 0x82, 0xdd, 0x39, 0xad, 0x71, 0x74, 0x0b, 0xaa, 0x63, 0xd4, 0xa0, + 0xa7, 0x7a, 0x6f, 0xaf, 0xd8, 0x84, 0x0c, 0xdf, 0x2f, 0xeb, 0x3e, 0x78, 0x06, 0xdb, 0xfb, 0xa1, + 0x0a, 0x15, 0xf4, 0x46, 0xbe, 0x86, 0xb2, 0x5e, 0x1d, 0xa4, 0x53, 0xb4, 0x2b, 0xae, 0xa3, 0xd6, + 0xb5, 0x35, 0x88, 0x2c, 0x18, 0x7a, 0xf0, 0xed, 0xef, 0xff, 0xfc, 0xb8, 0xf1, 0x36, 0x79, 0xd3, + 0x2d, 0xac, 0x3a, 0xbd, 0x81, 0xa4, 0xfb, 0x68, 0xae, 0x5a, 0x8f, 0xc9, 0x77, 0x16, 0x54, 0x70, + 0x79, 0x90, 0xe5, 0xbe, 0x67, 0x97, 0x54, 0x8b, 0xae, 0x83, 0x18, 0xfe, 0x5b, 0xc8, 0xef, 0x90, + 0x77, 0x8a, 0xfc, 0x52, 0xc3, 0x16, 0x02, 0x70, 0x1f, 0x1d, 0xf3, 0xc9, 0x63, 0xf2, 0x8b, 0x05, + 0xbb, 0x4b, 0x66, 0x83, 0xb8, 0x2b, 0x12, 0x5e, 0x35, 0x7e, 0xad, 0x1b, 0x2f, 0x6f, 0x60, 0x02, + 0xde, 0xc7, 0x80, 0xdf, 0x20, 0x74, 0xb1, 0x60, 0x99, 0x91, 0x74, 0x0f, 0x27, 0x03, 0x1c, 0x0e, + 0xf2, 0x0d, 0x54, 0xb2, 0xb8, 0x96, 0x17, 0x6b, 0x2e, 0x12, 0xba, 0x0e, 0x62, 0xb8, 0x1d, 0xe4, + 0xee, 0x92, 0xb7, 0x8a, 0xdc, 0x48, 0xb7, 0xd8, 0xad, 0x11, 0x94, 0xf5, 0xce, 0x58, 0x35, 0x29, + 0x2f, 0x36, 0xfa, 0xaa, 0x49, 0x99, 0x59, 0x38, 0xb4, 0x8d, 0xe4, 0x57, 0xee, 0x5a, 0xfb, 0xb4, + 0xb1, 0x90, 0xbb, 0x66, 0x39, 0x81, 0x6a, 0x36, 0xb9, 0x64, 0x79, 0x2e, 0x73, 0x8f, 0xa3, 0x75, + 0x7d, 0x2d, 0xc6, 0x70, 0xda, 0xc8, 0xd9, 0x24, 0x7b, 0x45, 0xc2, 0xec, 0x51, 0xf4, 0x1f, 0x9c, + 0xfd, 0x6d, 0x97, 0x9e, 0x4c, 0xed, 0xd2, 0xd9, 0xd4, 0xb6, 0x9e, 0x4e, 0x6d, 0xeb, 0xaf, 0xa9, + 0x6d, 0x7d, 0x7f, 0x6e, 0x97, 0x9e, 0x9e, 0xdb, 0xa5, 0x3f, 0xce, 0xed, 0xd2, 0x17, 0xfb, 0x41, + 0xa8, 0x8e, 0xd2, 0x43, 0x67, 0x28, 0x22, 0x37, 0x8c, 0x43, 0x15, 0xb2, 0x83, 0x11, 0x3b, 0x94, + 0xcf, 0xfd, 0x7d, 0x85, 0x1e, 0xf1, 0xbb, 0x7e, 0x58, 0xc5, 0x0f, 0xfb, 0xbb, 0xff, 0x07, 0x00, + 0x00, 0xff, 0xff, 0x39, 0x2f, 0xf9, 0x5f, 0x69, 0x08, 0x00, 0x00, } func (this *QueryCodeResponse) Equal(that interface{}) bool { @@ -751,7 +756,9 @@ type QueryClient interface { Code(ctx context.Context, in *QueryCodeRequest, opts ...grpc.CallOption) (*QueryCodeResponse, error) // State gets the state bytes of the given address and key bytes. State(ctx context.Context, in *QueryStateRequest, opts ...grpc.CallOption) (*QueryStateResponse, error) + // ContractAddrByDenom gets the contract address by denom. ContractAddrByDenom(ctx context.Context, in *QueryContractAddrByDenomRequest, opts ...grpc.CallOption) (*QueryContractAddrByDenomResponse, error) + // Denom gets the denom of the given contract address. Denom(ctx context.Context, in *QueryDenomRequest, opts ...grpc.CallOption) (*QueryDenomResponse, error) // Call execute entry function and return the function result Call(ctx context.Context, in *QueryCallRequest, opts ...grpc.CallOption) (*QueryCallResponse, error) @@ -827,7 +834,9 @@ type QueryServer interface { Code(context.Context, *QueryCodeRequest) (*QueryCodeResponse, error) // State gets the state bytes of the given address and key bytes. State(context.Context, *QueryStateRequest) (*QueryStateResponse, error) + // ContractAddrByDenom gets the contract address by denom. ContractAddrByDenom(context.Context, *QueryContractAddrByDenomRequest) (*QueryContractAddrByDenomResponse, error) + // Denom gets the denom of the given contract address. Denom(context.Context, *QueryDenomRequest) (*QueryDenomResponse, error) // Call execute entry function and return the function result Call(context.Context, *QueryCallRequest) (*QueryCallResponse, error) @@ -1160,8 +1169,18 @@ func (m *QueryCallRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintQuery(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 + dAtA[i] = 0x2a } + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.Input) > 0 { i -= len(m.Input) copy(dAtA[i:], m.Input) @@ -1573,6 +1592,8 @@ func (m *QueryCallRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + l = m.Value.Size() + n += 1 + l + sovQuery(uint64(l)) if m.TraceOptions != nil { l = m.TraceOptions.Size() n += 1 + l + sovQuery(uint64(l)) @@ -2195,6 +2216,40 @@ func (m *QueryCallRequest) Unmarshal(dAtA []byte) error { m.Input = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field TraceOptions", wireType) } diff --git a/x/evm/types/tx.pb.go b/x/evm/types/tx.pb.go index 46e3380..6344352 100644 --- a/x/evm/types/tx.pb.go +++ b/x/evm/types/tx.pb.go @@ -5,6 +5,7 @@ package types import ( context "context" + cosmossdk_io_math "cosmossdk.io/math" fmt "fmt" _ "github.com/cosmos/cosmos-proto" _ "github.com/cosmos/cosmos-sdk/types/msgservice" @@ -37,6 +38,8 @@ type MsgCreate struct { Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` // Code is hex encoded raw contract bytes code. Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` + // Value is the amount of fee denom token to transfer to the contract. + Value cosmossdk_io_math.Int `protobuf:"bytes,3,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value"` } func (m *MsgCreate) Reset() { *m = MsgCreate{} } @@ -148,6 +151,8 @@ type MsgCreate2 struct { Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` // Salt is a random value to distinguish contract creation. Salt uint64 `protobuf:"varint,3,opt,name=salt,proto3" json:"salt,omitempty"` + // Value is the amount of fee denom token to transfer to the contract. + Value cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value"` } func (m *MsgCreate2) Reset() { *m = MsgCreate2{} } @@ -267,6 +272,8 @@ type MsgCall struct { ContractAddr string `protobuf:"bytes,2,opt,name=contract_addr,json=contractAddr,proto3" json:"contract_addr,omitempty"` // Hex encoded execution input bytes. Input string `protobuf:"bytes,3,opt,name=input,proto3" json:"input,omitempty"` + // Value is the amount of fee denom token to transfer to the contract. + Value cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=value,proto3,customtype=cosmossdk.io/math.Int" json:"value"` } func (m *MsgCall) Reset() { *m = MsgCall{} } @@ -486,44 +493,47 @@ func init() { func init() { proto.RegisterFile("minievm/evm/v1/tx.proto", fileDescriptor_d925564029372f6a) } var fileDescriptor_d925564029372f6a = []byte{ - // 588 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x54, 0x41, 0x8b, 0xd3, 0x4e, - 0x14, 0x6f, 0xda, 0x6e, 0x97, 0xbe, 0xee, 0xf6, 0xcf, 0xe6, 0x5f, 0xb6, 0x6d, 0xc4, 0x6c, 0x8d, - 0x07, 0x4b, 0x61, 0x1b, 0x37, 0x82, 0x60, 0x4f, 0x5a, 0x45, 0x10, 0x5c, 0x58, 0x23, 0x82, 0x08, - 0xb2, 0x4c, 0x9b, 0x21, 0x1b, 0x48, 0x32, 0x21, 0x33, 0x2d, 0xbb, 0x37, 0xf1, 0xe0, 0xc1, 0x93, - 0xa0, 0x1f, 0xc2, 0x63, 0x0f, 0xde, 0xfc, 0x02, 0x7b, 0x5c, 0x3c, 0x79, 0x12, 0x69, 0x0f, 0xfd, - 0x1a, 0x92, 0xc9, 0x24, 0xdd, 0x86, 0x2d, 0x15, 0xd9, 0xc3, 0x94, 0x79, 0xef, 0xfd, 0xde, 0xef, - 0xbd, 0xdf, 0xf4, 0xe5, 0x41, 0xdd, 0x73, 0x7c, 0x07, 0x8f, 0x3d, 0x3d, 0x3a, 0xe3, 0x03, 0x9d, - 0x9d, 0x76, 0x83, 0x90, 0x30, 0x22, 0x57, 0x45, 0xa0, 0x1b, 0x9d, 0xf1, 0x81, 0xb2, 0x83, 0x3c, - 0xc7, 0x27, 0x3a, 0xff, 0x8d, 0x21, 0x4a, 0x7d, 0x48, 0xa8, 0x47, 0xa8, 0xee, 0x51, 0x3b, 0x4a, - 0xf5, 0xa8, 0x2d, 0x02, 0xcd, 0x38, 0x70, 0xcc, 0x2d, 0x3d, 0x36, 0x44, 0xa8, 0x66, 0x13, 0x9b, - 0xc4, 0xfe, 0xe8, 0x26, 0xbc, 0x4a, 0xb6, 0x8b, 0xb3, 0x00, 0x8b, 0x0c, 0x2d, 0x80, 0xf2, 0x21, - 0xb5, 0x1f, 0x87, 0x18, 0x31, 0x2c, 0xdf, 0x85, 0x12, 0xc5, 0xbe, 0x85, 0xc3, 0x86, 0xd4, 0x92, - 0xda, 0xe5, 0x7e, 0xe3, 0xc7, 0xb7, 0xfd, 0x9a, 0x28, 0xf0, 0xc8, 0xb2, 0x42, 0x4c, 0xe9, 0x4b, - 0x16, 0x3a, 0xbe, 0x6d, 0x0a, 0x9c, 0x2c, 0x43, 0x71, 0x48, 0x2c, 0xdc, 0xc8, 0x47, 0x78, 0x93, - 0xdf, 0x7b, 0x37, 0xdf, 0xcf, 0x27, 0x1d, 0x01, 0xf8, 0x38, 0x9f, 0x74, 0xb6, 0xa3, 0xb2, 0x69, - 0x11, 0xed, 0x08, 0x76, 0x52, 0xc3, 0xc4, 0x34, 0x20, 0x3e, 0xc5, 0xf2, 0x2e, 0x94, 0x42, 0x4c, - 0x47, 0x2e, 0x8b, 0x2b, 0x9b, 0xc2, 0x92, 0x6f, 0xc3, 0xf6, 0x90, 0xf8, 0x2c, 0x44, 0x43, 0x76, - 0x8c, 0x2c, 0x2b, 0x14, 0x85, 0xb6, 0x12, 0x67, 0xd4, 0x95, 0xf6, 0x41, 0x02, 0x48, 0x29, 0x8d, - 0xeb, 0x51, 0x11, 0xf9, 0x28, 0x72, 0x59, 0xa3, 0xd0, 0x92, 0xda, 0x45, 0x93, 0xdf, 0x7b, 0x6a, - 0x46, 0x59, 0x75, 0x49, 0x99, 0xa1, 0xbd, 0x00, 0x79, 0x61, 0x5d, 0x8f, 0xb6, 0xcf, 0x12, 0x6c, - 0x46, 0x9c, 0xc8, 0x75, 0xff, 0x41, 0xd8, 0xdf, 0x94, 0x90, 0x6b, 0xb0, 0xe1, 0xf8, 0xc1, 0x28, - 0x96, 0x5a, 0x36, 0x63, 0xa3, 0x77, 0x23, 0xa3, 0xb5, 0x92, 0x68, 0x45, 0xae, 0xab, 0xbd, 0x85, - 0xff, 0xc4, 0x75, 0xad, 0x4a, 0x03, 0x8a, 0x2e, 0xb1, 0x69, 0x23, 0xdf, 0x2a, 0xb4, 0x2b, 0xc6, - 0xff, 0xdd, 0xe5, 0xc1, 0xef, 0x3e, 0x27, 0x76, 0xbf, 0x7c, 0xfe, 0x6b, 0x2f, 0xf7, 0x75, 0x3e, - 0xe9, 0x48, 0x26, 0xc7, 0x6a, 0x5f, 0x24, 0xce, 0xff, 0x2a, 0xb0, 0x10, 0xc3, 0x47, 0x28, 0x44, - 0x1e, 0x95, 0xef, 0x43, 0x19, 0x8d, 0xd8, 0x09, 0x09, 0x1d, 0x76, 0xb6, 0x56, 0xff, 0x02, 0x2a, - 0x3f, 0x80, 0x52, 0xc0, 0x19, 0xb8, 0xf6, 0x8a, 0xb1, 0x9b, 0xed, 0x20, 0xe6, 0xbf, 0xdc, 0x84, - 0x48, 0xe8, 0x55, 0xa3, 0x27, 0x58, 0x50, 0x69, 0x4d, 0xa8, 0x67, 0xba, 0x4a, 0xd4, 0x1b, 0xdf, - 0xf3, 0x50, 0x38, 0xa4, 0xb6, 0xfc, 0x14, 0x4a, 0xe2, 0x5b, 0x6a, 0x66, 0xeb, 0xa4, 0x93, 0xa1, - 0xdc, 0x5a, 0x19, 0x4a, 0x5f, 0xf3, 0x19, 0x6c, 0x26, 0xe3, 0xac, 0xac, 0x44, 0x1b, 0x8a, 0xb6, - 0x3a, 0x96, 0x52, 0x3d, 0x84, 0x22, 0x9f, 0x9e, 0xfa, 0x55, 0x58, 0xe4, 0xba, 0xca, 0xde, 0x8a, - 0x40, 0xca, 0xf0, 0x1a, 0xb6, 0x96, 0xfe, 0x8a, 0xab, 0x12, 0x2e, 0x03, 0x94, 0x3b, 0x6b, 0x00, - 0x09, 0xb3, 0xb2, 0xf1, 0x2e, 0x7a, 0xf0, 0xfe, 0x93, 0xf3, 0xa9, 0x2a, 0x5d, 0x4c, 0x55, 0xe9, - 0xf7, 0x54, 0x95, 0x3e, 0xcd, 0xd4, 0xdc, 0xc5, 0x4c, 0xcd, 0xfd, 0x9c, 0xa9, 0xb9, 0x37, 0x1d, - 0xdb, 0x61, 0x27, 0xa3, 0x41, 0x77, 0x48, 0x3c, 0xdd, 0xf1, 0x1d, 0xe6, 0xa0, 0x7d, 0x17, 0x0d, - 0xa8, 0x9e, 0x6c, 0xb4, 0x53, 0xbe, 0xd3, 0xf8, 0x42, 0x1b, 0x94, 0xf8, 0x46, 0xbb, 0xf7, 0x27, - 0x00, 0x00, 0xff, 0xff, 0x6e, 0xbf, 0xc6, 0x34, 0x75, 0x05, 0x00, 0x00, + // 639 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0xcf, 0x6b, 0xd4, 0x40, + 0x14, 0xc7, 0x37, 0x6d, 0xba, 0x65, 0x5f, 0x7f, 0x48, 0xc7, 0xda, 0xdd, 0x46, 0x4c, 0x6b, 0x3c, + 0x58, 0x16, 0x9a, 0xb4, 0x11, 0x04, 0x7b, 0xd2, 0x2a, 0x85, 0x82, 0x85, 0x1a, 0x11, 0x44, 0x90, + 0x32, 0xdd, 0x0c, 0x69, 0x30, 0xc9, 0x84, 0xcc, 0xec, 0xd2, 0xde, 0xc4, 0xa3, 0x27, 0x0f, 0xfe, + 0x11, 0x1e, 0x7b, 0xe8, 0x41, 0xf0, 0x1f, 0xe8, 0x49, 0x4a, 0x4f, 0xa2, 0x50, 0xa4, 0x3d, 0xf4, + 0xdf, 0x90, 0x4c, 0x26, 0xd9, 0x6e, 0xe8, 0xb2, 0xa2, 0x7b, 0xc8, 0x32, 0x6f, 0xde, 0x77, 0xbe, + 0xef, 0xcd, 0x67, 0x93, 0x07, 0xf5, 0xd0, 0x8f, 0x7c, 0xd2, 0x09, 0xad, 0xf4, 0xe9, 0xac, 0x5a, + 0x7c, 0xdf, 0x8c, 0x13, 0xca, 0x29, 0x9a, 0x96, 0x09, 0x33, 0x7d, 0x3a, 0xab, 0xda, 0x0c, 0x0e, + 0xfd, 0x88, 0x5a, 0xe2, 0x37, 0x93, 0x68, 0xf5, 0x16, 0x65, 0x21, 0x65, 0x56, 0xc8, 0xbc, 0xf4, + 0x68, 0xc8, 0x3c, 0x99, 0x98, 0xcf, 0x12, 0x3b, 0x22, 0xb2, 0xb2, 0x40, 0xa6, 0x66, 0x3d, 0xea, + 0xd1, 0x6c, 0x3f, 0x5d, 0xc9, 0x5d, 0xad, 0xdc, 0xc5, 0x41, 0x4c, 0xe4, 0x09, 0xe3, 0xab, 0x02, + 0xb5, 0x2d, 0xe6, 0x3d, 0x4d, 0x08, 0xe6, 0x04, 0xad, 0x40, 0x95, 0x91, 0xc8, 0x25, 0x49, 0x43, + 0x59, 0x54, 0x96, 0x6a, 0xeb, 0x8d, 0xd3, 0xa3, 0xe5, 0x59, 0x59, 0xe1, 0x89, 0xeb, 0x26, 0x84, + 0xb1, 0x97, 0x3c, 0xf1, 0x23, 0xcf, 0x91, 0x3a, 0x84, 0x40, 0x6d, 0x51, 0x97, 0x34, 0x46, 0x52, + 0xbd, 0x23, 0xd6, 0x68, 0x03, 0xc6, 0x3a, 0x38, 0x68, 0x93, 0xc6, 0xa8, 0x30, 0x59, 0x39, 0x3e, + 0x5b, 0xa8, 0xfc, 0x3c, 0x5b, 0xb8, 0x95, 0x19, 0x31, 0xf7, 0x9d, 0xe9, 0x53, 0x2b, 0xc4, 0x7c, + 0xcf, 0xdc, 0x8c, 0xf8, 0xe9, 0xd1, 0x32, 0xc8, 0x0a, 0x9b, 0x11, 0xff, 0x72, 0x79, 0xd8, 0x54, + 0x9c, 0xec, 0xf8, 0xda, 0x9d, 0x0f, 0x97, 0x87, 0x4d, 0x59, 0xe8, 0xe3, 0xe5, 0x61, 0x73, 0x2a, + 0xed, 0xbf, 0x68, 0xd6, 0xd8, 0x86, 0x99, 0x22, 0x70, 0x08, 0x8b, 0x69, 0xc4, 0x08, 0x9a, 0x83, + 0x6a, 0x42, 0x58, 0x3b, 0xe0, 0xd9, 0x0d, 0x1c, 0x19, 0xa1, 0x7b, 0x30, 0xd5, 0xa2, 0x11, 0x4f, + 0x70, 0x8b, 0xef, 0x60, 0xd7, 0x4d, 0x64, 0xc3, 0x93, 0xf9, 0x66, 0x7a, 0x3b, 0xe3, 0xbb, 0x02, + 0x50, 0x58, 0xda, 0x43, 0xa2, 0x81, 0x40, 0x65, 0x38, 0xe0, 0x02, 0x86, 0xea, 0x88, 0x75, 0x97, + 0x90, 0xfa, 0x7f, 0x84, 0xf4, 0x12, 0xa1, 0xe9, 0x1e, 0x42, 0xb6, 0xf1, 0x02, 0x50, 0x37, 0x1a, + 0x0e, 0xa3, 0x5f, 0x0a, 0x8c, 0xa7, 0x9e, 0x38, 0x08, 0xfe, 0x01, 0xd0, 0xdf, 0x94, 0x40, 0xb3, + 0x30, 0xe6, 0x47, 0x71, 0x3b, 0x43, 0x56, 0x73, 0xb2, 0x60, 0x68, 0xcc, 0x6e, 0x97, 0x98, 0x4d, + 0xe4, 0xcc, 0x70, 0x10, 0x18, 0x6f, 0xe1, 0x86, 0x5c, 0x0e, 0xa4, 0x65, 0x83, 0x1a, 0x50, 0x8f, + 0x35, 0x46, 0x16, 0x47, 0x97, 0x26, 0xec, 0x9b, 0x66, 0xef, 0x17, 0x6d, 0x3e, 0xa7, 0xde, 0x7a, + 0x2d, 0xed, 0x31, 0x2b, 0x2e, 0xb4, 0xc6, 0x67, 0x45, 0xf8, 0xbf, 0x8a, 0x5d, 0xcc, 0xc9, 0x36, + 0x4e, 0x70, 0xc8, 0xd0, 0x43, 0xa8, 0xe1, 0x36, 0xdf, 0xa3, 0x89, 0xcf, 0x0f, 0x06, 0x72, 0xec, + 0x4a, 0xd1, 0x23, 0xa8, 0xc6, 0xc2, 0x41, 0x30, 0x9c, 0xb0, 0xe7, 0xca, 0x1d, 0x64, 0xfe, 0x57, + 0x9b, 0x90, 0x07, 0xd6, 0xa6, 0x53, 0x04, 0x5d, 0x2b, 0x63, 0x1e, 0xea, 0xa5, 0xae, 0xf2, 0xdb, + 0xdb, 0xdf, 0x46, 0x60, 0x74, 0x8b, 0x79, 0x68, 0x03, 0xaa, 0x72, 0x46, 0xcc, 0x97, 0xeb, 0x14, + 0x6f, 0x98, 0x76, 0xb7, 0x6f, 0xaa, 0xa0, 0xb9, 0x09, 0xe3, 0xf9, 0xe7, 0xa5, 0xf5, 0x55, 0xdb, + 0x9a, 0xd1, 0x3f, 0x57, 0x58, 0x3d, 0x06, 0x55, 0xbc, 0x85, 0xf5, 0xeb, 0xb4, 0x38, 0x08, 0xb4, + 0x85, 0x3e, 0x89, 0xc2, 0xe1, 0x35, 0x4c, 0xf6, 0xfc, 0x15, 0xd7, 0x1d, 0xb8, 0x2a, 0xd0, 0xee, + 0x0f, 0x10, 0xe4, 0xce, 0xda, 0xd8, 0xfb, 0x14, 0xf8, 0xfa, 0xb3, 0xe3, 0x73, 0x5d, 0x39, 0x39, + 0xd7, 0x95, 0xdf, 0xe7, 0xba, 0xf2, 0xe9, 0x42, 0xaf, 0x9c, 0x5c, 0xe8, 0x95, 0x1f, 0x17, 0x7a, + 0xe5, 0x4d, 0xd3, 0xf3, 0xf9, 0x5e, 0x7b, 0xd7, 0x6c, 0xd1, 0xd0, 0xf2, 0x23, 0x9f, 0xfb, 0x78, + 0x39, 0xc0, 0xbb, 0xcc, 0xca, 0x47, 0xf5, 0xbe, 0x18, 0xd6, 0x62, 0x52, 0xef, 0x56, 0xc5, 0xa8, + 0x7e, 0xf0, 0x27, 0x00, 0x00, 0xff, 0xff, 0xde, 0xd9, 0x38, 0x3b, 0x4e, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -744,6 +754,16 @@ func (m *MsgCreate) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a if len(m.Code) > 0 { i -= len(m.Code) copy(dAtA[i:], m.Code) @@ -818,6 +838,16 @@ func (m *MsgCreate2) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if m.Salt != 0 { i = encodeVarintTx(dAtA, i, uint64(m.Salt)) i-- @@ -897,6 +927,16 @@ func (m *MsgCall) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size := m.Value.Size() + i -= size + if _, err := m.Value.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 if len(m.Input) > 0 { i -= len(m.Input) copy(dAtA[i:], m.Input) @@ -1053,6 +1093,8 @@ func (m *MsgCreate) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = m.Value.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1090,6 +1132,8 @@ func (m *MsgCreate2) Size() (n int) { if m.Salt != 0 { n += 1 + sovTx(uint64(m.Salt)) } + l = m.Value.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1128,6 +1172,8 @@ func (m *MsgCall) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + l = m.Value.Size() + n += 1 + l + sovTx(uint64(l)) return n } @@ -1273,6 +1319,40 @@ func (m *MsgCreate) Unmarshal(dAtA []byte) error { } m.Code = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -1520,6 +1600,40 @@ func (m *MsgCreate2) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -1780,6 +1894,40 @@ func (m *MsgCall) Unmarshal(dAtA []byte) error { } m.Input = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Value.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/evm/types/types.pb.go b/x/evm/types/types.pb.go index e1b0e6d..465c4cd 100644 --- a/x/evm/types/types.pb.go +++ b/x/evm/types/types.pb.go @@ -35,6 +35,8 @@ type Params struct { // to be registered on cosmos bank interface. AllowCustomERC20 bool `protobuf:"varint,3,opt,name=allow_custom_erc20,json=allowCustomErc20,proto3" json:"allow_custom_erc20,omitempty"` AllowedCustomERC20s []string `protobuf:"bytes,4,rep,name=allowed_custom_erc20s,json=allowedCustomErc20s,proto3" json:"allowed_custom_erc20s,omitempty" yaml:"allowed_custom_erc20s"` + // fee_denom defines the fee denom for the evm transactions + FeeDenom string `protobuf:"bytes,5,opt,name=fee_denom,json=feeDenom,proto3" json:"fee_denom,omitempty" yaml:"fee_denom"` } func (m *Params) Reset() { *m = Params{} } @@ -121,34 +123,36 @@ func init() { func init() { proto.RegisterFile("minievm/evm/v1/types.proto", fileDescriptor_98c9eab1c4bf0154) } var fileDescriptor_98c9eab1c4bf0154 = []byte{ - // 430 bytes of a gzipped FileDescriptorProto + // 458 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x31, 0x6f, 0xd3, 0x40, - 0x14, 0xf6, 0xd5, 0x55, 0xc0, 0x37, 0xa0, 0xe6, 0x5a, 0xc0, 0x44, 0xe8, 0x1c, 0x79, 0x8a, 0x22, - 0x11, 0xb7, 0x65, 0xab, 0x58, 0xe2, 0xca, 0x03, 0xa2, 0x43, 0xf0, 0xc8, 0x62, 0x9d, 0xed, 0x93, - 0x7b, 0x92, 0x9d, 0xb3, 0x7c, 0x97, 0xd0, 0xfe, 0x05, 0x26, 0x46, 0xc6, 0x8e, 0x1d, 0xfb, 0x33, - 0x3a, 0x76, 0x64, 0xb2, 0xc0, 0x19, 0xca, 0xc2, 0x92, 0x5f, 0x80, 0xee, 0xec, 0x40, 0x22, 0x86, - 0x67, 0xbd, 0xf7, 0xbe, 0xef, 0x3d, 0xbf, 0xf7, 0xee, 0x83, 0x83, 0x82, 0xcd, 0x19, 0x5d, 0x16, - 0x9e, 0xb2, 0xe5, 0x89, 0x27, 0xaf, 0x4b, 0x2a, 0x26, 0x65, 0xc5, 0x25, 0x47, 0xcf, 0x3a, 0x6c, - 0xa2, 0x6c, 0x79, 0x32, 0xe8, 0x93, 0x82, 0xcd, 0xb9, 0xa7, 0xbf, 0x2d, 0x65, 0x70, 0x94, 0xf1, - 0x8c, 0x6b, 0xd7, 0x53, 0x5e, 0x9b, 0x75, 0x7f, 0xef, 0xc1, 0xde, 0x8c, 0x54, 0xa4, 0x10, 0x68, - 0x0a, 0x21, 0xbd, 0x92, 0x15, 0x89, 0x28, 0x2b, 0x85, 0x0d, 0x86, 0xe6, 0xc8, 0xf4, 0xdd, 0xa6, - 0x76, 0xac, 0x40, 0x65, 0x83, 0xf7, 0x33, 0xb1, 0xae, 0x9d, 0xfe, 0x35, 0x29, 0xf2, 0x33, 0xf7, - 0x1f, 0xd1, 0x0d, 0x2d, 0x1d, 0x04, 0xac, 0x14, 0xe8, 0x23, 0x44, 0x24, 0xcf, 0xf9, 0x67, 0x9a, - 0x46, 0xe5, 0x22, 0xce, 0x99, 0xb8, 0xa4, 0x95, 0xb0, 0xf7, 0x86, 0xe6, 0xc8, 0xf2, 0xdd, 0x75, - 0xed, 0xbc, 0x6a, 0xab, 0xff, 0xe7, 0xb8, 0xb7, 0x8f, 0x77, 0x63, 0x10, 0xf6, 0x3b, 0x64, 0xf6, - 0x17, 0x40, 0x7e, 0xd7, 0x32, 0x4a, 0x16, 0x42, 0xf2, 0x22, 0xa2, 0x55, 0x72, 0x7a, 0x6c, 0x9b, - 0x43, 0x30, 0x7a, 0xea, 0x1f, 0x35, 0xb5, 0x73, 0x30, 0x55, 0xe8, 0xb9, 0x06, 0x83, 0xf0, 0xfc, - 0xf4, 0x38, 0x3c, 0x20, 0x5b, 0x19, 0xc5, 0x46, 0x25, 0x7c, 0xbe, 0xf9, 0xe5, 0x76, 0x17, 0x61, - 0xef, 0xeb, 0xc9, 0xde, 0x35, 0xb5, 0x73, 0x38, 0x6d, 0x09, 0x5b, 0x8d, 0xd4, 0xba, 0xaf, 0x77, - 0x07, 0xde, 0xa9, 0xee, 0x66, 0x3e, 0x24, 0x3b, 0x95, 0x1a, 0x3a, 0x7b, 0xf9, 0xed, 0xc6, 0x31, - 0x7e, 0xdd, 0x38, 0xe0, 0xcb, 0xe3, 0xdd, 0x18, 0xaa, 0x07, 0x6b, 0x8f, 0xec, 0x7e, 0x80, 0xe6, - 0x05, 0xcf, 0x90, 0x0d, 0x9f, 0x90, 0x34, 0xad, 0xa8, 0x50, 0x87, 0x06, 0x23, 0x2b, 0xdc, 0x84, - 0xe8, 0x05, 0xec, 0x49, 0x5e, 0xb2, 0xa4, 0x3b, 0x5b, 0xd8, 0x45, 0x08, 0xc1, 0xfd, 0x94, 0x48, - 0xa2, 0x37, 0xb7, 0x42, 0xed, 0xfb, 0x17, 0xf7, 0x3f, 0xb1, 0x71, 0xdb, 0x60, 0x70, 0xdf, 0x60, - 0xf0, 0xd0, 0x60, 0xf0, 0xa3, 0xc1, 0xe0, 0xeb, 0x0a, 0x1b, 0x0f, 0x2b, 0x6c, 0x7c, 0x5f, 0x61, - 0xe3, 0xd3, 0x38, 0x63, 0xf2, 0x72, 0x11, 0x4f, 0x12, 0x5e, 0x78, 0x6c, 0xce, 0x24, 0x23, 0x6f, - 0x72, 0x12, 0x0b, 0x6f, 0x23, 0xa5, 0x2b, 0x2d, 0x26, 0xad, 0xa4, 0xb8, 0xa7, 0x15, 0xf1, 0xf6, - 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x41, 0xfc, 0x84, 0x5b, 0x68, 0x02, 0x00, 0x00, + 0x14, 0xf6, 0xe1, 0x12, 0xea, 0x1b, 0x50, 0x72, 0x0d, 0x60, 0x22, 0x64, 0x47, 0x9e, 0xac, 0x48, + 0xc4, 0x4d, 0xd9, 0x2a, 0x96, 0xb8, 0x64, 0x40, 0x74, 0x08, 0x1e, 0x59, 0xac, 0x4b, 0x7c, 0x4d, + 0x4f, 0xf2, 0xe5, 0x2c, 0xdf, 0x25, 0xb4, 0x7f, 0x81, 0x89, 0x91, 0x31, 0x63, 0xc7, 0xfe, 0x8c, + 0x8e, 0x1d, 0x99, 0x2c, 0x70, 0x86, 0x32, 0xe7, 0x17, 0xa0, 0x3b, 0x3b, 0x25, 0x11, 0xc3, 0x59, + 0xef, 0xbd, 0xef, 0x7b, 0x9f, 0xdf, 0xdd, 0xfb, 0x60, 0x87, 0xd1, 0x39, 0x25, 0x4b, 0x16, 0xa8, + 0xb3, 0x1c, 0x04, 0xf2, 0x3a, 0x23, 0xa2, 0x9f, 0xe5, 0x5c, 0x72, 0xf4, 0xbc, 0xc6, 0xfa, 0xea, + 0x2c, 0x07, 0x9d, 0x16, 0x66, 0x74, 0xce, 0x03, 0xfd, 0xad, 0x28, 0x9d, 0xf6, 0x8c, 0xcf, 0xb8, + 0x0e, 0x03, 0x15, 0x55, 0x55, 0x6f, 0x65, 0xc2, 0xc6, 0x18, 0xe7, 0x98, 0x09, 0x34, 0x84, 0x90, + 0x5c, 0xc9, 0x1c, 0xc7, 0x84, 0x66, 0xc2, 0x06, 0x5d, 0xd3, 0x37, 0x43, 0xaf, 0x2c, 0x5c, 0x6b, + 0xa4, 0xaa, 0xa3, 0x8f, 0x63, 0xb1, 0x29, 0xdc, 0xd6, 0x35, 0x66, 0xe9, 0xa9, 0xf7, 0x8f, 0xe8, + 0x45, 0x96, 0x4e, 0x46, 0x34, 0x13, 0xe8, 0x33, 0x44, 0x38, 0x4d, 0xf9, 0x57, 0x92, 0xc4, 0xd9, + 0x62, 0x92, 0x52, 0x71, 0x49, 0x72, 0x61, 0x3f, 0xe9, 0x9a, 0xbe, 0x15, 0x7a, 0x9b, 0xc2, 0x7d, + 0x5d, 0x75, 0xff, 0xcf, 0xf1, 0x6e, 0x1e, 0x6e, 0x7b, 0x20, 0x6a, 0xd5, 0xc8, 0xf8, 0x11, 0x40, + 0x61, 0x2d, 0x19, 0x4f, 0x17, 0x42, 0x72, 0x16, 0x93, 0x7c, 0x7a, 0x72, 0x6c, 0x9b, 0x5d, 0xe0, + 0x1f, 0x86, 0xed, 0xb2, 0x70, 0x9b, 0x43, 0x85, 0x9e, 0x69, 0x70, 0x14, 0x9d, 0x9d, 0x1c, 0x47, + 0x4d, 0xbc, 0x53, 0x51, 0x6c, 0x94, 0xc1, 0x17, 0xdb, 0x5f, 0xee, 0xaa, 0x08, 0xfb, 0x40, 0x4f, + 0xf6, 0xbe, 0x2c, 0xdc, 0xa3, 0x61, 0x45, 0xd8, 0x11, 0x52, 0xd7, 0x7d, 0xb3, 0x3f, 0xf0, 0x5e, + 0x77, 0x3d, 0xf3, 0x11, 0xde, 0xeb, 0xd4, 0x10, 0x1a, 0x40, 0xeb, 0x82, 0x90, 0x38, 0x21, 0x73, + 0xce, 0xec, 0xa7, 0x5d, 0xe0, 0x5b, 0x61, 0x7b, 0x53, 0xb8, 0xcd, 0x4a, 0xee, 0x11, 0xf2, 0xa2, + 0xc3, 0x0b, 0x42, 0x3e, 0xa8, 0xf0, 0xf4, 0xd5, 0x8f, 0x95, 0x6b, 0xfc, 0x59, 0xb9, 0xe0, 0xdb, + 0xc3, 0x6d, 0x0f, 0xaa, 0x1d, 0x57, 0x7b, 0xf1, 0x3e, 0x41, 0xf3, 0x9c, 0xcf, 0x90, 0x0d, 0x9f, + 0xe1, 0x24, 0xc9, 0x89, 0x50, 0xbb, 0x01, 0xbe, 0x15, 0x6d, 0x53, 0xf4, 0x12, 0x36, 0x24, 0xcf, + 0xe8, 0xb4, 0x7e, 0xe9, 0xa8, 0xce, 0x10, 0x82, 0x07, 0x09, 0x96, 0x58, 0x3f, 0x96, 0x15, 0xe9, + 0x38, 0x3c, 0xbf, 0xfb, 0xed, 0x18, 0x37, 0xa5, 0x03, 0xee, 0x4a, 0x07, 0xdc, 0x97, 0x0e, 0xf8, + 0x55, 0x3a, 0xe0, 0xfb, 0xda, 0x31, 0xee, 0xd7, 0x8e, 0xf1, 0x73, 0xed, 0x18, 0x5f, 0x7a, 0x33, + 0x2a, 0x2f, 0x17, 0x93, 0xfe, 0x94, 0xb3, 0x80, 0xce, 0xa9, 0xa4, 0xf8, 0x6d, 0x8a, 0x27, 0x22, + 0xd8, 0xba, 0xef, 0x4a, 0xfb, 0x4f, 0x9b, 0x6f, 0xd2, 0xd0, 0x26, 0x7a, 0xf7, 0x37, 0x00, 0x00, + 0xff, 0xff, 0x58, 0x79, 0x35, 0x96, 0x9b, 0x02, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -197,6 +201,9 @@ func (this *Params) Equal(that interface{}) bool { return false } } + if this.FeeDenom != that1.FeeDenom { + return false + } return true } func (this *Log) Equal(that interface{}) bool { @@ -254,6 +261,13 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.FeeDenom) > 0 { + i -= len(m.FeeDenom) + copy(dAtA[i:], m.FeeDenom) + i = encodeVarintTypes(dAtA, i, uint64(len(m.FeeDenom))) + i-- + dAtA[i] = 0x2a + } if len(m.AllowedCustomERC20s) > 0 { for iNdEx := len(m.AllowedCustomERC20s) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.AllowedCustomERC20s[iNdEx]) @@ -389,6 +403,10 @@ func (m *Params) Size() (n int) { n += 1 + l + sovTypes(uint64(l)) } } + l = len(m.FeeDenom) + if l > 0 { + n += 1 + l + sovTypes(uint64(l)) + } return n } @@ -610,6 +628,38 @@ func (m *Params) Unmarshal(dAtA []byte) error { } m.AllowedCustomERC20s = append(m.AllowedCustomERC20s, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FeeDenom", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTypes + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTypes + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.FeeDenom = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:])