diff --git a/app/app.go b/app/app.go index ecab0bc8f1..77503eb42d 100644 --- a/app/app.go +++ b/app/app.go @@ -726,7 +726,7 @@ func New( } app.EvmKeeper = *evmkeeper.NewKeeper(keys[evmtypes.StoreKey], tkeys[evmtypes.TransientStoreKey], app.GetSubspace(evmtypes.ModuleName), app.receiptStore, app.BankKeeper, - &app.AccountKeeper, &app.StakingKeeper, app.TransferKeeper, + &app.AccountKeeper, &app.StakingKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), &app.WasmKeeper, &app.UpgradeKeeper) app.BankKeeper.RegisterRecipientChecker(app.EvmKeeper.CanAddressReceive) @@ -797,7 +797,7 @@ func New( app.GigaEvmKeeper = *gigaevmkeeper.NewKeeper(keys[evmtypes.StoreKey], tkeys[evmtypes.TransientStoreKey], app.GetSubspace(evmtypes.ModuleName), app.receiptStore, app.GigaBankKeeper, - &app.AccountKeeper, &app.StakingKeeper, app.TransferKeeper, + &app.AccountKeeper, &app.StakingKeeper, wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper), &app.WasmKeeper, &app.UpgradeKeeper) app.GigaEvmKeeper.UseRegularStore = true app.GigaBankKeeper.UseRegularStore = true diff --git a/app/precompiles.go b/app/precompiles.go index df70e31806..ee2c4eb0c3 100644 --- a/app/precompiles.go +++ b/app/precompiles.go @@ -38,10 +38,6 @@ type PrecompileKeepers struct { putils.SlashingMsgServer putils.SlashingQuerier putils.UpgradeQuerier - putils.TransferKeeper - putils.ClientKeeper - putils.ConnectionKeeper - putils.ChannelKeeper txConf client.TxConfig cdc codec.Codec } @@ -73,10 +69,6 @@ func NewPrecompileKeepers(a *App) *PrecompileKeepers { SlashingMsgServer: slashingkeeper.NewMsgServerImpl(a.SlashingKeeper), SlashingQuerier: a.SlashingKeeper, UpgradeQuerier: a.UpgradeKeeper, - TransferKeeper: a.TransferKeeper, - ClientKeeper: a.IBCKeeper.ClientKeeper, - ConnectionKeeper: a.IBCKeeper.ConnectionKeeper, - ChannelKeeper: a.IBCKeeper.ChannelKeeper, txConf: a.GetTxConfig(), cdc: a.appCodec, } @@ -109,9 +101,5 @@ func (pk *PrecompileKeepers) ParamsQ() putils.ParamsQuerier { return pk.P func (pk *PrecompileKeepers) SlashingMS() putils.SlashingMsgServer { return pk.SlashingMsgServer } func (pk *PrecompileKeepers) SlashingQ() putils.SlashingQuerier { return pk.SlashingQuerier } func (pk *PrecompileKeepers) UpgradeQ() putils.UpgradeQuerier { return pk.UpgradeQuerier } -func (pk *PrecompileKeepers) TransferK() putils.TransferKeeper { return pk.TransferKeeper } -func (pk *PrecompileKeepers) ClientK() putils.ClientKeeper { return pk.ClientKeeper } -func (pk *PrecompileKeepers) ConnectionK() putils.ConnectionKeeper { return pk.ConnectionKeeper } -func (pk *PrecompileKeepers) ChannelK() putils.ChannelKeeper { return pk.ChannelKeeper } func (pk *PrecompileKeepers) TxConfig() client.TxConfig { return pk.txConf } func (pk *PrecompileKeepers) Codec() codec.Codec { return pk.cdc } diff --git a/evmrpc/historical_trace_error.go b/evmrpc/historical_trace_error.go new file mode 100644 index 0000000000..2a33cde766 --- /dev/null +++ b/evmrpc/historical_trace_error.go @@ -0,0 +1,57 @@ +package evmrpc + +import ( + "context" + "sync" + + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" +) + +type historicalTraceErrorCollector struct { + mu sync.Mutex + err error +} + +func (c *historicalTraceErrorCollector) RecordHistoricalTraceError(err error) { + c.mu.Lock() + defer c.mu.Unlock() + if c.err == nil { + c.err = err + } +} + +func (c *historicalTraceErrorCollector) Err() error { + c.mu.Lock() + defer c.mu.Unlock() + return c.err +} + +type historicalTraceErrorCollectorKey struct{} + +func withHistoricalTraceErrorCollector(ctx context.Context) (context.Context, *historicalTraceErrorCollector) { + collector := &historicalTraceErrorCollector{} + return context.WithValue(ctx, historicalTraceErrorCollectorKey{}, collector), collector +} + +func historicalTraceErrorCollectorFromContext(ctx context.Context) *historicalTraceErrorCollector { + collector, _ := ctx.Value(historicalTraceErrorCollectorKey{}).(*historicalTraceErrorCollector) + return collector +} + +// attachHistoricalTraceErrorCollector bridges the RPC request context into the +// SDK context used by precompiles during replay. +func attachHistoricalTraceErrorCollector(sdkCtx sdk.Context, requestCtx context.Context) sdk.Context { + collector := historicalTraceErrorCollectorFromContext(requestCtx) + if collector == nil { + return sdkCtx + } + return pcommon.WithHistoricalTraceErrorRecorder(sdkCtx, collector) +} + +func rejectUnavailableHistoricalTrace(result interface{}, traceErr error, collector *historicalTraceErrorCollector) (interface{}, error) { + if err := collector.Err(); err != nil { + return nil, err + } + return result, traceErr +} diff --git a/evmrpc/historical_trace_error_test.go b/evmrpc/historical_trace_error_test.go new file mode 100644 index 0000000000..4cf1a9042d --- /dev/null +++ b/evmrpc/historical_trace_error_test.go @@ -0,0 +1,43 @@ +package evmrpc + +import ( + "context" + "errors" + "testing" + + "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/require" +) + +func TestRejectUnavailableHistoricalTrace(t *testing.T) { + ctx, collector := withHistoricalTraceErrorCollector(context.Background()) + require.NotNil(t, historicalTraceErrorCollectorFromContext(ctx)) + + historicalErr := errors.New("historical execution unavailable") + collector.RecordHistoricalTraceError(historicalErr) + + result, err := rejectUnavailableHistoricalTrace("plausible but wrong", nil, collector) + require.Nil(t, result) + require.ErrorIs(t, err, historicalErr) +} + +type recordingHistoricalTraceBlockTracer struct { + err error +} + +func (t recordingHistoricalTraceBlockTracer) TraceBlockByNumber(ctx context.Context, _ rpc.BlockNumber, _ *tracers.TraceConfig) ([]*tracers.TxTraceResult, error) { + historicalTraceErrorCollectorFromContext(ctx).RecordHistoricalTraceError(t.err) + return []*tracers.TxTraceResult{{}}, nil +} + +func TestHistoricalTraceGuardedBlockTracer(t *testing.T) { + historicalErr := errors.New("historical execution unavailable") + tracer := historicalTraceGuardedBlockTracer{ + delegate: recordingHistoricalTraceBlockTracer{err: historicalErr}, + } + + result, err := tracer.TraceBlockByNumber(context.Background(), 1, nil) + require.Nil(t, result) + require.ErrorIs(t, err, historicalErr) +} diff --git a/evmrpc/simulate.go b/evmrpc/simulate.go index dc05696a2c..8f7cc9387c 100644 --- a/evmrpc/simulate.go +++ b/evmrpc/simulate.go @@ -701,6 +701,7 @@ func (b *Backend) initializeBlock(ctx context.Context, block *ethtypes.Block, ct reqBeginBlock := tmBlock.Block.ToReqBeginBlock(res.Validators) reqBeginBlock.Simulate = true baseCtx, baseRelease := ctxProvider(prevBlockHeight) + baseCtx = attachHistoricalTraceErrorCollector(baseCtx, ctx) sdkCtx := baseCtx.WithBlockHeight(blockNumber).WithBlockTime(tmBlock.Block.Time) legacyabci.BeginBlock(sdkCtx, blockNumber, reqBeginBlock.LastCommitInfo.Votes, tmBlock.Block.Evidence.ToABCI(), b.beginBlockKeepers) nextCtx, nextRelease := ctxProvider(sdkCtx.BlockHeight()) @@ -714,7 +715,10 @@ func (b *Backend) initializeBlock(ctx context.Context, block *ethtypes.Block, ct }, nil } -func (b *Backend) GetEVM(_ context.Context, msg *core.Message, stateDB vm.StateDB, h *ethtypes.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { +func (b *Backend) GetEVM(ctx context.Context, msg *core.Message, stateDB vm.StateDB, h *ethtypes.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) *vm.EVM { + if db := state.GetDBImpl(stateDB); db != nil { + db.WithCtx(attachHistoricalTraceErrorCollector(db.Ctx(), ctx)) + } txContext := core.NewEVMTxContext(msg) if blockCtx == nil { blockCtx, _ = b.keeper.GetVMBlockContext(b.ctxProvider(LatestCtxHeight).WithIsEVM(true).WithEVMEntryViaWasmdPrecompile(wasmd.IsWasmdCall(msg.To)), b.keeper.GetGasPool()) diff --git a/evmrpc/trace_baker.go b/evmrpc/trace_baker.go index 4cfe03a0b4..24e72bd056 100644 --- a/evmrpc/trace_baker.go +++ b/evmrpc/trace_baker.go @@ -21,6 +21,19 @@ type blockTracer interface { TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *gethtracers.TraceConfig) ([]*gethtracers.TxTraceResult, error) } +type historicalTraceGuardedBlockTracer struct { + delegate blockTracer +} + +func (t historicalTraceGuardedBlockTracer) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *gethtracers.TraceConfig) ([]*gethtracers.TxTraceResult, error) { + ctx, collector := withHistoricalTraceErrorCollector(ctx) + result, err := t.delegate.TraceBlockByNumber(ctx, number, config) + if historicalErr := collector.Err(); historicalErr != nil { + return nil, historicalErr + } + return result, err +} + // TraceBaker re-runs committed blocks through the tracer in background workers // and writes the JSON to a TraceDB. Enqueue is non-blocking; misses fall // through to live re-execution. @@ -64,13 +77,13 @@ func StartTraceBakerForDebugAPI(api *DebugAPI, cfg TraceBakerConfig) *TraceBaker if cache == nil { return nil } - b := NewTraceBaker(api.tracersAPI, cache, cfg) + b := NewTraceBaker(historicalTraceGuardedBlockTracer{delegate: api.tracersAPI}, cache, cfg) cache.SetTraceEnqueuer(b) b.Start() return b } -func NewTraceBaker(api *gethtracers.API, cache *keeper.TraceDB, cfg TraceBakerConfig) *TraceBaker { +func NewTraceBaker(api blockTracer, cache *keeper.TraceDB, cfg TraceBakerConfig) *TraceBaker { if cfg.Workers <= 0 { cfg.Workers = 1 } diff --git a/evmrpc/trace_profile.go b/evmrpc/trace_profile.go index 244836c5c6..929dcadd38 100644 --- a/evmrpc/trace_profile.go +++ b/evmrpc/trace_profile.go @@ -55,6 +55,7 @@ func (api *DebugAPI) TraceTransactionProfile(ctx context.Context, hash common.Ha return nil, returnErr } + ctx, collector := withHistoricalTraceErrorCollector(ctx) ctx, done, err := api.prepareTraceContext(ctx) if err != nil { return nil, err @@ -94,6 +95,9 @@ func (api *DebugAPI) TraceTransactionProfile(ctx context.Context, hash common.Ha if err != nil { return nil, err } + if err := collector.Err(); err != nil { + return nil, err + } blockContextStart := time.Now() blockCtx, err := tracingBackend.GetBlockContext(ctx, block, statedb, tracingBackend) @@ -119,6 +123,9 @@ func (api *DebugAPI) TraceTransactionProfile(ctx context.Context, hash common.Ha if err != nil { return nil, err } + if err := collector.Err(); err != nil { + return nil, err + } storeDump := dumpStoreTrace(statedb) historicalLookupNanos := historicalLookupNanos(storeDump) diff --git a/evmrpc/tracers.go b/evmrpc/tracers.go index 9afaf9ccfc..85812a9dfb 100644 --- a/evmrpc/tracers.go +++ b/evmrpc/tracers.go @@ -339,6 +339,7 @@ func (api *DebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, con return cached, nil } + ctx, collector := withHistoricalTraceErrorCollector(ctx) ctx, done, err := api.prepareTraceContext(ctx) if err != nil { return nil, err @@ -349,7 +350,8 @@ func (api *DebugAPI) TraceTransaction(ctx context.Context, hash common.Hash, con config = &tracers.TraceConfig{} } api.clampDefaultStructLogLimit(config) - return api.tracersAPI.TraceTransaction(ctx, hash, config) + result, returnErr = api.tracersAPI.TraceTransaction(ctx, hash, config) + return rejectUnavailableHistoricalTrace(result, returnErr, collector) } func (api *DebugAPI) tryTraceCache(hash common.Hash, config *tracers.TraceConfig) (interface{}, bool) { @@ -558,6 +560,7 @@ func (api *DebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNum return cached, nil } + ctx, collector := withHistoricalTraceErrorCollector(ctx) if config == nil { config = &tracers.TraceConfig{} } @@ -567,7 +570,7 @@ func (api *DebugAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNum } else { result, returnErr = api.tracersAPI.TraceBlockByNumber(ctx, number, config) } - return + return rejectUnavailableHistoricalTrace(result, returnErr, collector) } func (api *DebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *tracers.TraceConfig) (result interface{}, returnErr error) { @@ -594,6 +597,7 @@ func (api *DebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, con return cached, nil } + ctx, collector := withHistoricalTraceErrorCollector(ctx) if config == nil { config = &tracers.TraceConfig{} } @@ -603,7 +607,7 @@ func (api *DebugAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, con } else { result, returnErr = api.tracersAPI.TraceBlockByHash(ctx, hash, config) } - return + return rejectUnavailableHistoricalTrace(result, returnErr, collector) } func (api *DebugAPI) TraceCall(ctx context.Context, args export.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *tracers.TraceCallConfig) (result interface{}, returnErr error) { @@ -633,8 +637,9 @@ func (api *DebugAPI) TraceCall(ctx context.Context, args export.TransactionArgs, return nil, returnErr } api.clampDefaultStructLogLimit(&config.TraceConfig) + ctx, collector := withHistoricalTraceErrorCollector(ctx) result, returnErr = api.tracersAPI.TraceCall(ctx, args, blockNrOrHash, config) - return + return rejectUnavailableHistoricalTrace(result, returnErr, collector) } func (api *DebugAPI) GetRawHeader(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (_ hexutil.Bytes, returnErr error) { @@ -687,6 +692,7 @@ func (api *DebugAPI) TraceStateAccess(ctx context.Context, hash common.Hash) (re return nil, returnErr } + ctx, collector := withHistoricalTraceErrorCollector(ctx) ctx, done, err := api.prepareTraceContext(ctx) if err != nil { return nil, err @@ -721,6 +727,9 @@ func (api *DebugAPI) TraceStateAccess(ctx context.Context, hash common.Hash) (re if err != nil { return nil, err } + if err := collector.Err(); err != nil { + return nil, err + } // Bail before the potentially expensive prestate/trace serialization if the // trace deadline has already elapsed during replay. if err := ctx.Err(); err != nil { diff --git a/giga/deps/xevm/keeper/keeper.go b/giga/deps/xevm/keeper/keeper.go index 54813f5f35..af8a77d05f 100644 --- a/giga/deps/xevm/keeper/keeper.go +++ b/giga/deps/xevm/keeper/keeper.go @@ -33,7 +33,6 @@ import ( stakingkeeper "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/keeper" upgradekeeper "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/keeper" "github.com/sei-protocol/sei-chain/sei-db/ledger_db/receipt" - ibctransferkeeper "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/keeper" abci "github.com/sei-protocol/sei-chain/sei-tendermint/abci/types" tmtypes "github.com/sei-protocol/sei-chain/sei-tendermint/types" wasmkeeper "github.com/sei-protocol/sei-chain/sei-wasmd/x/wasm/keeper" @@ -55,7 +54,6 @@ type Keeper struct { bankKeeper bankkeeper.Keeper accountKeeper *authkeeper.AccountKeeper stakingKeeper *stakingkeeper.Keeper - transferKeeper ibctransferkeeper.Keeper wasmKeeper *wasmkeeper.PermissionedKeeper wasmViewKeeper *wasmkeeper.Keeper upgradeKeeper *upgradekeeper.Keeper @@ -128,7 +126,7 @@ func (ctx *ReplayChainContext) Config() *params.ChainConfig { func NewKeeper( storeKey sdk.StoreKey, transientStoreKey sdk.StoreKey, paramstore paramtypes.Subspace, receiptStateStore receipt.ReceiptStore, bankKeeper bankkeeper.Keeper, accountKeeper *authkeeper.AccountKeeper, stakingKeeper *stakingkeeper.Keeper, - transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper, wasmViewKeeper *wasmkeeper.Keeper, upgradeKeeper *upgradekeeper.Keeper) *Keeper { + wasmKeeper *wasmkeeper.PermissionedKeeper, wasmViewKeeper *wasmkeeper.Keeper, upgradeKeeper *upgradekeeper.Keeper) *Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) @@ -140,7 +138,6 @@ func NewKeeper( bankKeeper: bankKeeper, accountKeeper: accountKeeper, stakingKeeper: stakingKeeper, - transferKeeper: transferKeeper, wasmKeeper: wasmKeeper, wasmViewKeeper: wasmViewKeeper, upgradeKeeper: upgradeKeeper, diff --git a/precompiles/common/legacy/v605/expected_keepers.go b/precompiles/common/legacy/v605/expected_keepers.go index 018b15962e..25849ba792 100644 --- a/precompiles/common/legacy/v605/expected_keepers.go +++ b/precompiles/common/legacy/v605/expected_keepers.go @@ -4,10 +4,6 @@ import ( "context" "math/big" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/04-channel/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" @@ -16,7 +12,6 @@ import ( distrtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/distribution/types" govtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/gov/types" stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types" - ibctypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" "github.com/sei-protocol/sei-chain/utils" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" ) @@ -117,20 +112,3 @@ type DistributionKeeper interface { WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) DelegationTotalRewards(c context.Context, req *distrtypes.QueryDelegationTotalRewardsRequest) (*distrtypes.QueryDelegationTotalRewardsResponse, error) } - -type TransferKeeper interface { - Transfer(goCtx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) -} - -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) -} - -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) -} - -type ChannelKeeper interface { - GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) -} diff --git a/precompiles/common/legacy/v606/expected_keepers.go b/precompiles/common/legacy/v606/expected_keepers.go index 3d79669e61..f91e986fe3 100644 --- a/precompiles/common/legacy/v606/expected_keepers.go +++ b/precompiles/common/legacy/v606/expected_keepers.go @@ -4,10 +4,6 @@ import ( "context" "math/big" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/04-channel/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" @@ -16,7 +12,6 @@ import ( distrtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/distribution/types" govtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/gov/types" stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types" - ibctypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" "github.com/sei-protocol/sei-chain/utils" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" ) @@ -117,20 +112,3 @@ type DistributionKeeper interface { WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) DelegationTotalRewards(c context.Context, req *distrtypes.QueryDelegationTotalRewardsRequest) (*distrtypes.QueryDelegationTotalRewardsResponse, error) } - -type TransferKeeper interface { - Transfer(goCtx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) -} - -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) -} - -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) -} - -type ChannelKeeper interface { - GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) -} diff --git a/precompiles/common/legacy/v610/expected_keepers.go b/precompiles/common/legacy/v610/expected_keepers.go index b975bae011..05297520b0 100644 --- a/precompiles/common/legacy/v610/expected_keepers.go +++ b/precompiles/common/legacy/v610/expected_keepers.go @@ -4,10 +4,6 @@ import ( "context" "math/big" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/04-channel/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" @@ -16,7 +12,6 @@ import ( distrtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/distribution/types" govtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/gov/types" stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types" - ibctypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" "github.com/sei-protocol/sei-chain/utils" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" ) @@ -117,20 +112,3 @@ type DistributionKeeper interface { WithdrawDelegationRewards(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (sdk.Coins, error) DelegationTotalRewards(c context.Context, req *distrtypes.QueryDelegationTotalRewardsRequest) (*distrtypes.QueryDelegationTotalRewardsResponse, error) } - -type TransferKeeper interface { - Transfer(goCtx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) -} - -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) -} - -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) -} - -type ChannelKeeper interface { - GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) -} diff --git a/precompiles/common/retired.go b/precompiles/common/retired.go new file mode 100644 index 0000000000..c362ac7bd7 --- /dev/null +++ b/precompiles/common/retired.go @@ -0,0 +1,109 @@ +package common + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/tracing" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + putils "github.com/sei-protocol/sei-chain/precompiles/utils" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" +) + +// NewRetiredPrecompile keeps a precompile address registered while making every +// valid method call revert with reason. Unregistering an address would instead +// make calls succeed with empty output, which can appear successful to callers. +func NewRetiredPrecompile(a abi.ABI, address common.Address, name string, evmKeeper putils.EVMKeeper, reason string) *DynamicGasPrecompile { + return NewDynamicGasPrecompile(a, &retiredExecutor{ + evmKeeper: evmKeeper, + err: errors.New(reason), + revertData: encodeRevertReason(reason), + }, address, name) +} + +type retiredExecutor struct { + evmKeeper putils.EVMKeeper + err error + revertData []byte + historicalTraceUnsupportedAt func(sdk.Context) bool + name string +} + +func (e *retiredExecutor) Execute(ctx sdk.Context, _ *abi.Method, _ common.Address, _ common.Address, _ []interface{}, value *big.Int, _ bool, _ *vm.EVM, _ uint64, _ *tracing.Hooks) ([]byte, uint64, error) { + if e.historicalTraceUnsupportedAt != nil && e.historicalTraceUnsupportedAt(ctx) { + recordHistoricalTraceError(ctx, &HistoricalTraceUnavailableError{Precompile: e.name}) + } + if err := ValidateNonPayable(value); err != nil { + return common.CopyBytes(e.revertData), 0, err + } + return common.CopyBytes(e.revertData), GetRemainingGas(ctx, e.evmKeeper), e.err +} + +func (e *retiredExecutor) EVMKeeper() putils.EVMKeeper { + return e.evmKeeper +} + +// NewRetiredPrecompileWithTraceGuard builds a retired precompile whose valid +// calls mark selected trace contexts as unsupported. The EVM still receives a +// normal revert internally; the RPC replay boundary turns the marker into a +// hard error. +func NewRetiredPrecompileWithTraceGuard( + a abi.ABI, + address common.Address, + name string, + evmKeeper putils.EVMKeeper, + reason string, + historicalTraceUnsupportedAt func(sdk.Context) bool, +) *DynamicGasPrecompile { + p := NewRetiredPrecompile(a, address, name, evmKeeper, reason) + executor := p.GetExecutor().(*retiredExecutor) + executor.historicalTraceUnsupportedAt = historicalTraceUnsupportedAt + executor.name = name + return p +} + +// HistoricalTraceUnavailableError means replay reached precompile code that is +// no longer available and must not return a plausible but incorrect trace. +type HistoricalTraceUnavailableError struct { + Precompile string +} + +func (e *HistoricalTraceUnavailableError) Error() string { + return fmt.Sprintf("historical trace unavailable: %s precompile implementation has been retired", e.Precompile) +} + +type HistoricalTraceErrorRecorder interface { + RecordHistoricalTraceError(error) +} + +type historicalTraceErrorRecorderKey struct{} + +// WithHistoricalTraceErrorRecorder installs the trace-only error side channel +// used to carry incompatibility beyond the EVM's normal revert boundary. +func WithHistoricalTraceErrorRecorder(ctx sdk.Context, recorder HistoricalTraceErrorRecorder) sdk.Context { + return ctx.WithContext(context.WithValue(ctx.Context(), historicalTraceErrorRecorderKey{}, recorder)) +} + +func recordHistoricalTraceError(ctx sdk.Context, err error) { + recorder, ok := ctx.Context().Value(historicalTraceErrorRecorderKey{}).(HistoricalTraceErrorRecorder) + if ok { + recorder.RecordHistoricalTraceError(err) + } +} + +func encodeRevertReason(reason string) []byte { + stringType, err := abi.NewType("string", "", nil) + if err != nil { + panic(err) + } + reasonData, err := abi.Arguments{{Type: stringType}}.Pack(reason) + if err != nil { + panic(err) + } + return append(crypto.Keccak256([]byte("Error(string)"))[:4], reasonData...) +} diff --git a/precompiles/ibc/ibc.go b/precompiles/ibc/ibc.go index ec428d9c95..73cb422e0a 100644 --- a/precompiles/ibc/ibc.go +++ b/precompiles/ibc/ibc.go @@ -2,400 +2,39 @@ package ibc import ( "embed" - "errors" - "fmt" - "math/big" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - pcommon "github.com/sei-protocol/sei-chain/precompiles/common" "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" + "golang.org/x/mod/semver" ) -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) +const IBCAddress = "0x0000000000000000000000000000000000001009" -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS +const RetiredReason = "ibc precompile is retired; ibc transfers are disabled" -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper +const RetirementUpgrade = "v6.7" - TransferID []byte - TransferWithDefaultTimeoutID []byte -} +//go:embed abi.json +var currentABI embed.FS +// NewPrecompile keeps the IBC address registered but retires all of its +// methods because IBC transfers are permanently disabled. func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg + return newRetiredPrecompile(pcommon.MustGetABI(currentABI, "abi.json"), keepers), nil +} + +func newRetiredPrecompile(a abi.ABI, keepers utils.Keepers) *pcommon.DynamicGasPrecompile { + return pcommon.NewRetiredPrecompileWithTraceGuard( + a, + common.HexToAddress(IBCAddress), + "ibc", + keepers.EVMK(), + RetiredReason, + func(ctx sdk.Context) bool { + return ctx.IsTracing() && semver.Compare(ctx.ClosestUpgradeName(), RetirementUpgrade) < 0 + }, + ) } diff --git a/precompiles/ibc/ibc_test.go b/precompiles/ibc/ibc_test.go index 25136a2c9e..f840096309 100644 --- a/precompiles/ibc/ibc_test.go +++ b/precompiles/ibc/ibc_test.go @@ -1,732 +1,170 @@ package ibc_test import ( - "context" - "errors" "math/big" - "reflect" + "os" + "strings" "testing" - "time" + "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/stretchr/testify/require" + "github.com/sei-protocol/sei-chain/app" + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" "github.com/sei-protocol/sei-chain/precompiles/ibc" - "github.com/sei-protocol/sei-chain/precompiles/utils" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported" tmtypes "github.com/sei-protocol/sei-chain/sei-tendermint/proto/tendermint/types" - testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper" "github.com/sei-protocol/sei-chain/x/evm/state" - "github.com/stretchr/testify/require" ) -type MockTransferKeeper struct{} - -func (tk *MockTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { - return nil, nil -} - -func (tk *MockTransferKeeper) SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, -) error { - return nil -} - -type MockMemoTransferKeeper struct { - t require.TestingT - wantMemo string -} - -func (tk *MockMemoTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { - require.Equal(tk.t, tk.wantMemo, msg.Memo) - return nil, nil +type historicalTraceErrorRecorder struct { + err error } -func (tk *MockMemoTransferKeeper) SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, -) error { - return nil -} - -type MockFailedTransferTransferKeeper struct{} - -func (tk *MockFailedTransferTransferKeeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) { - return nil, errors.New("failed to send transfer") -} - -func (tk *MockFailedTransferTransferKeeper) SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, -) error { - return nil -} - -func TestPrecompile_Run(t *testing.T) { - senderSeiAddress, senderEvmAddress := testkeeper.MockAddressPair() - receiverAddress := "cosmos1yykwxjzr2tv4mhx5tsf8090sdg96f2ax8fydk2" - - pre, _ := ibc.NewPrecompile(&utils.EmptyKeepers{}) - testTransfer, _ := pre.ABI.MethodById(pre.GetExecutor().(*ibc.PrecompileExecutor).TransferID) - packedTrue, _ := testTransfer.Outputs.Pack(true) - - type fields struct { - transferKeeper utils.TransferKeeper - } - - type input struct { - receiverAddr string - sourcePort string - sourceChannel string - denom string - amount *big.Int - revisionNumber uint64 - revisionHeight uint64 - timeoutTimestamp uint64 - memo string - } - type args struct { - caller common.Address - callingContract common.Address - input *input - suppliedGas uint64 - value *big.Int - isFromDelegateCall bool - } - - commonArgs := args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "denom", - amount: big.NewInt(100), - revisionNumber: 1, - revisionHeight: 1, - timeoutTimestamp: 1, - }, - suppliedGas: uint64(1000000), - value: nil, - } - - tests := []struct { - name string - fields fields - args args - wantBz []byte - wantRemainingGas uint64 - wantErr bool - wantErrMsg string - }{ - { - name: "successful transfer: with amount > 0 between EVM addresses", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: commonArgs, - wantBz: packedTrue, - wantRemainingGas: 995840, - wantErr: false, - }, - { - name: "failed transfer: internal error", - fields: fields{transferKeeper: &MockFailedTransferTransferKeeper{}}, - args: commonArgs, - wantBz: nil, - wantErr: true, - wantErrMsg: "failed to send transfer", - }, - { - name: "failed transfer: caller not whitelisted", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: nil, isFromDelegateCall: true}, - wantBz: nil, - wantErr: true, - wantErrMsg: "cannot delegatecall IBC", - }, - { - name: "failed transfer: value is not nil", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: big.NewInt(100), isFromDelegateCall: true}, - wantBz: nil, - wantErr: true, - wantErrMsg: "sending funds to a non-payable function", - }, - { - name: "failed transfer: empty sourcePort", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "", // empty sourcePort - sourceChannel: "channel-0", - denom: "denom", - amount: big.NewInt(100), - revisionNumber: 1, - revisionHeight: 1, - timeoutTimestamp: 1, - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "port cannot be empty", - }, - { - name: "failed transfer: empty sourceChannel", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "", - denom: "denom", - amount: big.NewInt(100), - revisionNumber: 1, - revisionHeight: 1, - timeoutTimestamp: 1, - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "channelID cannot be empty", - }, - { - name: "failed transfer: invalid denom", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "", - amount: big.NewInt(100), - revisionNumber: 1, - revisionHeight: 1, - timeoutTimestamp: 1, - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "invalid denom", - }, - { - name: "failed transfer: invalid receiver address", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: "", - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "", - amount: big.NewInt(100), - revisionNumber: 1, - revisionHeight: 1, - timeoutTimestamp: 1, - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "receiverAddress is not a string or empty", - }, - { - name: "memo is added to the transfer if passed", - fields: fields{transferKeeper: &MockMemoTransferKeeper{t: t, wantMemo: "test memo"}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "usei", - amount: big.NewInt(100), - memo: "test memo", - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: packedTrue, - wantRemainingGas: 995720, - wantErr: false, - }, - { - name: "memo is not added to the transfer if not passed", - fields: fields{transferKeeper: &MockMemoTransferKeeper{t: t, wantMemo: ""}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "usei", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: packedTrue, - wantRemainingGas: 995843, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - testApp := testkeeper.EVMTestApp - ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) - k := &testApp.EvmKeeper - k.SetAddressMapping(ctx, senderSeiAddress, senderEvmAddress) - stateDb := state.NewDBImpl(ctx, k, true) - evm := vm.EVM{ - StateDB: stateDb, - TxContext: vm.TxContext{Origin: senderEvmAddress}, - } - p, _ := ibc.NewPrecompile(&app.PrecompileKeepers{ - TransferKeeper: tt.fields.transferKeeper, - EVMKeeper: k, - }) - transfer, err := p.ABI.MethodById(p.GetExecutor().(*ibc.PrecompileExecutor).TransferID) - require.Nil(t, err) - inputs, err := transfer.Inputs.Pack(tt.args.input.receiverAddr, - tt.args.input.sourcePort, tt.args.input.sourceChannel, tt.args.input.denom, tt.args.input.amount, - tt.args.input.revisionNumber, tt.args.input.revisionHeight, tt.args.input.timeoutTimestamp, - tt.args.input.memo) - require.Nil(t, err) - gotBz, gotRemainingGas, err := p.RunAndCalculateGas(&evm, tt.args.caller, tt.args.callingContract, append(p.GetExecutor().(*ibc.PrecompileExecutor).TransferID, inputs...), tt.args.suppliedGas, tt.args.value, nil, false, tt.args.isFromDelegateCall) - if (err != nil) != tt.wantErr { - t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err != nil { - require.Equal(t, vm.ErrExecutionReverted, err) - require.Nil(t, gotBz) - } else if !reflect.DeepEqual(gotBz, tt.wantBz) { - t.Errorf("Run() gotRet = %v, want %v", gotBz, tt.wantBz) - } - - if !reflect.DeepEqual(gotRemainingGas, tt.wantRemainingGas) { - t.Errorf("Run() gotRemainingGas = %v, want %v", gotRemainingGas, tt.wantRemainingGas) - } - }) - } +func (r *historicalTraceErrorRecorder) RecordHistoricalTraceError(err error) { + r.err = err } -func TestTransferWithDefaultTimeoutPrecompile_Run(t *testing.T) { - senderSeiAddress, senderEvmAddress := testkeeper.MockAddressPair() - receiverAddress := "cosmos1yykwxjzr2tv4mhx5tsf8090sdg96f2ax8fydk2" - - type fields struct { - transferKeeper utils.TransferKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - } +func TestEveryIBCVersionIsRetired(t *testing.T) { + testApp := app.Setup(t, false, true, false) + ctx := testApp.NewContext(false, tmtypes.Header{}) + evm := &vm.EVM{StateDB: state.NewDBImpl(ctx, &testApp.EvmKeeper, true)} - type input struct { - receiverAddr string - sourcePort string - sourceChannel string - denom string - amount *big.Int - memo string - } - type args struct { - caller common.Address - callingContract common.Address - input *input - suppliedGas uint64 - value *big.Int - isFromDelegateCall bool - } + manifest, err := os.ReadFile("versions") + require.NoError(t, err) + historicalVersions := strings.Fields(string(manifest)) - commonArgs := args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "denom", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, + const futureUpgrade = "future-upgrade" + versioned := ibc.GetVersioned(futureUpgrade, testApp.GetPrecompileKeepers()) + require.Len(t, versioned, len(historicalVersions)+1) + for _, version := range historicalVersions { + require.Contains(t, versioned, version) } - tests := []struct { - name string - fields fields - args args - wantBz []byte - wantRemainingGas uint64 - wantErr bool - wantErrMsg string - }{ - { - name: "failed transfer: caller not whitelisted", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: nil, isFromDelegateCall: true}, - wantBz: nil, - wantErr: true, - wantErrMsg: "cannot delegatecall IBC", - }, - { - name: "failed transfer: value is not nil", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{caller: senderEvmAddress, callingContract: common.Address{}, input: commonArgs.input, suppliedGas: 1000000, value: big.NewInt(100), isFromDelegateCall: true}, - wantBz: nil, - wantErr: true, - wantErrMsg: "sending funds to a non-payable function", - }, - { - name: "failed transfer: empty sourcePort", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "", // empty sourcePort - sourceChannel: "channel-0", - denom: "denom", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "port cannot be empty", - }, - { - name: "failed transfer: empty sourceChannel", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "", - denom: "denom", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "channelID cannot be empty", - }, - { - name: "failed transfer: invalid denom", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: receiverAddress, - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "invalid denom", - }, - { - name: "failed transfer: invalid receiver address", - fields: fields{transferKeeper: &MockTransferKeeper{}}, - args: args{ - caller: senderEvmAddress, - callingContract: senderEvmAddress, - input: &input{ - receiverAddr: "", - sourcePort: "transfer", - sourceChannel: "channel-0", - denom: "", - amount: big.NewInt(100), - }, - suppliedGas: uint64(1000000), - value: nil, - }, - wantBz: nil, - wantErr: true, - wantErrMsg: "receiverAddress is not a string or empty", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - testApp := testkeeper.EVMTestApp - ctx := testApp.NewContext(false, tmtypes.Header{}).WithBlockHeight(2) - k := &testApp.EvmKeeper - k.SetAddressMapping(ctx, senderSeiAddress, senderEvmAddress) - stateDb := state.NewDBImpl(ctx, k, true) - evm := vm.EVM{ - StateDB: stateDb, - TxContext: vm.TxContext{Origin: senderEvmAddress}, - } + for version, contract := range versioned { + t.Run(version, func(t *testing.T) { + precompile, ok := contract.(*pcommon.DynamicGasPrecompile) + require.True(t, ok) - p, _ := ibc.NewPrecompile(&app.PrecompileKeepers{ - TransferKeeper: tt.fields.transferKeeper, - EVMKeeper: k, - ClientKeeper: tt.fields.clientKeeper, - ChannelKeeper: tt.fields.channelKeeper, - ConnectionKeeper: tt.fields.connectionKeeper, - }) - transfer, err := p.ABI.MethodById(p.GetExecutor().(*ibc.PrecompileExecutor).TransferWithDefaultTimeoutID) - require.Nil(t, err) - inputs, err := transfer.Inputs.Pack(tt.args.input.receiverAddr, - tt.args.input.sourcePort, tt.args.input.sourceChannel, tt.args.input.denom, tt.args.input.amount, - tt.args.input.memo) - require.Nil(t, err) - gotBz, gotRemainingGas, err := p.RunAndCalculateGas(&evm, - tt.args.caller, - tt.args.callingContract, - append(p.GetExecutor().(*ibc.PrecompileExecutor).TransferWithDefaultTimeoutID, inputs...), - tt.args.suppliedGas, - tt.args.value, + input := validCallData(t, precompile.GetABI()) + ret, _, err := precompile.RunAndCalculateGas( + evm, + common.Address{}, + common.Address{}, + input, + 1_000_000, nil, + nil, + false, false, - tt.args.isFromDelegateCall, ) - if (err != nil) != tt.wantErr { - t.Errorf("Run() error = %v, wantErr %v", err, tt.wantErr) - return - } - if err != nil { - require.Equal(t, vm.ErrExecutionReverted, err) - require.Nil(t, gotBz) - } else if !reflect.DeepEqual(gotBz, tt.wantBz) { - t.Errorf("Run() gotRet = %v, want %v", gotBz, tt.wantBz) - } - if !reflect.DeepEqual(gotRemainingGas, tt.wantRemainingGas) { - t.Errorf("Run() gotRemainingGas = %v, want %v", gotRemainingGas, tt.wantRemainingGas) - } - }) - } -} + require.ErrorIs(t, err, vm.ErrExecutionReverted) -func TestPrecompile_GetAdjustedHeight(t *testing.T) { - type args struct { - latestConsensusHeight clienttypes.Height - } - tests := []struct { - name string - args args - want clienttypes.Height - wantErr bool - }{ - { - name: "height is adjusted with defaults", - args: args{ - latestConsensusHeight: clienttypes.NewHeight(2, 3), - }, - want: clienttypes.Height{ - RevisionNumber: 2, - RevisionHeight: 1003, - }, - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ibc.GetAdjustedHeight(tt.args.latestConsensusHeight) - if (err != nil) != tt.wantErr { - t.Errorf("GetAdjustedHeight() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetAdjustedHeight() got = %v, want %v", got, tt.want) - } + reason, err := abi.UnpackRevert(ret) + require.NoError(t, err) + require.Equal(t, ibc.RetiredReason, reason) }) } } -type MockClientKeeper struct { - consensusState *MockConsensusState - returnConsensusState bool -} - -func (ck *MockClientKeeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) { - return nil, false -} - -func (ck *MockClientKeeper) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) { - return ck.consensusState, ck.returnConsensusState -} - -type MockConsensusState struct { - timestamp uint64 -} - -func (m *MockConsensusState) Reset() { - panic("implement me") -} - -func (m *MockConsensusState) String() string { - panic("implement me") -} - -func (m *MockConsensusState) ProtoMessage() { - panic("implement me") -} - -func (m *MockConsensusState) ClientType() string { - return "mock" -} - -func (m *MockConsensusState) GetRoot() exported.Root { - return nil -} - -func (m *MockConsensusState) GetTimestamp() uint64 { - return m.timestamp -} - -func (m *MockConsensusState) ValidateBasic() error { - return nil -} - -func TestPrecompile_GetAdjustedTimestamp(t *testing.T) { - type fields struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - } - type args struct { - ctx sdk.Context - clientId string - height clienttypes.Height - } - timestampSeconds := 1714680155 - ctx := sdk.Context{} - tests := []struct { - name string - fields fields - args args - want uint64 - wantErr bool - }{ - { - name: "if consensus timestamp is less than the given time, return the given time adjusted with default", - fields: fields{ - clientKeeper: &MockClientKeeper{ - consensusState: &MockConsensusState{ - timestamp: uint64(timestampSeconds - 1), - }, - returnConsensusState: true, - }, - }, - args: args{ - ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), - }, - want: uint64(timestampSeconds)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), - wantErr: false, - }, - { - name: "if consensus state is not found, return the given time adjusted with default", - fields: fields{ - clientKeeper: &MockClientKeeper{ - returnConsensusState: false, - }, - }, - args: args{ - ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), - }, - want: uint64(timestampSeconds)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), - wantErr: false, - }, - { - name: "if time from local clock can not be retrieved, return error", - fields: fields{ - clientKeeper: &MockClientKeeper{ - returnConsensusState: false, - }, - }, - args: args{ - ctx: ctx.WithBlockTime(time.Unix(int64(0), 0)), - }, - wantErr: true, - }, - { - name: "if consensus timestamp is > than the given time, return the consensus time adjusted with default", - fields: fields{ - clientKeeper: &MockClientKeeper{ - consensusState: &MockConsensusState{ - timestamp: uint64(timestampSeconds+1) * 1_000_000_000, - }, - returnConsensusState: true, - }, - }, - args: args{ - ctx: ctx.WithBlockTime(time.Unix(int64(timestampSeconds), 0)), - }, - want: uint64(timestampSeconds+1)*1_000_000_000 + uint64((time.Duration(10) * time.Minute).Nanoseconds()), - wantErr: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - p, _ := ibc.NewPrecompile(&app.PrecompileKeepers{ - TransferKeeper: tt.fields.transferKeeper, - EVMKeeper: tt.fields.evmKeeper, - ClientKeeper: tt.fields.clientKeeper, - ChannelKeeper: tt.fields.channelKeeper, - ConnectionKeeper: tt.fields.connectionKeeper, - }) - got, err := p.GetExecutor().(*ibc.PrecompileExecutor).GetAdjustedTimestamp(tt.args.ctx, tt.args.clientId, tt.args.height) - if (err != nil) != tt.wantErr { - t.Errorf("GetAdjustedTimestamp() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("GetAdjustedTimestamp() got = %v, want %v", got, tt.want) +func TestRetiredIBCPrecompileRemainsNonPayable(t *testing.T) { + testApp := app.Setup(t, false, true, false) + ctx := testApp.NewContext(false, tmtypes.Header{}) + evm := &vm.EVM{StateDB: state.NewDBImpl(ctx, &testApp.EvmKeeper, true)} + + precompile, err := ibc.NewPrecompile(testApp.GetPrecompileKeepers()) + require.NoError(t, err) + + ret, remainingGas, err := precompile.RunAndCalculateGas( + evm, + common.Address{}, + common.Address{}, + validCallData(t, precompile.GetABI()), + 1_000_000, + big.NewInt(1), + nil, + false, + false, + ) + require.ErrorIs(t, err, vm.ErrExecutionReverted) + require.Zero(t, remainingGas) + + reason, err := abi.UnpackRevert(ret) + require.NoError(t, err) + require.Equal(t, ibc.RetiredReason, reason) +} + +func TestHistoricalIBCTraceRecordsHardFailure(t *testing.T) { + testApp := app.Setup(t, false, true, false) + recorder := &historicalTraceErrorRecorder{} + historicalCtx := pcommon.WithHistoricalTraceErrorRecorder( + testApp.NewContext(false, tmtypes.Header{}). + WithIsTracing(true). + WithClosestUpgradeName("v6.6"), + recorder, + ) + stateDB := state.NewDBImpl(historicalCtx, &testApp.EvmKeeper, true) + evm := &vm.EVM{StateDB: stateDB} + + precompile, err := ibc.NewPrecompile(testApp.GetPrecompileKeepers()) + require.NoError(t, err) + _, _, err = precompile.RunAndCalculateGas( + evm, + common.Address{}, + common.Address{}, + validCallData(t, precompile.GetABI()), + 1_000_000, + nil, + nil, + false, + false, + ) + require.ErrorIs(t, err, vm.ErrExecutionReverted) + var unavailable *pcommon.HistoricalTraceUnavailableError + require.ErrorAs(t, recorder.err, &unavailable) + + recorder.err = nil + stateDB.WithCtx(pcommon.WithHistoricalTraceErrorRecorder( + historicalCtx.WithClosestUpgradeName(ibc.RetirementUpgrade), + recorder, + )) + _, _, err = precompile.RunAndCalculateGas( + evm, + common.Address{}, + common.Address{}, + validCallData(t, precompile.GetABI()), + 1_000_000, + nil, + nil, + false, + false, + ) + require.ErrorIs(t, err, vm.ErrExecutionReverted) + require.NoError(t, recorder.err) +} + +func validCallData(t *testing.T, contractABI abi.ABI) []byte { + t.Helper() + + method := contractABI.Methods["transferWithDefaultTimeout"] + args := make([]interface{}, len(method.Inputs)) + for i, input := range method.Inputs { + switch input.Type.T { + case abi.StringTy: + args[i] = "" + case abi.UintTy: + if input.Type.Size == 256 { + args[i] = new(big.Int) + } else { + args[i] = uint64(0) } - }) + default: + t.Fatalf("unsupported ABI input type %s", input.Type.String()) + } } + + encoded, err := method.Inputs.Pack(args...) + require.NoError(t, err) + return append(method.ID, encoded...) } diff --git a/precompiles/ibc/legacy/v552/ibc.go b/precompiles/ibc/legacy/v552/ibc.go deleted file mode 100644 index b7bb3539d9..0000000000 --- a/precompiles/ibc/legacy/v552/ibc.go +++ /dev/null @@ -1,450 +0,0 @@ -package v552 - -import ( - "bytes" - "embed" - "errors" - "fmt" - "math/big" - - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - - "github.com/sei-protocol/sei-chain/sei-cosmos/types/bech32" - - putils "github.com/sei-protocol/sei-chain/precompiles/utils" - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/evm/state" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v552" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -var _ vm.PrecompiledContract = &Precompile{} -var _ vm.DynamicGasPrecompiledContract = &Precompile{} - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -func GetABI() abi.ABI { - abiBz, err := f.ReadFile("abi.json") - if err != nil { - panic(err) - } - - newAbi, err := abi.JSON(bytes.NewReader(abiBz)) - if err != nil { - panic(err) - } - return newAbi -} - -type Precompile struct { - pcommon.Precompile - address common.Address - transferKeeper putils.TransferKeeper - evmKeeper putils.EVMKeeper - clientKeeper putils.ClientKeeper - connectionKeeper putils.ConnectionKeeper - channelKeeper putils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers putils.Keepers) (*Precompile, error) { - newAbi := GetABI() - - p := &Precompile{ - Precompile: pcommon.Precompile{ABI: newAbi}, - address: common.HexToAddress(IBCAddress), - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return p, nil -} - -// RequiredGas returns the required bare minimum gas to execute the precompile. -func (p Precompile) RequiredGas(input []byte) uint64 { - methodID, err := pcommon.ExtractMethodID(input) - if err != nil { - return pcommon.UnknownMethodCallGas - } - - method, err := p.MethodById(methodID) - if err != nil { - // This should never happen since this method is going to fail during Run - return pcommon.UnknownMethodCallGas - } - - return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) -} - -func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, value *big.Int, _ *tracing.Hooks, readOnly bool, _ bool) (ret []byte, remainingGas uint64, err error) { - defer func() { - if err != nil { - state.GetDBImpl(evm.StateDB).SetPrecompileError(err) - } - }() - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - ctx, method, args, err := p.Prepare(evm, input) - if err != nil { - return nil, 0, err - } - if caller.Cmp(callingContract) != 0 { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - gasMultiplier := p.evmKeeper.GetPriorityNormalizer(ctx) - gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultiplier.TruncateInt().BigInt()) - if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { - gasLimitBigInt = utils.BigMaxU64 - } - ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, gasLimitBigInt.Uint64())) - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool, bool, *tracing.Hooks) (bz []byte, err error) { - panic("static gas Run is not implemented for dynamic gas precompile") -} - -func (p Precompile) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 8); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - err = p.transferKeeper.SendTransfer( - ctx, - validatedArgs.port, - validatedArgs.channelID, - coin, - validatedArgs.senderSeiAddr, - validatedArgs.receiverAddressString, - height, - timeoutTimestamp) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p Precompile) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 5); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - err = p.transferKeeper.SendTransfer( - ctx, - validatedArgs.port, - validatedArgs.channelID, - coin, - validatedArgs.senderSeiAddr, - validatedArgs.receiverAddressString, - height, - timeoutTimestamp) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (Precompile) IsTransaction(method string) bool { - switch method { - case TransferMethod: - return true - default: - return false - } -} - -func (p Precompile) Address() common.Address { - return p.address -} - -func (p Precompile) GetName() string { - return "ibc" -} - -func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) - } - return seiAddr, nil -} - -func (p Precompile) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p Precompile) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p Precompile) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p Precompile) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok { - return nil, errors.New("receiverAddress is not a string") - } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - return nil, err - } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} diff --git a/precompiles/ibc/legacy/v555/ibc.go b/precompiles/ibc/legacy/v555/ibc.go deleted file mode 100644 index 696a3ff6dc..0000000000 --- a/precompiles/ibc/legacy/v555/ibc.go +++ /dev/null @@ -1,481 +0,0 @@ -package v555 - -import ( - "bytes" - "embed" - "errors" - "fmt" - "math/big" - - putils "github.com/sei-protocol/sei-chain/precompiles/utils" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - - "github.com/sei-protocol/sei-chain/sei-cosmos/types/bech32" - - "github.com/sei-protocol/sei-chain/utils" - "github.com/sei-protocol/sei-chain/x/evm/state" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v555" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -var _ vm.PrecompiledContract = &Precompile{} -var _ vm.DynamicGasPrecompiledContract = &Precompile{} - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -func GetABI() abi.ABI { - abiBz, err := f.ReadFile("abi.json") - if err != nil { - panic(err) - } - - newAbi, err := abi.JSON(bytes.NewReader(abiBz)) - if err != nil { - panic(err) - } - return newAbi -} - -type Precompile struct { - pcommon.Precompile - address common.Address - transferKeeper putils.TransferKeeper - evmKeeper putils.EVMKeeper - clientKeeper putils.ClientKeeper - connectionKeeper putils.ConnectionKeeper - channelKeeper putils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers putils.Keepers) (*Precompile, error) { - newAbi := GetABI() - - p := &Precompile{ - Precompile: pcommon.Precompile{ABI: newAbi}, - address: common.HexToAddress(IBCAddress), - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return p, nil -} - -// RequiredGas returns the required bare minimum gas to execute the precompile. -func (p Precompile) RequiredGas(input []byte) uint64 { - methodID, err := pcommon.ExtractMethodID(input) - if err != nil { - return pcommon.UnknownMethodCallGas - } - - method, err := p.MethodById(methodID) - if err != nil { - // This should never happen since this method is going to fail during Run - return pcommon.UnknownMethodCallGas - } - - return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name)) -} - -func (p Precompile) RunAndCalculateGas(evm *vm.EVM, caller common.Address, callingContract common.Address, input []byte, suppliedGas uint64, _ *big.Int, _ *tracing.Hooks, readOnly bool, _ bool) (ret []byte, remainingGas uint64, err error) { - defer func() { - if err != nil { - state.GetDBImpl(evm.StateDB).SetPrecompileError(err) - } - }() - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - ctx, method, args, err := p.Prepare(evm, input) - if err != nil { - return nil, 0, err - } - if caller.Cmp(callingContract) != 0 { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - gasMultiplier := p.evmKeeper.GetPriorityNormalizer(ctx) - gasLimitBigInt := new(big.Int).Mul(new(big.Int).SetUint64(suppliedGas), gasMultiplier.TruncateInt().BigInt()) - if gasLimitBigInt.Cmp(utils.BigMaxU64) > 0 { - gasLimitBigInt = utils.BigMaxU64 - } - ctx = ctx.WithGasMeter(sdk.NewGasMeterWithMultiplier(ctx, gasLimitBigInt.Uint64())) - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p Precompile) Run(*vm.EVM, common.Address, common.Address, []byte, *big.Int, bool, bool, *tracing.Hooks) (bz []byte, err error) { - panic("static gas Run is not implemented for dynamic gas precompile") -} - -func (p Precompile) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p Precompile) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (Precompile) IsTransaction(method string) bool { - switch method { - case TransferMethod: - return true - case TransferWithDefaultTimeoutMethod: - return true - default: - return false - } -} - -func (p Precompile) Address() common.Address { - return p.address -} - -func (p Precompile) GetName() string { - return "ibc" -} - -func (p Precompile) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, fmt.Errorf("EVM address %s is not associated", addr.Hex()) - } - return seiAddr, nil -} - -func (p Precompile) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p Precompile) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p Precompile) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p Precompile) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok { - return nil, errors.New("receiverAddress is not a string") - } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - return nil, err - } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v562/ibc.go b/precompiles/ibc/legacy/v562/ibc.go deleted file mode 100644 index 698059cb7b..0000000000 --- a/precompiles/ibc/legacy/v562/ibc.go +++ /dev/null @@ -1,420 +0,0 @@ -package v562 - -import ( - "bytes" - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - putils "github.com/sei-protocol/sei-chain/precompiles/utils" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-cosmos/types/bech32" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v562" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -func GetABI() abi.ABI { - abiBz, err := f.ReadFile("abi.json") - if err != nil { - panic(err) - } - - newAbi, err := abi.JSON(bytes.NewReader(abiBz)) - if err != nil { - panic(err) - } - return newAbi -} - -type PrecompileExecutor struct { - transferKeeper putils.TransferKeeper - evmKeeper putils.EVMKeeper - clientKeeper putils.ClientKeeper - connectionKeeper putils.ConnectionKeeper - channelKeeper putils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers putils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := GetABI() - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, hooks *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if caller.Cmp(callingContract) != 0 { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() putils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok { - return nil, errors.New("receiverAddress is not a string") - } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - return nil, err - } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v580/ibc.go b/precompiles/ibc/legacy/v580/ibc.go deleted file mode 100644 index 2c57648404..0000000000 --- a/precompiles/ibc/legacy/v580/ibc.go +++ /dev/null @@ -1,406 +0,0 @@ -package v580 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-cosmos/types/bech32" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v580" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, hooks *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if caller.Cmp(callingContract) != 0 { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok { - return nil, errors.New("receiverAddress is not a string") - } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - return nil, err - } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v601/ibc.go b/precompiles/ibc/legacy/v601/ibc.go deleted file mode 100644 index 2409bed68b..0000000000 --- a/precompiles/ibc/legacy/v601/ibc.go +++ /dev/null @@ -1,406 +0,0 @@ -package v601 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-cosmos/types/bech32" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v66" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok { - return nil, errors.New("receiverAddress is not a string") - } - _, bz, err := bech32.DecodeAndConvert(receiverAddressString) - if err != nil { - return nil, err - } - err = sdk.VerifyAddressFormat(bz) - if err != nil { - return nil, err - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v603/ibc.go b/precompiles/ibc/legacy/v603/ibc.go deleted file mode 100644 index 4bf2d17e52..0000000000 --- a/precompiles/ibc/legacy/v603/ibc.go +++ /dev/null @@ -1,397 +0,0 @@ -package v603 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v66" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v605/ibc.go b/precompiles/ibc/legacy/v605/ibc.go deleted file mode 100644 index 8fdfe973d0..0000000000 --- a/precompiles/ibc/legacy/v605/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v605 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v605" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v606/ibc.go b/precompiles/ibc/legacy/v606/ibc.go deleted file mode 100644 index b76057374b..0000000000 --- a/precompiles/ibc/legacy/v606/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v606 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v606" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v610/ibc.go b/precompiles/ibc/legacy/v610/ibc.go deleted file mode 100644 index d0e571f8e7..0000000000 --- a/precompiles/ibc/legacy/v610/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v610 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v606" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v614/ibc.go b/precompiles/ibc/legacy/v614/ibc.go deleted file mode 100644 index 97e76b3719..0000000000 --- a/precompiles/ibc/legacy/v614/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v614 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v614" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v620/ibc.go b/precompiles/ibc/legacy/v620/ibc.go deleted file mode 100644 index 830b15c57e..0000000000 --- a/precompiles/ibc/legacy/v620/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v620 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v620" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v630/ibc.go b/precompiles/ibc/legacy/v630/ibc.go deleted file mode 100644 index 33cee9208a..0000000000 --- a/precompiles/ibc/legacy/v630/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v630 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v630" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v640/ibc.go b/precompiles/ibc/legacy/v640/ibc.go deleted file mode 100644 index 77597bd1e1..0000000000 --- a/precompiles/ibc/legacy/v640/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v640 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v640" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v65/ibc.go b/precompiles/ibc/legacy/v65/ibc.go deleted file mode 100644 index a2db1705b5..0000000000 --- a/precompiles/ibc/legacy/v65/ibc.go +++ /dev/null @@ -1,401 +0,0 @@ -package v65 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v65" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/legacy/v66/ibc.go b/precompiles/ibc/legacy/v66/ibc.go deleted file mode 100644 index 2d705225ce..0000000000 --- a/precompiles/ibc/legacy/v66/ibc.go +++ /dev/null @@ -1,403 +0,0 @@ -// Code generated by scripts/bump_version; DO NOT EDIT. - -package v66 - -import ( - "embed" - "errors" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/tracing" - "github.com/ethereum/go-ethereum/core/vm" - sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - - pcommon "github.com/sei-protocol/sei-chain/precompiles/common/legacy/v66" - "github.com/sei-protocol/sei-chain/precompiles/utils" - evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" -) - -const ( - TransferMethod = "transfer" - TransferWithDefaultTimeoutMethod = "transferWithDefaultTimeout" -) - -const ( - IBCAddress = "0x0000000000000000000000000000000000001009" -) - -// Embed abi json file to the executable binary. Needed when importing as dependency. -// -//go:embed abi.json -var f embed.FS - -type PrecompileExecutor struct { - transferKeeper utils.TransferKeeper - evmKeeper utils.EVMKeeper - clientKeeper utils.ClientKeeper - connectionKeeper utils.ConnectionKeeper - channelKeeper utils.ChannelKeeper - - TransferID []byte - TransferWithDefaultTimeoutID []byte -} - -func NewPrecompile(keepers utils.Keepers) (*pcommon.DynamicGasPrecompile, error) { - newAbi := pcommon.MustGetABI(f, "abi.json") - - p := &PrecompileExecutor{ - transferKeeper: keepers.TransferK(), - evmKeeper: keepers.EVMK(), - clientKeeper: keepers.ClientK(), - connectionKeeper: keepers.ConnectionK(), - channelKeeper: keepers.ChannelK(), - } - - for name, m := range newAbi.Methods { - switch name { - case TransferMethod: - p.TransferID = m.ID - case TransferWithDefaultTimeoutMethod: - p.TransferWithDefaultTimeoutID = m.ID - } - } - - return pcommon.NewDynamicGasPrecompile(newAbi, p, common.HexToAddress(IBCAddress), "ibc"), nil -} - -func (p PrecompileExecutor) Execute(ctx sdk.Context, method *abi.Method, caller common.Address, callingContract common.Address, args []interface{}, value *big.Int, readOnly bool, evm *vm.EVM, suppliedGas uint64, _ *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { - if err = pcommon.ValidateNonPayable(value); err != nil { - return nil, 0, err - } - - if readOnly { - return nil, 0, errors.New("cannot call IBC precompile from staticcall") - } - if ctx.EVMPrecompileCalledFromDelegateCall() { - return nil, 0, errors.New("cannot delegatecall IBC") - } - - switch method.Name { - case TransferMethod: - return p.transfer(ctx, method, args, caller) - case TransferWithDefaultTimeoutMethod: - return p.transferWithDefaultTimeout(ctx, method, args, caller) - } - return -} - -func (p PrecompileExecutor) EVMKeeper() utils.EVMKeeper { - return p.evmKeeper -} - -func (p PrecompileExecutor) transfer(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 9); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - revisionNumber, ok := args[5].(uint64) - if !ok { - rerr = errors.New("revisionNumber is not a uint64") - return - } - - revisionHeight, ok := args[6].(uint64) - if !ok { - rerr = errors.New("revisionHeight is not a uint64") - return - } - - height := clienttypes.Height{ - RevisionNumber: revisionNumber, - RevisionHeight: revisionHeight, - } - - timeoutTimestamp, ok := args[7].(uint64) - if !ok { - rerr = errors.New("timeoutTimestamp is not a uint64") - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[8], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) transferWithDefaultTimeout(ctx sdk.Context, method *abi.Method, args []interface{}, caller common.Address) (ret []byte, remainingGas uint64, rerr error) { - defer func() { - if err := recover(); err != nil { - ret = nil - remainingGas = 0 - rerr = fmt.Errorf("%s", err) - return - } - }() - - if err := pcommon.ValidateArgsLength(args, 6); err != nil { - rerr = err - return - } - validatedArgs, err := p.validateCommonArgs(ctx, args, caller) - if err != nil { - rerr = err - return - } - - if validatedArgs.amount.Cmp(big.NewInt(0)) == 0 { - // short circuit - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return - } - - coin := sdk.Coin{ - Denom: validatedArgs.denom, - Amount: sdk.NewIntFromBigInt(validatedArgs.amount), - } - - connection, err := p.getChannelConnection(ctx, validatedArgs.port, validatedArgs.channelID) - - if err != nil { - rerr = err - return - } - - latestConsensusHeight, err := p.getConsensusLatestHeight(ctx, *connection) - if err != nil { - rerr = err - return - } - - height, err := GetAdjustedHeight(*latestConsensusHeight) - if err != nil { - rerr = err - return - } - - timeoutTimestamp, err := p.GetAdjustedTimestamp(ctx, connection.ClientId, *latestConsensusHeight) - if err != nil { - rerr = err - return - } - - msg := types.MsgTransfer{ - SourcePort: validatedArgs.port, - SourceChannel: validatedArgs.channelID, - Token: coin, - Sender: validatedArgs.senderSeiAddr.String(), - Receiver: validatedArgs.receiverAddressString, - TimeoutHeight: height, - TimeoutTimestamp: timeoutTimestamp, - } - - msg = addMemo(args[5], msg) - - err = msg.ValidateBasic() - if err != nil { - rerr = err - return - } - - _, err = p.transferKeeper.Transfer(sdk.WrapSDKContext(ctx), &msg) - - if err != nil { - rerr = err - return - } - remainingGas = pcommon.GetRemainingGas(ctx, p.evmKeeper) - ret, rerr = method.Outputs.Pack(true) - return -} - -func (p PrecompileExecutor) accAddressFromArg(ctx sdk.Context, arg interface{}) (sdk.AccAddress, error) { - addr := arg.(common.Address) - if addr == (common.Address{}) { - return nil, errors.New("invalid addr") - } - seiAddr, found := p.evmKeeper.GetSeiAddress(ctx, addr) - if !found { - return nil, evmtypes.NewAssociationMissingErr(addr.Hex()) - } - return seiAddr, nil -} - -func (p PrecompileExecutor) getChannelConnection(ctx sdk.Context, port string, channelID string) (*connectiontypes.ConnectionEnd, error) { - channel, found := p.channelKeeper.GetChannel(ctx, port, channelID) - if !found { - return nil, errors.New("channel not found") - } - - connection, found := p.connectionKeeper.GetConnection(ctx, channel.ConnectionHops[0]) - - if !found { - return nil, errors.New("connection not found") - } - return &connection, nil -} - -func (p PrecompileExecutor) getConsensusLatestHeight(ctx sdk.Context, connection connectiontypes.ConnectionEnd) (*clienttypes.Height, error) { - clientState, found := p.clientKeeper.GetClientState(ctx, connection.ClientId) - - if !found { - return nil, errors.New("could not get the client state") - } - - latestHeight := clientState.GetLatestHeight() - return &clienttypes.Height{ - RevisionNumber: latestHeight.GetRevisionNumber(), - RevisionHeight: latestHeight.GetRevisionHeight(), - }, nil -} - -func GetAdjustedHeight(latestConsensusHeight clienttypes.Height) (clienttypes.Height, error) { - defaultTimeoutHeight, err := clienttypes.ParseHeight(types.DefaultRelativePacketTimeoutHeight) - if err != nil { - return clienttypes.Height{}, err - } - - absoluteHeight := latestConsensusHeight - absoluteHeight.RevisionNumber += defaultTimeoutHeight.RevisionNumber - absoluteHeight.RevisionHeight += defaultTimeoutHeight.RevisionHeight - return absoluteHeight, nil -} - -func (p PrecompileExecutor) GetAdjustedTimestamp(ctx sdk.Context, clientId string, height clienttypes.Height) (uint64, error) { - consensusState, found := p.clientKeeper.GetClientConsensusState(ctx, clientId, height) - var consensusStateTimestamp uint64 - if found { - consensusStateTimestamp = consensusState.GetTimestamp() - } - - defaultRelativePacketTimeoutTimestamp := types.DefaultRelativePacketTimeoutTimestamp - blockTime := ctx.BlockTime().UnixNano() - if blockTime > 0 { - now := uint64(blockTime) - if now > consensusStateTimestamp { - return now + defaultRelativePacketTimeoutTimestamp, nil - } else { - return consensusStateTimestamp + defaultRelativePacketTimeoutTimestamp, nil - } - } else { - return 0, errors.New("block time is not greater than Jan 1st, 1970 12:00 AM") - } -} - -type ValidatedArgs struct { - senderSeiAddr sdk.AccAddress - receiverAddressString string - port string - channelID string - denom string - amount *big.Int -} - -func (p PrecompileExecutor) validateCommonArgs(ctx sdk.Context, args []interface{}, caller common.Address) (*ValidatedArgs, error) { - senderSeiAddr, ok := p.evmKeeper.GetSeiAddress(ctx, caller) - if !ok { - return nil, errors.New("caller is not a valid SEI address") - } - - receiverAddressString, ok := args[0].(string) - if !ok || receiverAddressString == "" { - return nil, errors.New("receiverAddress is not a string or empty") - } - - port, ok := args[1].(string) - if !ok { - return nil, errors.New("port is not a string") - } - if port == "" { - return nil, errors.New("port cannot be empty") - } - - channelID, ok := args[2].(string) - if !ok { - return nil, errors.New("channelID is not a string") - } - if channelID == "" { - return nil, errors.New("channelID cannot be empty") - } - - denom := args[3].(string) - if denom == "" { - return nil, errors.New("invalid denom") - } - - amount, ok := args[4].(*big.Int) - if !ok { - return nil, errors.New("amount is not a big.Int") - } - return &ValidatedArgs{ - senderSeiAddr: senderSeiAddr, - receiverAddressString: receiverAddressString, - port: port, - channelID: channelID, - denom: denom, - amount: amount, - }, nil -} - -func addMemo(memoArg interface{}, transferMsg types.MsgTransfer) types.MsgTransfer { - memo := "" - if memoArg != nil { - memo = memoArg.(string) - } - transferMsg.Memo = memo - return transferMsg -} diff --git a/precompiles/ibc/retired b/precompiles/ibc/retired new file mode 100644 index 0000000000..4c9328dbb9 --- /dev/null +++ b/precompiles/ibc/retired @@ -0,0 +1 @@ +This marker keeps scripts/bump_version from archiving or regenerating this retired precompile. diff --git a/precompiles/ibc/setup.go b/precompiles/ibc/setup.go index eb7963fb89..dd349247e5 100644 --- a/precompiles/ibc/setup.go +++ b/precompiles/ibc/setup.go @@ -1,49 +1,36 @@ -// Code generated by scripts/bump_version; DO NOT EDIT. - package ibc import ( - "github.com/ethereum/go-ethereum/core/vm" - ibcv552 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v552" - ibcv555 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v555" - ibcv562 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v562" - ibcv580 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v580" - ibcv601 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v601" - ibcv603 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v603" - ibcv605 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v605" - ibcv606 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v606" - ibcv610 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v610" - ibcv614 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v614" - ibcv620 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v620" - ibcv630 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v630" - ibcv640 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v640" - ibcv65 "github.com/sei-protocol/sei-chain/precompiles/ibc/legacy/v65" + "embed" + "strings" + + pcommon "github.com/sei-protocol/sei-chain/precompiles/common" "github.com/sei-protocol/sei-chain/precompiles/utils" ) +// The retired precompile still uses the ABI active at the traced height so +// historical method selectors are decoded before returning the retirement reason. +// The versions manifest is frozen with the module and remains the source of truth +// for every ABI that must be available after future upgrades. +// +//go:embed versions legacy/*/abi.json +var retiredAssets embed.FS + func GetVersioned(latestUpgrade string, keepers utils.Keepers) utils.VersionedPrecompiles { - return utils.VersionedPrecompiles{ - latestUpgrade: check(NewPrecompile(keepers)), - "v5.5.2": check(ibcv552.NewPrecompile(keepers)), - "v5.5.5": check(ibcv555.NewPrecompile(keepers)), - "v5.6.2": check(ibcv562.NewPrecompile(keepers)), - "v5.8.0": check(ibcv580.NewPrecompile(keepers)), - "v6.0.1": check(ibcv601.NewPrecompile(keepers)), - "v6.0.3": check(ibcv603.NewPrecompile(keepers)), - "v6.0.5": check(ibcv605.NewPrecompile(keepers)), - "v6.0.6": check(ibcv606.NewPrecompile(keepers)), - "v6.1.0": check(ibcv610.NewPrecompile(keepers)), - "v6.1.4": check(ibcv614.NewPrecompile(keepers)), - "v6.2.0": check(ibcv620.NewPrecompile(keepers)), - "v6.3.0": check(ibcv630.NewPrecompile(keepers)), - "v6.4.0": check(ibcv640.NewPrecompile(keepers)), - "v6.5": check(ibcv65.NewPrecompile(keepers)), + historicalVersions := getHistoricalVersions() + versioned := make(utils.VersionedPrecompiles, len(historicalVersions)+1) + for _, version := range historicalVersions { + filename := "legacy/" + strings.ReplaceAll(version, ".", "") + "/abi.json" + versioned[version] = newRetiredPrecompile(pcommon.MustGetABI(retiredAssets, filename), keepers) } + versioned[latestUpgrade] = newRetiredPrecompile(pcommon.MustGetABI(currentABI, "abi.json"), keepers) + return versioned } -func check(p vm.PrecompiledContract, err error) vm.PrecompiledContract { +func getHistoricalVersions() []string { + manifest, err := retiredAssets.ReadFile("versions") if err != nil { panic(err) } - return p + return strings.Fields(string(manifest)) } diff --git a/precompiles/utils/expected_keepers.go b/precompiles/utils/expected_keepers.go index ab0581c70e..3934b58f2d 100644 --- a/precompiles/utils/expected_keepers.go +++ b/precompiles/utils/expected_keepers.go @@ -4,10 +4,6 @@ import ( "context" "math/big" - connectiontypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/03-connection/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/04-channel/types" - "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/exported" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" "github.com/sei-protocol/sei-chain/sei-cosmos/client" @@ -24,8 +20,6 @@ import ( slashingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/slashing/types" stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types" upgradetypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/types" - ibctypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - clienttypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/02-client/types" "github.com/sei-protocol/sei-chain/utils" minttypes "github.com/sei-protocol/sei-chain/x/mint/types" oracletypes "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -57,10 +51,6 @@ type Keepers interface { SlashingMS() SlashingMsgServer SlashingQ() SlashingQuerier UpgradeQ() UpgradeQuerier - TransferK() TransferKeeper - ClientK() ClientKeeper - ConnectionK() ConnectionKeeper - ChannelK() ChannelKeeper TxConfig() client.TxConfig Codec() codec.Codec } @@ -94,10 +84,6 @@ func (ek *EmptyKeepers) ParamsQ() ParamsQuerier { return nil } func (ek *EmptyKeepers) SlashingMS() SlashingMsgServer { return nil } func (ek *EmptyKeepers) SlashingQ() SlashingQuerier { return nil } func (ek *EmptyKeepers) UpgradeQ() UpgradeQuerier { return nil } -func (ek *EmptyKeepers) TransferK() TransferKeeper { return nil } -func (ek *EmptyKeepers) ClientK() ClientKeeper { return nil } -func (ek *EmptyKeepers) ConnectionK() ConnectionKeeper { return nil } -func (ek *EmptyKeepers) ChannelK() ChannelKeeper { return nil } func (ek *EmptyKeepers) TxConfig() client.TxConfig { return nil } func (ek *EmptyKeepers) Codec() codec.Codec { return nil } @@ -232,33 +218,6 @@ type DistributionKeeper interface { DelegationTotalRewards(c context.Context, req *distrtypes.QueryDelegationTotalRewardsRequest) (*distrtypes.QueryDelegationTotalRewardsResponse, error) } -type TransferKeeper interface { - Transfer(goCtx context.Context, msg *ibctypes.MsgTransfer) (*ibctypes.MsgTransferResponse, error) - SendTransfer( - ctx sdk.Context, - sourcePort, - sourceChannel string, - token sdk.Coin, - sender sdk.AccAddress, - receiver string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - ) error -} - -type ClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) -} - -type ConnectionKeeper interface { - GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) -} - -type ChannelKeeper interface { - GetChannel(ctx sdk.Context, portID, channelID string) (types.Channel, bool) -} - type BankQuerier interface { SpendableBalances(ctx context.Context, req *banktypes.QuerySpendableBalancesRequest) (*banktypes.QuerySpendableBalancesResponse, error) TotalSupply(ctx context.Context, req *banktypes.QueryTotalSupplyRequest) (*banktypes.QueryTotalSupplyResponse, error) diff --git a/scripts/bump_version/README.md b/scripts/bump_version/README.md index 009fc27735..0650a6128c 100644 --- a/scripts/bump_version/README.md +++ b/scripts/bump_version/README.md @@ -10,6 +10,10 @@ When a new upgrade version is added to `app/tags`, this tool: 2. Archives their current code into `precompiles//legacy//` 3. Regenerates all `precompiles//setup.go` files from the `versions` files +Modules containing a `retired` marker file are excluded from archival and setup +generation. Their historical version mapping is maintained by the module so a +future upgrade cannot archive or reactivate retired code. + It replaces the old `scripts/bump-version.sh` shell script. ## Developer workflow diff --git a/scripts/bump_version/main.go b/scripts/bump_version/main.go index bcd5251fe0..36628f322d 100644 --- a/scripts/bump_version/main.go +++ b/scripts/bump_version/main.go @@ -46,6 +46,7 @@ const ( tagFile = "app/tags" precompilesDir = "precompiles" commonDir = "precompiles/common" + retiredMarker = "retired" modulePath = "github.com/sei-protocol/sei-chain" commonPkgPath = modulePath + "/precompiles/common" generatedHdr = "// Code generated by scripts/bump_version; DO NOT EDIT." @@ -380,6 +381,9 @@ func regenerateAllSetup() error { moduleName := entry.Name() moduleDir := filepath.Join(precompilesDir, moduleName) + if fileExists(filepath.Join(moduleDir, retiredMarker)) { + continue + } versionsFile := filepath.Join(moduleDir, "versions") if _, err := os.Stat(versionsFile); os.IsNotExist(err) { @@ -515,6 +519,11 @@ func dirExists(path string) bool { return err == nil && info.IsDir() } +func fileExists(path string) bool { + info, err := os.Stat(path) + return err == nil && !info.IsDir() +} + func discoverModules() []string { entries, err := os.ReadDir(precompilesDir) if err != nil { @@ -522,7 +531,7 @@ func discoverModules() []string { } var modules []string for _, e := range entries { - if e.IsDir() && !excludeDirs[e.Name()] { + if e.IsDir() && !excludeDirs[e.Name()] && !fileExists(filepath.Join(precompilesDir, e.Name(), retiredMarker)) { modules = append(modules, e.Name()) } } diff --git a/tools/utils/helper.go b/tools/utils/helper.go index a2af58ecee..c4bdc2e476 100644 --- a/tools/utils/helper.go +++ b/tools/utils/helper.go @@ -16,8 +16,6 @@ import ( slashingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/slashing/types" stakingtypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/staking/types" upgradetypes "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/types" - ibctransfertypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types" - ibchost "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/core/24-host" "github.com/sei-protocol/sei-chain/sei-wasmd/x/wasm" epochmoduletypes "github.com/sei-protocol/sei-chain/x/epoch/types" evmtypes "github.com/sei-protocol/sei-chain/x/evm/types" @@ -29,8 +27,8 @@ import ( var ModuleKeys = sdk.NewKVStoreKeys( authtypes.StoreKey, authzkeeper.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, paramstypes.StoreKey, ibchost.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, - evidencetypes.StoreKey, ibctransfertypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, + govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + evidencetypes.StoreKey, capabilitytypes.StoreKey, oracletypes.StoreKey, evmtypes.StoreKey, wasm.StoreKey, epochmoduletypes.StoreKey, tokenfactorytypes.StoreKey, ) @@ -45,14 +43,12 @@ var Modules = []string{ "evm", "feegrant", "gov", - "ibc", "mint", "oracle", "params", "slashing", "staking", "tokenfactory", - "transfer", "upgrade", "wasm"} diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index a7371299ee..e1c9ad94bf 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -31,7 +31,6 @@ import ( upgradekeeper "github.com/sei-protocol/sei-chain/sei-cosmos/x/upgrade/keeper" receipt "github.com/sei-protocol/sei-chain/sei-db/ledger_db/receipt" sctypes "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/types" - ibctransferkeeper "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/keeper" abci "github.com/sei-protocol/sei-chain/sei-tendermint/abci/types" tmtypes "github.com/sei-protocol/sei-chain/sei-tendermint/types" wasmkeeper "github.com/sei-protocol/sei-chain/sei-wasmd/x/wasm/keeper" @@ -60,7 +59,6 @@ type Keeper struct { bankKeeper bankkeeper.Keeper accountKeeper *authkeeper.AccountKeeper stakingKeeper *stakingkeeper.Keeper - transferKeeper ibctransferkeeper.Keeper wasmKeeper *wasmkeeper.PermissionedKeeper wasmViewKeeper *wasmkeeper.Keeper upgradeKeeper *upgradekeeper.Keeper @@ -132,7 +130,7 @@ func (ctx *ReplayChainContext) Config() *params.ChainConfig { func NewKeeper( storeKey sdk.StoreKey, transientStoreKey sdk.StoreKey, paramstore paramtypes.Subspace, receiptStore receipt.ReceiptStore, bankKeeper bankkeeper.Keeper, accountKeeper *authkeeper.AccountKeeper, stakingKeeper *stakingkeeper.Keeper, - transferKeeper ibctransferkeeper.Keeper, wasmKeeper *wasmkeeper.PermissionedKeeper, wasmViewKeeper *wasmkeeper.Keeper, upgradeKeeper *upgradekeeper.Keeper) *Keeper { + wasmKeeper *wasmkeeper.PermissionedKeeper, wasmViewKeeper *wasmkeeper.Keeper, upgradeKeeper *upgradekeeper.Keeper) *Keeper { if !paramstore.HasKeyTable() { paramstore = paramstore.WithKeyTable(types.ParamKeyTable()) @@ -144,7 +142,6 @@ func NewKeeper( bankKeeper: bankKeeper, accountKeeper: accountKeeper, stakingKeeper: stakingKeeper, - transferKeeper: transferKeeper, wasmKeeper: wasmKeeper, wasmViewKeeper: wasmViewKeeper, upgradeKeeper: upgradeKeeper,