Skip to content

Commit

Permalink
feat(stride): Add Run function, Precompile struct and transaction def…
Browse files Browse the repository at this point in the history
…initions (#1913)

* feat(stride): Stride Outpost interface and abi.

* feat(stride): Add Run function and transaction definitions

* fix: add license
  • Loading branch information
Vvaradinov committed Oct 19, 2023
1 parent 24c1442 commit 6201def
Show file tree
Hide file tree
Showing 2 changed files with 191 additions and 0 deletions.
142 changes: 142 additions & 0 deletions precompiles/outposts/stride/stride.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE)

package stride

import (
"bytes"
"embed"
"fmt"

storetypes "github.com/cosmos/cosmos-sdk/store/types"
authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
cmn "github.com/evmos/evmos/v15/precompiles/common"
erc20keeper "github.com/evmos/evmos/v15/x/erc20/keeper"
transferkeeper "github.com/evmos/evmos/v15/x/ibc/transfer/keeper"
)

var _ vm.PrecompiledContract = &Precompile{}

// Embed abi json file to the executable binary. Needed when importing as dependency.
//
//go:embed abi.json
var f embed.FS

type Precompile struct {
cmn.Precompile
portID string
channelID string
timeoutHeight clienttypes.Height
transferKeeper transferkeeper.Keeper
erc20Keeper erc20keeper.Keeper
stakingKeeper stakingkeeper.Keeper
}

// NewPrecompile creates a new staking Precompile instance as a
// PrecompiledContract interface.
func NewPrecompile(
portID, channelID string,
transferKeeper transferkeeper.Keeper,
erc20Keeper erc20keeper.Keeper,
authzKeeper authzkeeper.Keeper,
stakingKeeper stakingkeeper.Keeper,
) (*Precompile, error) {
abiBz, err := f.ReadFile("abi.json")
if err != nil {
return nil, err
}

newAbi, err := abi.JSON(bytes.NewReader(abiBz))
if err != nil {
return nil, err
}

return &Precompile{
Precompile: cmn.Precompile{
ABI: newAbi,
AuthzKeeper: authzKeeper,
KvGasConfig: storetypes.KVGasConfig(),
TransientKVGasConfig: storetypes.TransientGasConfig(),
ApprovalExpiration: cmn.DefaultExpirationDuration, // should be configurable in the future.
},
portID: portID,
channelID: channelID,
timeoutHeight: clienttypes.NewHeight(100, 100),
transferKeeper: transferKeeper,
erc20Keeper: erc20Keeper,
stakingKeeper: stakingKeeper,
}, nil
}

// Address defines the address of the Stride Outpost precompile contract.
func (Precompile) Address() common.Address {
return common.HexToAddress("0x0000000000000000000000000000000000000900")
}

// IsStateful returns true since the precompile contract has access to the
// chain state.
func (Precompile) IsStateful() bool {
return true
}

// RequiredGas calculates the precompiled contract's base gas rate.
func (p Precompile) RequiredGas(input []byte) uint64 {
methodID := input[:4]

method, err := p.MethodById(methodID)
if err != nil {
// This should never happen since this method is going to fail during Run
return 0
}

return p.Precompile.RequiredGas(input, p.IsTransaction(method.Name))
}

// Run executes the precompiled contract IBC transfer methods defined in the ABI.
func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz []byte, err error) {
ctx, stateDB, method, initialGas, args, err := p.RunSetup(evm, contract, readOnly, p.IsTransaction)
if err != nil {
return nil, err
}

// This handles any out of gas errors that may occur during the execution of a precompile tx or query.
// It avoids panics and returns the out of gas error so the EVM can continue gracefully.
defer cmn.HandleGasError(ctx, contract, initialGas, &err)()

switch method.Name {
// Stride Outpost Methods:
case LiquidStakeMethod:
bz, err = p.LiquidStake(ctx, evm.Origin, stateDB, contract, method, args)
case RedeemMethod:
bz, err = p.Redeem(ctx, evm.Origin, stateDB, contract, method, args)
default:
return nil, fmt.Errorf(cmn.ErrUnknownMethod, method.Name)
}

if err != nil {
return nil, err
}

cost := ctx.GasMeter().GasConsumed() - initialGas

if !contract.UseGas(cost) {
return nil, vm.ErrOutOfGas
}

return bz, nil
}

// IsTransaction checks if the given method name corresponds to a transaction or query.
func (Precompile) IsTransaction(method string) bool {
switch method {
case LiquidStakeMethod, RedeemMethod:
return true
default:
return false
}
}
49 changes: 49 additions & 0 deletions precompiles/outposts/stride/tx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright Tharsis Labs Ltd.(Evmos)
// SPDX-License-Identifier:ENCL-1.0(https://github.com/evmos/evmos/blob/main/LICENSE)

package stride

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
)

const (
// LiquidStakeMethod is the name of the liquidStake method
LiquidStakeMethod = "liquidStake"
// RedeemMethod is the name of the redeem method
RedeemMethod = "redeem"
// LiquidStakeAction is the action name needed in the memo field
LiquidStakeAction = "LiquidStake"
// RedeemAction is the action name needed in the memo field
RedeemAction = "Redeem"
)

// LiquidStake is a transaction that liquid stakes tokens using
// a ICS20 transfer with a custom memo field that will trigger Stride's Autopilot middleware
func (p Precompile) LiquidStake(
_ sdk.Context,
_ common.Address,
_ vm.StateDB,
_ *vm.Contract,
_ *abi.Method,
_ []interface{},
) ([]byte, error) {
return nil, nil
}

// Redeem is a transaction that redeems the native tokens using the liquid stake
// tokens. It executes a ICS20 transfer with a custom memo field that will
// trigger Stride's Autopilot middleware
func (p Precompile) Redeem(
_ sdk.Context,
_ common.Address,
_ vm.StateDB,
_ *vm.Contract,
_ *abi.Method,
_ []interface{},
) ([]byte, error) {
return nil, nil
}

0 comments on commit 6201def

Please sign in to comment.