Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
- (store) [#12](https://github.com/EscanBE/evermint/pull/12) Add local `snapshots` management commands
- (store) [#14](https://github.com/EscanBE/evermint/pull/14) Add `inspect` command and sub-commands
- (test+rpc) [#74](https://github.com/EscanBE/evermint/pull/74) Add integration test util + add IT skeleton for Json-RPC
- (vesting) [#144](https://github.com/EscanBE/evermint/pull/144) Support vesting account creation via new module `x/vauth`

### Improvement

Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ evmd convert-address evm1sv9m0g7ycejwr3s369km58h5qe7xj77hxrsmsz evmos
# alias: "ca"
```
2. [Rename chain](https://github.com/EscanBE/evermint/blob/main/RENAME_CHAIN.md)
3. [`snapshots` command](https://github.com/EscanBE/evermint/pull/12)
4. [`inspect` command](https://github.com/EscanBE/evermint/pull/14)
5. [Flag `--allow-insecure-unlock`](https://github.com/EscanBE/evermint/pull/142)
6. Dependencies updated: `Cosmos-SDK v0.47.13`, `CometBFT v0.37.5`, `ibc-go v7.8.0`, `go-ethereum v1.10.26`
3. [Support vesting account creation](https://github.com/EscanBE/evermint/pull/144) with help from module `x/vauth`
4. [`snapshots` command](https://github.com/EscanBE/evermint/pull/12)
5. [`inspect` command](https://github.com/EscanBE/evermint/pull/14)
6. [Flag `--allow-insecure-unlock`](https://github.com/EscanBE/evermint/pull/142)
7. Dependencies updated: `Cosmos-SDK v0.47.13`, `CometBFT v0.37.5`, `ibc-go v7.8.0`, `go-ethereum v1.10.26`
4 changes: 4 additions & 0 deletions app/ante/cosmos/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ type BankKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
}

type VAuthKeeper interface {
HasProofExternalOwnedAccount(ctx sdk.Context, accAddr sdk.AccAddress) bool
}
6 changes: 0 additions & 6 deletions app/ante/cosmos/reject_msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
evmtypes "github.com/EscanBE/evermint/v12/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)

// RejectMessagesDecorator prevents invalid msg types from being executed
Expand All @@ -20,11 +19,6 @@ func (rmd RejectMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
errortypes.ErrInvalidType,
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
)
case *vestingtypes.MsgCreateVestingAccount, *vestingtypes.MsgCreatePeriodicVestingAccount, *vestingtypes.MsgCreatePermanentLockedAccount:
return ctx, errorsmod.Wrapf(
errortypes.ErrInvalidType,
"vesting messages are prohibited from execution: %T", msg,
)
default:
continue
}
Expand Down
49 changes: 49 additions & 0 deletions app/ante/cosmos/vesting.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package cosmos

import (
errorsmod "cosmossdk.io/errors"
vauthtypes "github.com/EscanBE/evermint/v12/x/vauth/types"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)

// VestingMessagesAuthorizationDecorator authorize vesting account creation msg execution.
// - If the target account has proof of EOA via `x/vauth`, the message can keep going.
// - Otherwise, the message will be rejected.
type VestingMessagesAuthorizationDecorator struct {
vAuthKeeper VAuthKeeper
}

// NewVestingMessagesAuthorizationDecorator creates a new VestingMessagesAuthorizationDecorator.
func NewVestingMessagesAuthorizationDecorator(vak VAuthKeeper) VestingMessagesAuthorizationDecorator {
return VestingMessagesAuthorizationDecorator{
vAuthKeeper: vak,
}
}

// AnteHandle (read VestingMessagesAuthorizationDecorator)
func (vd VestingMessagesAuthorizationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
for _, msg := range tx.GetMsgs() {
var account string
if m, ok := msg.(*vestingtypes.MsgCreateVestingAccount); ok {
account = m.ToAddress
} else if m, ok := msg.(*vestingtypes.MsgCreatePeriodicVestingAccount); ok {
account = m.ToAddress
} else if m, ok := msg.(*vestingtypes.MsgCreatePermanentLockedAccount); ok {
account = m.ToAddress
} else {
continue
}

if vd.vAuthKeeper.HasProofExternalOwnedAccount(ctx, sdk.MustAccAddressFromBech32(account)) {
continue
}

return ctx, errorsmod.Wrapf(
errortypes.ErrUnauthorized,
"must prove account is external owned account (EOA) via `x/%s` module before able to create vesting account: %s", vauthtypes.ModuleName, account,
)
}
return next(ctx, tx, simulate)
}
103 changes: 103 additions & 0 deletions app/ante/cosmos/vesting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package cosmos_test

import (
sdkmath "cosmossdk.io/math"
"encoding/hex"
"fmt"
cosmosante "github.com/EscanBE/evermint/v12/app/ante/cosmos"
"github.com/EscanBE/evermint/v12/constants"
"github.com/EscanBE/evermint/v12/rename_chain/marker"
"github.com/EscanBE/evermint/v12/testutil"
testutiltx "github.com/EscanBE/evermint/v12/testutil/tx"
vauthtypes "github.com/EscanBE/evermint/v12/x/vauth/types"
sdk "github.com/cosmos/cosmos-sdk/types"
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
"github.com/ethereum/go-ethereum/crypto"
"time"
)

//goland:noinspection ALL
func (suite *AnteTestSuite) TestNewVestingMessagesAuthorizationDecorator() {
proof := vauthtypes.ProofExternalOwnedAccount{
Account: marker.ReplaceAbleAddress("evm1xx2enpw8wzlr64xkdz2gh3c7epucfdftnqtcem"),
Hash: "0x" + hex.EncodeToString(crypto.Keccak256([]byte(vauthtypes.MessageToSign))),
Signature: "0xe665110439b1d18002ef866285f7e532090065ad74274560db5e8373d0cdb6297afefc70a5dd46c23e74bd3f0f262195f089b2923242a14e8e0791f4b0621a2c00",
}

submitter := marker.ReplaceAbleAddress("evm1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ppeqynn")
nonProvedAddress := marker.ReplaceAbleAddress("evm1dx67l23hz9l0k9hcher8xz04uj7wf3yuqpfj0p")

amount := sdk.NewCoins(sdk.NewInt64Coin(constants.BaseDenom, 1e18))

testCases := []struct {
name string
malleate func(ctx sdk.Context) sdk.Tx
expPass bool
errMsg string
}{
{
name: "pass - invalid cosmos tx type",
malleate: func(_ sdk.Context) sdk.Tx {
return &testutiltx.InvalidTx{}
},
expPass: true,
},
{
name: "pass - account has proof",
malleate: func(ctx sdk.Context) sdk.Tx {
suite.app.VAuthKeeper.SaveProofExternalOwnedAccount(ctx, proof)

txBuilder := suite.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), constants.BaseDenom, &vestingtypes.MsgCreateVestingAccount{
FromAddress: submitter,
ToAddress: proof.Account,
Amount: amount,
EndTime: time.Now().Add(24 * time.Hour).Unix(),
Delayed: true,
})
return txBuilder.GetTx()
},
expPass: true,
},
{
name: "fail - reject account does not have proof",
malleate: func(ctx sdk.Context) sdk.Tx {
txBuilder := suite.CreateTestCosmosTxBuilder(sdkmath.NewInt(0), constants.BaseDenom, &vestingtypes.MsgCreateVestingAccount{
FromAddress: submitter,
ToAddress: nonProvedAddress,
Amount: amount,
EndTime: time.Now().Add(24 * time.Hour).Unix(),
Delayed: true,
})
return txBuilder.GetTx()
},
expPass: false,
errMsg: "must prove account is external owned account (EOA)",
},
}

var execTypes = []struct {
name string
isCheckTx bool
simulate bool
}{
{"deliverTx", false, false},
{"deliverTxSimulate", false, true},
}

for _, et := range execTypes {
for _, tc := range testCases {
suite.Run(fmt.Sprintf("%s - %s", et.name, tc.name), func() {
// s.SetupTest(et.isCheckTx)
ctx := suite.ctx.WithIsReCheckTx(et.isCheckTx)
dec := cosmosante.NewVestingMessagesAuthorizationDecorator(suite.app.VAuthKeeper)
_, err := dec.AnteHandle(ctx, tc.malleate(ctx), et.simulate, testutil.NextFn)

if tc.expPass {
suite.Require().NoError(err, tc.name)
} else {
suite.Require().ErrorContains(err, tc.errMsg)
}
})
}
}
}
7 changes: 7 additions & 0 deletions app/ante/handler_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ante
import (
errorsmod "cosmossdk.io/errors"
anteutils "github.com/EscanBE/evermint/v12/app/ante/utils"
vauthtypes "github.com/EscanBE/evermint/v12/x/vauth/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
errortypes "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -32,6 +33,7 @@ type HandlerOptions struct {
StakingKeeper *stakingkeeper.Keeper
FeeMarketKeeper evmante.FeeMarketKeeper
EvmKeeper evmante.EVMKeeper
VAuthKeeper cosmosante.VAuthKeeper
FeegrantKeeper ante.FeegrantKeeper
ExtensionOptionChecker ante.ExtensionOptionChecker
SignModeHandler authsigning.SignModeHandler
Expand Down Expand Up @@ -75,6 +77,9 @@ func (options HandlerOptions) Validate() error {
if options.EvmKeeper == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "evm keeper is required for AnteHandler")
}
if options.VAuthKeeper == nil {
return errorsmod.Wrapf(errortypes.ErrLogic, "%s keeper is required for AnteHandler", vauthtypes.ModuleName)
}
if options.SigGasConsumer == nil {
return errorsmod.Wrap(errortypes.ErrLogic, "signature gas consumer is required for AnteHandler")
}
Expand Down Expand Up @@ -127,6 +132,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
ante.NewSetUpContextDecorator(),
ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker),
ante.NewValidateBasicDecorator(),
cosmosante.NewVestingMessagesAuthorizationDecorator(options.VAuthKeeper),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
cosmosante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
Expand All @@ -151,6 +157,7 @@ func newLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
),
ante.NewSetUpContextDecorator(),
ante.NewValidateBasicDecorator(),
cosmosante.NewVestingMessagesAuthorizationDecorator(options.VAuthKeeper),
ante.NewTxTimeoutHeightDecorator(),
cosmosante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper),
ante.NewValidateMemoDecorator(options.AccountKeeper),
Expand Down
30 changes: 24 additions & 6 deletions app/ante/handler_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,21 @@ func (suite *AnteTestSuite) TestValidateHandlerOptions() {
},
false,
},
{
"fail - empty VAuth keeper",
ante.HandlerOptions{
Cdc: suite.app.AppCodec(),
AccountKeeper: suite.app.AccountKeeper,
BankKeeper: suite.app.BankKeeper,
DistributionKeeper: suite.app.DistrKeeper,
IBCKeeper: suite.app.IBCKeeper,
StakingKeeper: suite.app.StakingKeeper,
FeeMarketKeeper: suite.app.FeeMarketKeeper,
EvmKeeper: suite.app.EvmKeeper,
VAuthKeeper: &suite.app.VAuthKeeper,
},
false,
},
{
"fail - empty signature gas consumer",
ante.HandlerOptions{
Expand Down Expand Up @@ -188,6 +203,7 @@ func (suite *AnteTestSuite) TestValidateHandlerOptions() {
DistributionKeeper: suite.app.DistrKeeper,
ExtensionOptionChecker: types.HasDynamicFeeExtensionOption,
EvmKeeper: suite.app.EvmKeeper,
VAuthKeeper: &suite.app.VAuthKeeper,
StakingKeeper: suite.app.StakingKeeper,
FeegrantKeeper: suite.app.FeeGrantKeeper,
IBCKeeper: suite.app.IBCKeeper,
Expand All @@ -202,11 +218,13 @@ func (suite *AnteTestSuite) TestValidateHandlerOptions() {
}

for _, tc := range cases {
err := tc.options.Validate()
if tc.expPass {
suite.Require().NoError(err, tc.name)
} else {
suite.Require().Error(err, tc.name)
}
suite.Run(tc.name, func() {
err := tc.options.Validate()
if tc.expPass {
suite.Require().NoError(err, tc.name)
} else {
suite.Require().Error(err, tc.name)
}
})
}
}
Loading