diff --git a/go.mod b/go.mod index 0073b362bd..06483f8877 100644 --- a/go.mod +++ b/go.mod @@ -125,7 +125,6 @@ require ( github.com/fzipp/gocyclo v0.5.1 // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect - github.com/ghodss/yaml v1.0.0 // indirect github.com/go-critic/go-critic v0.6.3 // indirect github.com/go-kit/kit v0.12.0 // indirect github.com/go-kit/log v0.2.1 // indirect @@ -173,7 +172,6 @@ require ( github.com/gostaticanalysis/nilerr v0.1.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect @@ -348,7 +346,7 @@ require ( replace ( github.com/CosmWasm/wasmd => github.com/sei-protocol/sei-wasmd v0.0.7 github.com/confio/ics23/go => github.com/cosmos/cosmos-sdk/ics23/go v0.8.0 - github.com/cosmos/cosmos-sdk => github.com/sei-protocol/sei-cosmos v0.2.73-evm-rebase-8 + github.com/cosmos/cosmos-sdk => github.com/kyriediculous/sei-cosmos v0.0.0-20240322222612-9e2a3f019263 github.com/cosmos/iavl => github.com/sei-protocol/sei-iavl v0.1.9 github.com/cosmos/ibc-go/v3 => github.com/sei-protocol/sei-ibc-go/v3 v3.3.0 github.com/ethereum/go-ethereum => github.com/sei-protocol/go-ethereum v1.13.5-sei-8 diff --git a/go.sum b/go.sum index 2e8718fe8e..a89987c008 100644 --- a/go.sum +++ b/go.sum @@ -457,7 +457,6 @@ github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 h1:BAIP2Gihuqh github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46/go.mod h1:QNpY22eby74jVhqH4WhDLDwxc/vqsern6pW+u2kbkpc= github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -765,8 +764,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/guptarohit/asciigraph v0.5.5/go.mod h1:dYl5wwK4gNsnFf9Zp+l06rFiDZ5YtXM6x7SRWZ3KGag= @@ -956,6 +953,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M= github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg= +github.com/kyriediculous/sei-cosmos v0.0.0-20240322222612-9e2a3f019263 h1:iTSOaJ2/s+6JDpEl+3QhFWzgFlvF0IoT2ZiNHtuo2fA= +github.com/kyriediculous/sei-cosmos v0.0.0-20240322222612-9e2a3f019263/go.mod h1:9lxLcKzSw+dWguFY8JkE04O1OlEjKxHsuP5zK/pS8q0= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= @@ -1349,8 +1348,6 @@ github.com/sei-protocol/go-ethereum v1.13.5-sei-8 h1:z6rUvSgLXtXQBdF1dOe8A1iDFOR github.com/sei-protocol/go-ethereum v1.13.5-sei-8/go.mod h1:kcRZmuzRn1lVejiFNTz4l4W7imnpq1bDAnuKS/RyhbQ= github.com/sei-protocol/goutils v0.0.2 h1:Bfa7Sv+4CVLNM20QcpvGb81B8C5HkQC/kW1CQpIbXDA= github.com/sei-protocol/goutils v0.0.2/go.mod h1:iYE2DuJfEnM+APPehr2gOUXfuLuPsVxorcDO+Tzq9q8= -github.com/sei-protocol/sei-cosmos v0.2.73-evm-rebase-8 h1:ueyLkyzlvuInVIPKvd4FLqe/N8+wZSRtfh5C0RMi7rQ= -github.com/sei-protocol/sei-cosmos v0.2.73-evm-rebase-8/go.mod h1:xhbsd0d50m0pKrYkWluhCIkLOaqE8AlEROiaPr4VkXQ= github.com/sei-protocol/sei-db v0.0.30 h1:dlAOTE+7nByzzAD9cb1/DxaHWbxXOHFh58a2ImvcoYs= github.com/sei-protocol/sei-db v0.0.30/go.mod h1:F/ZKZA8HJPcUzSZPA8yt6pfwlGriJ4RDR4eHKSGLStI= github.com/sei-protocol/sei-iavl v0.1.9 h1:y4mVYftxLNRs6533zl7N0/Ch+CzRQc04JDfHolIxgBE= diff --git a/precompiles/common/expected_keepers.go b/precompiles/common/expected_keepers.go index 8dae28f850..7b234f581b 100644 --- a/precompiles/common/expected_keepers.go +++ b/precompiles/common/expected_keepers.go @@ -42,6 +42,10 @@ type StakingKeeper interface { Delegate(goCtx context.Context, msg *stakingtypes.MsgDelegate) (*stakingtypes.MsgDelegateResponse, error) BeginRedelegate(goCtx context.Context, msg *stakingtypes.MsgBeginRedelegate) (*stakingtypes.MsgBeginRedelegateResponse, error) Undelegate(goCtx context.Context, msg *stakingtypes.MsgUndelegate) (*stakingtypes.MsgUndelegateResponse, error) + Delegation(goCtx context.Context, delegatorAddr, validatorAddr string) (stakingtypes.QueryDelegationResponse, error) + Validator(goCtx context.Context, validatorAddr string) (stakingtypes.QueryValidatorResponse, error) + UnbondingDelegation(goCtx context.Context, delegatorAddr, validatorAddr string) (stakingtypes.QueryUnbondingDelegationResponse, error) + UnbondingDelegationByUnbondingId(goCtx context.Context, delegatorAddr, validatorAddr string, unbondingId uint64) (stakingtypes.UnbondingDelegationEntry, error) } type GovKeeper interface { diff --git a/precompiles/staking/Staking.sol b/precompiles/staking/Staking.sol index 7d7fa50305..b0ea18a293 100644 --- a/precompiles/staking/Staking.sol +++ b/precompiles/staking/Staking.sol @@ -3,25 +3,48 @@ pragma solidity ^0.8.0; address constant STAKING_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000001005; -IStaking constant STAKING_CONTRACT = IStaking( - STAKING_PRECOMPILE_ADDRESS -); +IStaking constant STAKING_CONTRACT = IStaking(STAKING_PRECOMPILE_ADDRESS); + +enum BondStatus { + Unbonded, + Unbonding, + Bonded +} + +struct UnbondingDelegationEntry { + uint256 initialAmount; + uint256 amount; + uint256 creationHeight; + uint256 completionTime; +} + +struct StakingPool { + uint256 totalShares; + uint256 totalTokens; + BondStatus status; + bool jailed; +} interface IStaking { - // Transactions - function delegate( - string memory valAddress, - uint256 amount - ) external returns (bool success); - - function redelegate( - string memory srcAddress, - string memory dstAddress, - uint256 amount - ) external returns (bool success); - - function undelegate( - string memory valAddress, - uint256 amount - ) external returns (bool success); -} \ No newline at end of file + // Messages + function delegate(address validator, uint256 amount) external returns (uint256 shares); + + function redelegate(address src, address dst, uint256 amount) external returns (bool success); + + function undelegate(address validator, uint256 amount) external returns (uint256 unbondingID); + + // Queries + function getDelegation(address delegator, address validator) external view returns (uint256 shares); + + function getStakingPool(address validator) external view returns (StakingPool memory); + + function getUnbondingDelegationByUnbondingID(address delegator, address validator) + external + view + returns (UnbondingDelegationEntry[] memory); + + function getUnbondingDelegationByUnbondingID(address delegator, address validator, uint256 unbondingID) + external + view + returns (UnbondingDelegationEntry memory); +} diff --git a/precompiles/staking/staking.go b/precompiles/staking/staking.go index 6f5eb78b49..ec7954e179 100644 --- a/precompiles/staking/staking.go +++ b/precompiles/staking/staking.go @@ -14,9 +14,13 @@ import ( ) const ( - DelegateMethod = "delegate" - RedelegateMethod = "redelegate" - UndelegateMethod = "undelegate" + DelegateMethod = "delegate" + RedelegateMethod = "redelegate" + UndelegateMethod = "undelegate" + DelegationQuery = "getDelegation" + StakingPoolQuery = "getStakingPool" + UnbondingDelegationQuery = "getUnbondingDelegation" + UnbondingDelegationByUnbondingIDQuery = "getUnbondingDelegationByUnbondingId" ) const ( @@ -49,9 +53,13 @@ type Precompile struct { evmKeeper pcommon.EVMKeeper address common.Address - DelegateID []byte - RedelegateID []byte - UndelegateID []byte + DelegateID []byte + RedelegateID []byte + UndelegateID []byte + DelegationID []byte + StakingPoolID []byte + UnbondingDelegationID []byte + UnbondingDelegationByUnbondingID []byte } func NewPrecompile(stakingKeeper pcommon.StakingKeeper, evmKeeper pcommon.EVMKeeper) (*Precompile, error) { @@ -72,7 +80,16 @@ func NewPrecompile(stakingKeeper pcommon.StakingKeeper, evmKeeper pcommon.EVMKee p.RedelegateID = m.ID case UndelegateMethod: p.UndelegateID = m.ID + case DelegationQuery: + p.DelegationID = m.ID + case StakingPoolQuery: + p.StakingPoolID = m.ID + case UnbondingDelegationQuery: + p.UnbondingDelegationID = m.ID + case UnbondingDelegationByUnbondingIDQuery: + p.UnbondingDelegationByUnbondingID = m.ID } + } return p, nil @@ -88,6 +105,12 @@ func (p Precompile) RequiredGas(input []byte) uint64 { return 70000 } else if bytes.Equal(methodID, p.UndelegateID) { return 50000 + } else if bytes.Equal(methodID, p.DelegationID) { + return 5000 + } else if bytes.Equal(methodID, p.StakingPoolID) { + return 5000 + } else if bytes.Equal(methodID, p.UnbondingDelegationID) { + return 10000 } panic("unknown method") } @@ -109,16 +132,25 @@ func (p Precompile) Run(evm *vm.EVM, caller common.Address, input []byte) (bz [] return p.redelegate(ctx, method, caller, args) case UndelegateMethod: return p.undelegate(ctx, method, caller, args) + case DelegationQuery: + return p.getDelegation(ctx, method, caller, args) + case StakingPoolQuery: + return p.getStakingPool(ctx, method, args) + case UnbondingDelegationQuery: + return p.getUnbondingDelegation(ctx, method, args) + case UnbondingDelegationByUnbondingIDQuery: + return p.getUnbondingDelegationByUnbondingId(ctx, method, args) + default: + return } - return } func (p Precompile) delegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}) ([]byte, error) { pcommon.AssertArgsLength(args, 2) delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) - validatorBech32 := args[0].(string) + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() amount := args[1].(*big.Int) - _, err := p.stakingKeeper.Delegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgDelegate{ + res, err := p.stakingKeeper.Delegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgDelegate{ DelegatorAddress: delegator.String(), ValidatorAddress: validatorBech32, Amount: sdk.NewCoin(p.evmKeeper.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amount)), @@ -126,14 +158,14 @@ func (p Precompile) delegate(ctx sdk.Context, method *abi.Method, caller common. if err != nil { return nil, err } - return method.Outputs.Pack(true) + return method.Outputs.Pack(res.Shares) } func (p Precompile) redelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}) ([]byte, error) { pcommon.AssertArgsLength(args, 3) delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) - srcValidatorBech32 := args[0].(string) - dstValidatorBech32 := args[1].(string) + srcValidatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() + dstValidatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[1].(common.Address)).String() amount := args[2].(*big.Int) _, err := p.stakingKeeper.BeginRedelegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgBeginRedelegate{ DelegatorAddress: delegator.String(), @@ -150,9 +182,9 @@ func (p Precompile) redelegate(ctx sdk.Context, method *abi.Method, caller commo func (p Precompile) undelegate(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}) ([]byte, error) { pcommon.AssertArgsLength(args, 2) delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) - validatorBech32 := args[0].(string) + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() amount := args[1].(*big.Int) - _, err := p.stakingKeeper.Undelegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgUndelegate{ + res, err := p.stakingKeeper.Undelegate(sdk.WrapSDKContext(ctx), &stakingtypes.MsgUndelegate{ DelegatorAddress: delegator.String(), ValidatorAddress: validatorBech32, Amount: sdk.NewCoin(p.evmKeeper.GetBaseDenom(ctx), sdk.NewIntFromBigInt(amount)), @@ -160,5 +192,59 @@ func (p Precompile) undelegate(ctx sdk.Context, method *abi.Method, caller commo if err != nil { return nil, err } - return method.Outputs.Pack(true) + return method.Outputs.Pack(res.UnbondingId) +} + +func (p Precompile) getDelegation(ctx sdk.Context, method *abi.Method, caller common.Address, args []interface{}) ([]byte, error) { + pcommon.AssertArgsLength(args, 2) + delegator := p.evmKeeper.GetSeiAddressOrDefault(ctx, caller) + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() + delegation, err := p.stakingKeeper.Delegation(sdk.WrapSDKContext(ctx), delegator.String(), validatorBech32) + if err != nil { + return nil, err + } + return method.Outputs.Pack(delegation.DelegationResponse.Balance) +} + +func (p Precompile) getStakingPool(ctx sdk.Context, method *abi.Method, args []interface{}) ([]byte, error) { + pcommon.AssertArgsLength(args, 1) + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() + validator, err := p.stakingKeeper.Validator(sdk.WrapSDKContext(ctx), validatorBech32) + if err != nil { + return nil, err + } + return method.Outputs.Pack(struct { + TotalShares *big.Int + TotalTokens *big.Int + Status stakingtypes.BondStatus + Jailed bool + }{ + validator.Validator.DelegatorShares.BigInt(), + validator.Validator.Tokens.BigInt(), + validator.Validator.Status, + validator.Validator.Jailed, + }) +} + +func (p Precompile) getUnbondingDelegation(ctx sdk.Context, method *abi.Method, args []interface{}) ([]byte, error) { + pcommon.AssertArgsLength(args, 2) + delegatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[1].(common.Address)).String() + unbonding, err := p.stakingKeeper.UnbondingDelegation(sdk.WrapSDKContext(ctx), delegatorBech32, validatorBech32) + if err != nil { + return nil, err + } + return method.Outputs.Pack(unbonding) +} + +func (p Precompile) getUnbondingDelegationByUnbondingId(ctx sdk.Context, method *abi.Method, args []interface{}) ([]byte, error) { + pcommon.AssertArgsLength(args, 1) + delegatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[0].(common.Address)).String() + validatorBech32 := p.evmKeeper.GetSeiAddressOrDefault(ctx, args[1].(common.Address)).String() + unbondingId := args[2].(uint64) + unbondingEntry, err := p.stakingKeeper.UnbondingDelegationByUnbondingId(sdk.WrapSDKContext(ctx), delegatorBech32, validatorBech32, unbondingId) + if err != nil { + return nil, err + } + return method.Outputs.Pack(unbondingEntry) }