-
Notifications
You must be signed in to change notification settings - Fork 834
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(stride): Add Run function, Precompile struct and transaction def…
…initions (#1913) * feat(stride): Stride Outpost interface and abi. * feat(stride): Add Run function and transaction definitions * fix: add license
- Loading branch information
1 parent
24c1442
commit 6201def
Showing
2 changed files
with
191 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |