diff --git a/README.md b/README.md index bdf4aee..9d13bee 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # MiniEVM MiniEVM is an optimistic rollup consumer chain powered by EVM, designed to simplify the process of bootstrapping an L2 network. The main advantage of using MiniEVM is that the users can leverage the OPinit stack for enhanced security and utilize all the Initia ecosystem tooling from day one, without the need to prepare a validator group or build the users' own ecosystem tools. -- https://github.com/initia-labs/evm + +- [go-ethereum](https://github.com/initia-labs/evm) ## Prerequisites @@ -19,6 +20,9 @@ To get started with L2, please visit the [documentation](https://initia.gitbook. - Integrates seamlessly with the OPinit stack, enhancing security. - Provides immediate access to the full suite of Initia ecosystem tools right from the start. +## JSON-RPC + +For information of supported JSON-RPC methods, please refer to the [JSON-RPC documentation](jsonrpc/README.md). ## Contributing diff --git a/app/ante/ante.go b/app/ante/ante.go index 081263f..58f0d91 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -11,6 +11,9 @@ import ( opchildante "github.com/initia-labs/OPinit/x/opchild/ante" opchildtypes "github.com/initia-labs/OPinit/x/opchild/types" + "github.com/initia-labs/initia/app/ante/accnum" + "github.com/initia-labs/initia/app/ante/sigverify" + 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 +28,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 +51,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 = sigverify.DefaultSigVerificationGasConsumer } txFeeChecker := options.TxFeeChecker @@ -72,6 +81,7 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { } anteDecorators := []sdk.AnteDecorator{ + accnum.NewAccountNumberDecorator(options.AccountKeeper), ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), ante.NewValidateBasicDecorator(), @@ -83,7 +93,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..4c9fa50 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.5 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 @@ -121,6 +124,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 +167,13 @@ 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/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 +207,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 +214,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 +236,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 +281,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..d4c368c 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.5 h1:JsO0OZ+ZRQjzFusXSA2f7U1LNO6nApaCr+U6idJ+Pko= +github.com/initia-labs/initia v0.3.5/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..6dda911 --- /dev/null +++ b/go.work.sum @@ -0,0 +1,740 @@ +4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs= +4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU= +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= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= +github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0= +github.com/Abirdcfly/dupword v0.0.14/go.mod h1:VKDAbxdY8YbKUByLGg8EETzYSuC4crm9WwI6Y3S0cLI= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/Antonboom/errname v0.1.13/go.mod h1:uWyefRYRN54lBg6HseYCFhs6Qjcy41Y3Jl/dVhA87Ns= +github.com/Antonboom/nilnil v0.1.8/go.mod h1:iGe2rYwCq5/Me1khrysB4nwI7swQvjclR8/YRPl5ihQ= +github.com/Antonboom/testifylint v1.2.0/go.mod h1:rkmEqjqVnHDRNsinyN6fPSLnoajzFwsCcguJgwADBkw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgxoBDMqMO/Nvy7bZ9a0nbU3I1DtFQK3YvB4= +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/Crocmagnon/fatcontext v0.2.2/go.mod h1:WSn/c/+MMNiD8Pri0ahRj0o9jVpeowzavOQplBJw6u0= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0/go.mod h1:b3g59n2Y+T5xmcxJL+UEG2f8cQploZm1mR/v6BW0mU0= +github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0/go.mod h1:Nl76DrGNJTA1KJ0LePKBw/vznBX1EHbAZX8mwjR82nI= +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/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc= +github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +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/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/go-check-sumtype v0.1.4/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ= +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/alexkohler/nakedret/v2 v2.0.4/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU= +github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= +github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= +github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= +github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= +github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= +github.com/aws/aws-sdk-go-v2/config v1.18.45/go.mod h1:ZwDUgFnQgsazQTnWfeLWk5GjeqTQTL8lMkoE1UXzxdE= +github.com/aws/aws-sdk-go-v2/credentials v1.13.43/go.mod h1:zWJBz1Yf1ZtX5NGax9ZdNjhhI4rgjfgsyk6vTY1yfVg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13/go.mod h1:f/Ib/qYjhV2/qdsf79H3QP/eRE4AkVyEf6sk7XfZ1tg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.45/go.mod h1:lD5M20o09/LCuQ2mE62Mb/iSdSlCNuj6H5ci7tW7OsE= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.8.1/go.mod h1:CM+19rL1+4dFWnOQKwDc7H1KwXTz+h61oUSHyhV0b3o= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.37/go.mod h1:vBmDnwWXWxNPFRMmG2m/3MKOe+xEcMDo1tanpaWCcck= +github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2/go.mod h1:TQZBt/WaQy+zTHoW++rnl8JBrmZ0VO6EUbVua1+foCA= +github.com/aws/aws-sdk-go-v2/service/sso v1.15.2/go.mod h1:gsL4keucRCgW+xA85ALBpRFfdSLH4kHOVSnLMSuBECo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.3/go.mod h1:a7bHA82fyUXOm+ZSWKU6PIoBxrjSprdLoM8xPYvzYVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.23.2/go.mod h1:Eows6e1uQEsc4ZaHANmsPRzAKcVDrcmjjWiih2+HUUQ= +github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +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/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= +github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= +github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo= +github.com/bombsimon/wsl/v4 v4.2.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo= +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/bradleyfalzon/ghinstallation/v2 v2.0.4/go.mod h1:B40qPqJxWE0jDZgOR1JmaMy+4AY1eBP+IByOvqyAKp0= +github.com/breml/bidichk v0.2.7/go.mod h1:YodjipAGI9fGcYM7II6wFvGhdMYsC5pHDlGzqvEW3tQ= +github.com/breml/errchkjson v0.3.6/go.mod h1:jhSDoFheAF2RSDOlCfhHO9KqhZgAYLyvHe7bRCX8f/U= +github.com/bufbuild/buf v1.15.1/go.mod h1:TQeGKam1QMfHy/xsSnnMpxN3JK5HBb6aNvZj4m52gkE= +github.com/bufbuild/connect-go v1.5.2/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= +github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA= +github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ= +github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= +github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= +github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= +github.com/celestiaorg/nmt v0.20.0/go.mod h1:Oz15Ub6YPez9uJV0heoU4WpFctxazuIhKyUtaYNio7E= +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/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ= +github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/chigopher/pathlib v0.19.1/go.mod h1:tzC1dZLW8o33UQpWkNkhvPwL5n4yyFRFm/jL1YGWFvY= +github.com/ckaznocha/intrange v0.1.2/go.mod h1:RWffCw/vKBwHeOEwWdCikAtY0q4gGt8VhJZEEA5n+RE= +github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/cloudflare-go v0.79.0/go.mod h1:gkHQf9xEubaQPEuerBuoinR9P8bf8a05Lq0X6WKy1Oc= +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-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +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/creachadair/command v0.0.0-20220916173946-56a74cdd66b6/go.mod h1:jN7ZJM5YSVtD3SHmkAdN/cOC1dXiqg2Y9K5Sr5a8Nxw= +github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/daixiang0/gci v0.13.4/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk= +github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= +github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= +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/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v23.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw= +github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.12.0/go.mod h1:ZBTaoJ23lqITozF0M6G4/IragXCQKCnYbmlmtHvwRG0= +github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0= +github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= +github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= +github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= +github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= +github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= +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/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= +github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= +github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs= +github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw= +github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +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/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= +github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= +github.com/gagliardetto/solana-go v1.10.0/go.mod h1:afBEcIRrDLJst3lvAahTr63m6W2Ns6dajZxe2irF7Jg= +github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= +github.com/garslo/gogen v0.0.0-20170306192744-1d203ffc1f61/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +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/ghostiam/protogetter v0.3.6/go.mod h1:7lpeDnEJ1ZjL/YtyoN99ljO4z0pd3H0d18/t2dPBxHw= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-critic/go-critic v0.11.3/go.mod h1:Je0h5Obm1rR5hAGA9mP2PDiOOk53W+n7pyvXErFKIgI= +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-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +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-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= +github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= +github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= +github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= +github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= +github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= +github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= +github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +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/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ= +github.com/golangci/gofmt v0.0.0-20231018234816-f50ced29576e/go.mod h1:Pm5KhLPA8gSnQwrQ6ukebRcapGb/BG9iUkdaiCcGHJM= +github.com/golangci/golangci-lint v1.58.1/go.mod h1:IX9uSbhwDDOVTcceKZWmshlally+fOQYv1pZhIJCMNw= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.5.1/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo= +github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM= +github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc= +github.com/golangci/revgrep v0.5.3/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= +github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= +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-containerregistry v0.13.0/go.mod h1:J9FQ+eSS4a1aC2GNZxvNpbWhgp0487v+cgiilB4FqDo= +github.com/google/go-github/v41 v41.0.0/go.mod h1:XgmCA5H323A9rtgExdTcnDkcqp6S30AVACCBDOonIxg= +github.com/google/go-pkcs11 v0.2.1-0.20230907215043-c6f79328ddf9/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +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/googleapis/google-cloud-go-testing v0.0.0-20210719221736-1c9a4c676720/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= +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/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= +github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= +github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak= +github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= +github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= +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/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.4.0/go.mod h1:9Ai6uvFy5fQNq6VPKtg+Ceq1+eTY4nKUlR2JElEOcDo= +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/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= +github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= +github.com/informalsystems/itf-go v0.0.1/go.mod h1:wgqaQ/yl2kbNlgw6GaleuHEefpZvkZo6Hc0jc8cGG9M= +github.com/informalsystems/tm-load-test v1.3.0/go.mod h1:OQ5AQ9TbT5hKWBNIwsMjn6Bf4O0U4b1kRc+0qZlQJKw= +github.com/initia-labs/initia v0.3.5 h1:JsO0OZ+ZRQjzFusXSA2f7U1LNO6nApaCr+U6idJ+Pko= +github.com/initia-labs/initia v0.3.5/go.mod h1:nwtnVe3obacErGb7w6tq8Ych3U0d2f59rsgpVUeMnmM= +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/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jdxcode/netrc v0.0.0-20221124155335-4616370d1a84/go.mod h1:Zi/ZFkEqFHTm7qkjyNJjaWH4LQA9LQhGJyF0lTYGpxw= +github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= +github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4= +github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= +github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jjti/go-spancheck v0.6.1/go.mod h1:vF1QkOO159prdo6mHRxak2CpzDpHAfKiPUDP/NeRnX8= +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/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0= +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/junk1tm/musttag v0.5.0/go.mod h1:PcR7BA+oREQYvHwgjIDmw3exJeds5JzRcvEJTfjrA0M= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= +github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k= +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/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= +github.com/kisielk/errcheck v1.7.0/go.mod h1:1kLL+jV4e+CFfueBmI1dSK2ADDyQnlrnrY/FqKluHJQ= +github.com/kkHAIKE/contextcheck v1.1.5/go.mod h1:O930cpht4xb1YQpK+1+AgoM3mFsvxr7uyFptcnWTYUA= +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/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +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/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= +github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY= +github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA= +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/lasiar/canonicalheader v1.0.6/go.mod h1:GfXTLQb3O1qF5qcSTyXTnfNUggUNyzbkOSpzZ0dpUJo= +github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g= +github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= +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/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= +github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= +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/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE= +github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc= +github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +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/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc= +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/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= +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/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moricho/tparallel v0.3.1/go.mod h1:leENX2cUv7Sv2qDgdi0D0fCftN8fRC67Bcn8pqzeYNI= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1/go.mod h1:ye2e/VUEtE2BHE+G/QcKkcLQVAEJoYRFj5VUOQatCRE= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= +github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= +github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= +github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k= +github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4= +github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= +github.com/nats-io/nats.go v1.31.0/go.mod h1:di3Bm5MLsoB4Bx61CBTsxuarI36WbhAwOm8QrW39+i8= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= +github.com/nats-io/nkeys v0.4.6/go.mod h1:4DxZNzenSVd1cYQoAa8948QY3QDjrHfcfVADymtkpts= +github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= +github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= +github.com/nunnatsa/ginkgolinter v0.16.2/go.mod h1:4tWRinDN1FeJgU+iJANW/kz7xKN5nYRAOfJDQUS9dOQ= +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/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openzipkin/zipkin-go v0.2.5/go.mod h1:KpXfKdgRDnnhsxw4pNIH9Md5lyFqKUa4YDFlwRYAMyE= +github.com/oxyno-zeta/gomock-extra-matcher v1.2.0/go.mod h1:S0r7HmKeCGsHmvIVFMjKWwswb4+30nCNWbXRMBVPkaU= +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/performancecopilot/speed/v4 v4.0.0/go.mod h1:qxrSyuDGrTOWfV+uKRFhfxw6h/4HXRGUiZiufxo49BM= +github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= +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/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= +github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= +github.com/polyfloyd/go-errorlint v1.5.1/go.mod h1:sH1QC1pxxi0fFecsVIzBmxtrgd9IF/SkJpA6wqyKAJs= +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/protolambda/bls12-381-util v0.1.0/go.mod h1:cdkysJTRpeFeuUVx/TXGDQNMTiRAalk1vQw3TYTHcE4= +github.com/protolambda/zrnt v0.32.2/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= +github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= +github.com/quasilyte/go-ruleguard v0.4.2/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI= +github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= +github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= +github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/rabbitmq/amqp091-go v1.2.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= +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/ryancurrah/gomodguard v1.3.2/go.mod h1:LqdemiFomEjcxOqirbQCb3JFvSxH2JUYMerTFd3sF2o= +github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sagikazarmark/crypt v0.17.0/go.mod h1:SMtHTvdmsZMuY/bpZoqokSoChIrcJ/epOxZN58PbZDg= +github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= +github.com/sashamelentyev/usestdlibvars v1.25.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +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/securego/gosec/v2 v2.19.0/go.mod h1:hOkDcHz9J/XIgIlPDXalxjeVYsHxoWUc5zJSHxcB8YM= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= +github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY= +github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= +github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= +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/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= +github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= +github.com/streadway/handy v0.0.0-20200128134331-0f66f006fb2e/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= +github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= +github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg= +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/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= +github.com/tetafro/godot v1.4.16/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ= +github.com/timonwong/loggercheck v0.9.4/go.mod h1:caz4zlPcgvpEkXgVnAJGowHAMW2NwHaNlpS8xDbVhTg= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tomarrell/wrapcheck/v2 v2.8.3/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo= +github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= +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/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4= +github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= +github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/uudashr/gocognit v1.1.2/go.mod h1:aAVdLURqcanke8h3vg35BC++eseDm66Z7KmchI5et4k= +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/vektra/mockery/v2 v2.43.0/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8= +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/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +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/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg= +github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= +github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= +github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= +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= +gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= +go-simpler.org/musttag v0.12.1/go.mod h1:46HKu04A3Am9Lne5kKP0ssgwY3AeIlqsDzz3UxKROpY= +go-simpler.org/sloglint v0.6.0/go.mod h1:+kJJtebtPePWyG5boFwY46COydAggADDOHM22zOvzBk= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= +go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= +go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.etcd.io/gofail v0.1.0/go.mod h1:VZBCXYGZhHAinaBiiqYvuDynvahNsAyLFwB3kEHKz1M= +go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= +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/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= +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= +golang.org/x/vuln v1.1.0/go.mod h1:HT/Ar8fE34tbxWG2s7PYjVl+iIE4Er36/940Z+K540Y= +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/gonum v0.12.0/go.mod h1:73TDxJfAAHeA8Mk9mf8NlIppyhQNo5GLTcYeqgo2lvY= +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/bytestream v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:SCz6T5xjNXM4QFPRwxHcfChp7V+9DcXR3ay2TkHR8Tg= +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= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= +mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20240427195214-063aff900ca1/go.mod h1:ZzZjEpJDOmx8TdVU6umamY3Xy0UAQUI2DHbf05USVbI= 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..c469f6e 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.5 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..fa0ab74 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,12 @@ 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/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 +790,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/README.md b/jsonrpc/README.md new file mode 100644 index 0000000..d96225c --- /dev/null +++ b/jsonrpc/README.md @@ -0,0 +1,79 @@ +# ETH JSON-RPC + +The ETH JSON-RPC (Remote Procedure Call) is a protocol that allows clients to interact with Ethereum nodes using JSON (JavaScript Object Notation) messages over HTTP or IPC (Inter-Process Communication). It provides a standardized way to communicate with the Ethereum network and perform various operations such as querying blockchain data, executing smart contracts, and managing accounts. + +## RPC list + +| namespace | api | supported | description | +| --------- | ------------------------------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| web3 | web3_clientVersion | 🚫 | Returns the current client version. | +| web3 | web3_sha3 | 🚫 | Returns the Keccak-256 (not the standardized SHA3-256) of the given data. | +| net | net_version | ✅ | Returns the current network ID. | +| net | net_peerCount | 🚫 | Returns the number of peers currently connected to the client. | +| net | net_listening | 🚫 | Returns true if the client is actively listening for network connections. | +| eth | eth_protocolVersion | 🚫 | Returns the current Ethereum protocol version. | +| eth | eth_syncing | 🚫 | Returns an object with data about the sync status or false if not syncing. | +| eth | eth_coinbase | 🚫 | Returns the client coinbase address. | +| eth | eth_chainId | ✅ | Returns the chain id. | +| eth | eth_mining | 🚫 | Returns true if the client is actively mining new blocks. | +| eth | eth_hashrate | 🚫 | Returns the number of hashes per second that the node is mining with. | +| eth | eth_gasPrice | ✅ | Returns the current price per gas in wei. | +| eth | eth_maxPriorityFeePerGas | ✅ | Returns the max priority fee per gas. | +| eth | eth_feeHistory | 🚫 | Returns the collection of historical gas information. | +| eth | eth_accounts | ✅ | Returns a list of addresses owned by the client. | +| eth | eth_blockNumber | ✅ | Returns the number of the most recent block. | +| eth | eth_getBalance | ✅ | Returns the balance of the account of given address. | +| eth | eth_getStorageAt | ✅ | Returns the value from a storage position at a given address. | +| eth | eth_getTransactionCount | ✅ | Returns the number of transactions sent from an address. | +| eth | eth_getTransactionCountByHash | ✅ | Returns the number of transactions in a block from a block matching the given block hash. | +| eth | eth_getBlockTransactionCountByNumber | ✅ | Returns the number of transactions in a block matching the given block number. | +| eth | eth_getUncleCountByBlockHash | 🚫 | Returns the number of uncles in a block from a block matching the given block hash. | +| eth | eth_getUncleCountByBlockNumber | 🚫 | Returns the number of uncles in a block from a block matching the given block number. | +| eth | eth_getCode | ✅ | Returns the code at a given address. | +| eth | eth_sign | 🚫 | Signs data with a given address. | +| eth | eth_signTypedData | 🚫 | Signs typed data with a given address. | +| eth | eth_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). | +| eth | eth_sendTransaction | 🚫 | Creates a new message call transaction or a contract creation if the data field contains code. | +| eth | eth_resend | 🚫 | Remove the given transaction from the pool and reinsert it with the new gas price and limit. | +| eth | eth_sendRawTransaction | ✅ | Sends a signed transaction to the network. | +| eth | eth_call | ✅ | Executes a new message call immediately without creating a transaction on the block chain. | +| eth | eth_estimateGas | ✅ | Generates an estimate of how much gas is necessary to allow the transaction to complete. | +| eth | eth_getBlockByHash | ✅ | Returns information about a block by hash. | +| eth | eth_getBlockByNumber | ✅ | Returns information about a block by block number. | +| eth | eth_getBlockReceipts | ✅ | Returns all transaction receipts for a given block. The API credit value for this method is 20. | +| eth | eth_getTransactionByHash | ✅ | Returns the information about a transaction requested by transaction hash. | +| eth | eth_getTransactionByBlockHashAndIndex | ✅ | Returns the information about a transaction by block hash and transaction index position. | +| eth | eth_getTransactionByBlockNumberAndIndex | ✅ | Returns the information about a transaction by block number and transaction index position. | +| eth | eth_getRawTransactionByHash | ✅ | Returns the raw transaction by block number and transaction index position. | +| eth | eth_getRawTransactionByBlockHashAndIndex | ✅ | Returns the raw transaction by block hash and transaction index position. | +| eth | eth_getRawTransactionByBlockNumberAndIndex | ✅ | Returns the raw transaction by block number and transaction index position. | +| eth | eth_getTransactionReceipt | ✅ | Returns the receipt of a transaction by transaction hash. | +| eth | eth_getUncleByBlockHashAndIndex | 🚫 | Returns information about a uncle of a block by hash and uncle index position. | +| eth | eth_getUncleByBlockNumberAndIndex | 🚫 | Returns information about a uncle of a block by number and uncle index position. | +| eth | eth_getCompilers | 🚫 | Returns a list of available compilers. | +| eth | eth_compileLLL | 🚫 | Returns compiled LLL code. | +| eth | eth_compileSolidity | 🚫 | Returns compiled solidity code. | +| eth | eth_compileSerpent | 🚫 | Returns compiled serpent code. | +| eth | eth_newFilter | ✅ | Creates a filter object based on filter options to notify when the state changes (logs). | +| eth | eth_newBlockFilter | ✅ | Creates a filter in the node to notify when a new block arrives. | +| eth | eth_newPendingTransactionFilter | ✅ | Creates a filter in the node to notify when new pending transactions arrive. | +| eth | eth_uninstallFilter | ✅ | Uninstalls a filter with given id. | +| eth | eth_getFilterChanges | ✅ | Polling method for a filter which returns an array of logs which occurred since last poll. | +| eth | eth_getFilterLogs | ✅ | Returns an array of all logs matching filter with given id. | +| eth | eth_getLogs | ✅ | Returns an array of all logs matching a given filter object. | +| eth | eth_getProof | 🚫 | Returns the account and storage values of the specified account including the Merkle-proof. The API credit value for this method is 20. | +| personal | personal_importRawKey | 🚫 | Imports a raw key into the node's key store. | +| personal | personal_lockAccount | 🚫 | Locks the account. | +| personal | personal_unlockAccount | 🚫 | Unlocks the account. | +| personal | personal_newAccount | 🚫 | Creates a new account. | +| personal | personal_sendTransaction | 🚫 | Signs and sends a transaction. | +| personal | personal_listAccounts | 🚫 | Returns all the accounts that the client controls. | +| debug | debug_traceTransaction | 🚫 | Returns trace of a transaction by hash. | +| debug | debug_traceBlockByNumber | 🚫 | Returns trace of a block by number. | +| debug | debug_traceBlockByHash | 🚫 | Returns trace of a block by hash. | +| debug | debug_storageRangeAt | 🚫 | Returns a storage range at a specific position. | +| debug | debug_getBadBlocks | 🚫 | Returns list of bad blocks. | +| txpool | txpool_content | 🚫 | Returns all pending and queued transactions | +| txpool | txpool_inspect | 🚫 | Returns a textual summary of all pending and queued transactions | +| txpool | txpool_contentFrom | 🚫 | Retrieves the transactions contained within the txpool, returning pending and queued transactions of this address, grouped by nonce | +| txpool | txpool_status | 🚫 | Returns the number of transactions in pending and queued states | 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:])