Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop oracle nst #198

Merged
merged 3 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,7 @@ func NewExocoreApp(
app.OracleKeeper = oracleKeeper.NewKeeper(
appCodec, keys[oracleTypes.StoreKey], memKeys[oracleTypes.MemStoreKey],
app.GetSubspace(oracleTypes.ModuleName), app.StakingKeeper,
&app.DelegationKeeper,
)

// the SDK slashing module is used to slash validators in the case of downtime. it tracks
Expand Down
2 changes: 1 addition & 1 deletion precompiles/assets/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (p Precompile) DepositOrWithdraw(
}
_, assetID := assetstypes.GetStakerIDAndAssetID(depositWithdrawParams.ClientChainLzID,
depositWithdrawParams.StakerAddress, depositWithdrawParams.AssetsAddress)
err = p.assetsKeeper.UpdateNativeTokenValidatorListForStaker(ctx, assetID,
err = p.assetsKeeper.UpdateNSTValidatorListForStaker(ctx, assetID,
hexutil.Encode(depositWithdrawParams.StakerAddress),
hexutil.Encode(depositWithdrawParams.ValidatorPubkey),
opAmount)
Expand Down
2 changes: 2 additions & 0 deletions testutil/keeper/oracle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
typesparams "github.com/cosmos/cosmos-sdk/x/params/types"

delegationkeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper"
dogfoodkeeper "github.com/ExocoreNetwork/exocore/x/dogfood/keeper"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -45,6 +46,7 @@ func OracleKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
memStoreKey,
paramsSubspace,
dogfoodkeeper.Keeper{},
delegationkeeper.Keeper{},
)

ctx := sdk.NewContext(stateStore, tmproto.Header{
Expand Down
6 changes: 6 additions & 0 deletions testutil/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type BaseTestSuite struct {
App *exocoreapp.ExocoreApp
Address common.Address
AccAddress sdk.AccAddress
StakerAddr string

PrivKey cryptotypes.PrivKey
Signer keyring.Signer
Expand Down Expand Up @@ -95,6 +96,7 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc
suite.ClientChains[0].LayerZeroChainID,
common.Address(operator1.Bytes()).String(), "",
)
suite.StakerAddr = common.Address(operator1.Bytes()).String()
stakerID2, _ := assetstypes.GetStakerIDAndAssetIDFromStr(
suite.ClientChains[0].LayerZeroChainID,
common.Address(operator2.Bytes()).String(), "",
Expand Down Expand Up @@ -176,6 +178,10 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc
AssetBasicInfo: suite.Assets[0],
StakingTotalAmount: depositAmount.Add(depositAmount2),
},
// {
// AssetBasicInfo: suite.Assets[1],
// StakingTotalAmount: depositAmount.Add(math.NewInt(132)),
// },
}, depositsByStaker, operatorAssets,
)
genesisState[assetstypes.ModuleName] = app.AppCodec().MustMarshalJSON(assetsGenesis)
Expand Down
2 changes: 1 addition & 1 deletion x/assets/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
type OracleKeeper interface {
GetSpecifiedAssetsPrice(ctx sdk.Context, assetID string) (oracletypes.Price, error)
RegisterNewTokenAndSetTokenFeeder(ctx sdk.Context, oInfo *oracletypes.OracleInfo) error
UpdateNativeTokenValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error
UpdateNSTValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error
}

type BankKeeper interface {
Expand Down
11 changes: 5 additions & 6 deletions x/delegation/keeper/update_native_restaking_balance.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ const (
MaxSlashProportion = 1
)

func (k Keeper) UpdateNativeRestakingBalance(
func (k Keeper) UpdateNSTBalance(
ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int,
) error {
// todo: check if the assetID is native retaking token
if amount.IsPositive() {
// If the balance increases due to the client chain PoS staking reward, the increased
// amount can be considered a virtual deposit event. However, the increased amount needs
Expand Down Expand Up @@ -54,7 +53,7 @@ func (k Keeper) UpdateNativeRestakingBalance(
if err != nil {
return err
}
ctx.Logger().Info("UpdateNativeRestakingBalance slash from withdrawable amount", "stakerID", stakerID, "assetID", assetID, "slashFromWithdrawable", slashFromWithdrawable, "pendingSlashAmount", pendingSlashAmount)
ctx.Logger().Info("UpdateNSTBalance slash from withdrawable amount", "stakerID", stakerID, "assetID", assetID, "slashFromWithdrawable", slashFromWithdrawable, "pendingSlashAmount", pendingSlashAmount)

// slash from pending undelegations
if pendingSlashAmount.IsPositive() {
Expand All @@ -72,7 +71,7 @@ func (k Keeper) UpdateNativeRestakingBalance(
if err != nil {
return true, err
}
ctx.Logger().Info("UpdateNativeRestakingBalance slash from undelegation", "stakerID", stakerID, "assetID", assetID, "operator", undelegation.OperatorAddr, "undelegationKey", undelegationKey, "slashAmount", slashAmount, "pendingSlashAmount", pendingSlashAmount)
ctx.Logger().Info("UpdateNSTBalance slash from undelegation", "stakerID", stakerID, "assetID", assetID, "operator", undelegation.OperatorAddr, "undelegationKey", undelegationKey, "slashAmount", slashAmount, "pendingSlashAmount", pendingSlashAmount)
if !pendingSlashAmount.IsPositive() {
// return ture to break the iteration if there isn't remaining amount to be slashed
return true, nil
Expand Down Expand Up @@ -116,7 +115,7 @@ func (k Keeper) UpdateNativeRestakingBalance(
return true, err
}
pendingSlashAmount = pendingSlashAmount.Sub(actualSlashAmount)
ctx.Logger().Info("UpdateNativeRestakingBalance slash from delegated share", "stakerID", stakerID, "assetID", assetID, "operator", keys.OperatorAddr, "slashProportion", slashProportion, "slashShare", slashShare, "actualSlashAmount", actualSlashAmount, "pendingSlashAmount", pendingSlashAmount)
ctx.Logger().Info("UpdateNSTBalance slash from delegated share", "stakerID", stakerID, "assetID", assetID, "operator", keys.OperatorAddr, "slashProportion", slashProportion, "slashShare", slashShare, "actualSlashAmount", actualSlashAmount, "pendingSlashAmount", pendingSlashAmount)
return false, nil
}
err = k.IterateDelegationsForStakerAndAsset(ctx, stakerID, assetID, opFunc)
Expand All @@ -128,7 +127,7 @@ func (k Keeper) UpdateNativeRestakingBalance(
// In this case, we only print a log as a reminder. This situation will only occur when the total slashing amount
// from the client chain and Exocore chain is greater than the total staking amount.
if pendingSlashAmount.IsPositive() {
ctx.Logger().Info("UpdateNativeRestakingBalance all staking funds has been slashed, the remaining amount is:", "stakerID", stakerID, "assetID", assetID, "pendingSlashAmount", pendingSlashAmount)
ctx.Logger().Info("UpdateNSTBalance all staking funds has been slashed, the remaining amount is:", "stakerID", stakerID, "assetID", assetID, "pendingSlashAmount", pendingSlashAmount)
}
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions x/delegation/keeper/update_native_restaking_balance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

func (suite *DelegationTestSuite) TestUpdateNativeRestakingBalance() {
func (suite *DelegationTestSuite) TestUpdateNSTBalance() {
// test case: slash 80
// withdrawable: 60 slash: 60 -> 0
// undelegation: 10 slash: 10 -> 0
Expand Down Expand Up @@ -35,7 +35,7 @@ func (suite *DelegationTestSuite) TestUpdateNativeRestakingBalance() {
slashAmount := sdkmath.NewInt(80)
actualSlashAmount := sdkmath.NewInt(79)
stakerID, assetID := assettypes.GetStakerIDAndAssetID(suite.clientChainLzID, suite.Address[:], suite.assetAddr.Bytes())
err = suite.App.DelegationKeeper.UpdateNativeRestakingBalance(suite.Ctx, stakerID, assetID, slashAmount.Neg())
err = suite.App.DelegationKeeper.UpdateNSTBalance(suite.Ctx, stakerID, assetID, slashAmount.Neg())
suite.NoError(err)

// check the asset state for the slashed staker
Expand Down
13 changes: 8 additions & 5 deletions x/oracle/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type (
paramstore paramtypes.Subspace
// authority string
common.KeeperDogfood
delegationKeeper types.DelegationKeeper
}
)

Expand All @@ -34,18 +35,20 @@ func NewKeeper(
memKey storetypes.StoreKey,
ps paramtypes.Subspace,
sKeeper common.KeeperDogfood,
delegationKeeper types.DelegationKeeper,
) Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
ps = ps.WithKeyTable(types.ParamKeyTable())
}

return Keeper{
cdc: cdc,
storeKey: storeKey,
memKey: memKey,
paramstore: ps,
KeeperDogfood: sKeeper,
cdc: cdc,
storeKey: storeKey,
memKey: memKey,
paramstore: ps,
KeeperDogfood: sKeeper,
delegationKeeper: delegationKeeper,
}
}

Expand Down
30 changes: 30 additions & 0 deletions x/oracle/keeper/keeper_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"testing"

"cosmossdk.io/math"
"github.com/ExocoreNetwork/exocore/testutil"
assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types"
"github.com/ExocoreNetwork/exocore/x/oracle/keeper"
"github.com/ExocoreNetwork/exocore/x/oracle/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -80,6 +82,34 @@ func (suite *KeeperSuite) Reset() {

func (suite *KeeperSuite) SetupTest() {
suite.DoSetupTest()

depositAmountNST := math.NewInt(132)
suite.App.AssetsKeeper.SetStakingAssetInfo(suite.Ctx, &assetstypes.StakingAssetInfo{
AssetBasicInfo: assetstypes.AssetInfo{
Name: "Native Restaking ETH",
Symbol: "NSTETH",
Address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
Decimals: 6,
LayerZeroChainID: suite.ClientChains[0].LayerZeroChainID,
MetaInfo: "native restaking token",
},
StakingTotalAmount: depositAmountNST,
})

stakerID, _ := assetstypes.GetStakerIDAndAssetIDFromStr(
suite.ClientChains[0].LayerZeroChainID,
ks.StakerAddr, "",
)
NSTAssetAddr := assetstypes.GenerateNSTAddr(
suite.ClientChains[0].AddressLength,
)
_, assetIDNST := assetstypes.GetStakerIDAndAssetID(suite.ClientChains[0].LayerZeroChainID, []byte{}, NSTAssetAddr)
suite.App.AssetsKeeper.UpdateStakerAssetState(ks.Ctx, stakerID, assetIDNST, assetstypes.DeltaStakerSingleAsset{
TotalDepositAmount: depositAmountNST,
WithdrawableAmount: depositAmountNST,
PendingUndelegationAmount: sdk.ZeroInt(),
})

validators := suite.ValSet.Validators
suite.valAddr1, _ = sdk.ValAddressFromBech32(sdk.ValAddress(validators[0].Address).String())
suite.valAddr2, _ = sdk.ValAddressFromBech32(sdk.ValAddress(validators[1].Address).String())
Expand Down
23 changes: 16 additions & 7 deletions x/oracle/keeper/native_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ package keeper
import (
"errors"
"fmt"
"strings"

sdkmath "cosmossdk.io/math"
utils "github.com/ExocoreNetwork/exocore/utils"
assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types"
"github.com/ExocoreNetwork/exocore/x/oracle/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common/hexutil"
)

// deposit: update staker's totalDeposit
Expand All @@ -31,9 +35,7 @@ func (k Keeper) GetStakerInfo(ctx sdk.Context, assetID, stakerAddr string) types
return stakerInfo
}

func (k Keeper) UpdateNativeTokenValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error {
// TODO: use definition from assets module
assetID := "0xe_" + chainID
func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error {
// emit an event to tell that a staker's validator list has changed
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeCreatePrice,
Expand Down Expand Up @@ -159,8 +161,9 @@ func (k Keeper) GetStakerList(ctx sdk.Context, assetID string) types.StakerList
return *stakerList
}

// UpdateNativeTokenByBalanceChange updates balance info for staker under native-restaking asset of assetID when its balance changed by slash/refund on the source chain (beacon chain for eth)
func (k Keeper) UpdateNativeTokenByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error {
// UpdateNSTByBalanceChange updates balance info for staker under native-restaking asset of assetID when its balance changed by slash/refund on the source chain (beacon chain for eth)
func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error {
_, chainID, _ := assetstypes.ParseID(assetID)
if len(rawData) < 32 {
return errors.New("length of indicate maps for stakers shoule be exactly 32 bytes")
}
Expand Down Expand Up @@ -202,8 +205,9 @@ func (k Keeper) UpdateNativeTokenByBalanceChange(ctx sdk.Context, assetID string
return errors.New("effective balance should never exceeds 32")
}
if delta := int64(balance) - newBalance.Balance; delta != 0 {
// TODO: call assetsmodule. func(k Keeper) UpdateNativeRestakingBalance(ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int) error
_ = balance
if err := k.delegationKeeper.UpdateNSTBalance(ctx, getStakerID(stakerAddr, chainID), assetID, sdkmath.NewInt(delta)); err != nil {
return err
}
newBalance.Balance = int64(balance)
}
// newBalance.Balance += int64(change)
Expand Down Expand Up @@ -290,3 +294,8 @@ func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, er
}
return stakerChanges, nil
}

// TODO use []byte and assetstypes.GetStakerIDAndAssetID for stakerAddr representation
func getStakerID(stakerAddr string, chainID uint64) string {
return strings.Join([]string{strings.ToLower(stakerAddr), hexutil.EncodeUint64(chainID)}, utils.DelimiterForID)
}
52 changes: 25 additions & 27 deletions x/oracle/keeper/native_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
sdkmath "cosmossdk.io/math"

"github.com/ExocoreNetwork/exocore/x/oracle/types"

"github.com/ethereum/go-ethereum/common"
"github.com/imroc/biu"
)

Expand All @@ -35,53 +33,53 @@ import (
// 1. removed stakerInfo
// 2. removed stakerList

func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() {
operator := ks.Operators[0]
stakerStr := common.Address(operator.Bytes()).String()
chainID := "beaconchain"
// TODO: update after assets module got the definition
assetID := "0xe_" + chainID
func (ks *KeeperSuite) TestNSTLifeCycleOneStaker() {
// operator := ks.Operators[0]
// stakerStr := common.Address(operator.Bytes()).String()
stakerStr := ks.StakerAddr
assetID := "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x65"
validators := []string{"0xv1", "0xv2"}
// 1. deposit amount 100
// 100 is not a possible nubmer with one validator, it's ok to use this as a start and we'll check the number to be updated to a right number(uncer 32 with one validator)
amount100 := sdkmath.NewIntFromUint64(100)
amount32 := sdkmath.NewIntFromUint64(32)
ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[0], amount100)
ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount100)

// - 1.1 check stakerInfo
stakerInfo := ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo := ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.BalanceInfo{
Block: 2,
Block: 1,
RoundID: 0,
Change: types.Action_ACTION_DEPOSIT,
Balance: 100,
}, *stakerInfo.BalanceList[0])
ks.Equal([]string{validators[0]}, stakerInfo.ValidatorPubkeyList)
// - 1.2 check stakerList
stakerList := ks.k.GetStakerList(ks.ctx, assetID)
stakerList := ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID)
ks.Equal(stakerList.StakerAddrs[0], stakerStr)

// 2. Msg. minus staker's balance
stakerChanges := [][]int{
{0, -10},
}
rawData := convertBalanceChangeToBytes(stakerChanges)
ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 9)
ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 9)
// - 2.1 check stakerInfo
stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.BalanceInfo{
Block: 2,
Block: 1,
RoundID: 9,
Change: types.Action_ACTION_SLASH_REFUND,
// this is expected to be 32-10=22, not 100-10
Balance: 22,
}, *stakerInfo.BalanceList[1])

// 3. deposit more. 100
ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[1], amount32) // 999
ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount32) // 999
// - 3.1 check stakerInfo
stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.BalanceInfo{
Block: 2,
Block: 1,
RoundID: 9,
Index: 1,
Change: types.Action_ACTION_DEPOSIT,
Expand All @@ -96,25 +94,25 @@ func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() {
{0, -5},
}
rawData = convertBalanceChangeToBytes(stakerChanges)
ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 11)
ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 11)
// - 4.1 check stakerInfo
stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.BalanceInfo{
Balance: 59,
Block: 2,
Block: 1,
RoundID: 11,
Index: 0,
Change: types.Action_ACTION_SLASH_REFUND,
}, *stakerInfo.BalanceList[3])

// 5. withdraw
amount30N := sdkmath.NewInt(-30)
ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[0], amount30N)
ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount30N)
// - 5.1 check stakerInfo
stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.BalanceInfo{
Balance: 29,
Block: 2,
Block: 1,
RoundID: 11,
Index: 1,
Change: types.Action_ACTION_WITHDRAW,
Expand All @@ -124,12 +122,12 @@ func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() {

// 6.withdrawall
amount100N := sdkmath.NewInt(-29)
ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[1], amount100N)
ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount100N)
// - 6.1 check stakerInfo
stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr)
stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr)
ks.Equal(types.StakerInfo{}, stakerInfo)
// - 6.2 check stakerList
stakerList = ks.k.GetStakerList(ks.ctx, assetID)
stakerList = ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID)
}

func convertBalanceChangeToBytes(stakerChanges [][]int) []byte {
Expand Down
Loading
Loading