diff --git a/app/app.go b/app/app.go index 186cada1e..356fdce76 100644 --- a/app/app.go +++ b/app/app.go @@ -551,6 +551,7 @@ func NewExocoreApp( app.AssetsKeeper, delegationTypes.VirtualSlashKeeper{}, &app.OperatorKeeper, + &app.OracleKeeper, ) // the dogfood module is the first AVS. it receives slashing calls from either x/slashing diff --git a/go.mod b/go.mod index daaeac22d..81beb849f 100644 --- a/go.mod +++ b/go.mod @@ -155,6 +155,7 @@ require ( github.com/holiman/uint256 v1.2.3 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/huin/goupnp v1.3.0 // indirect + github.com/imroc/biu v0.0.0-20170329141542-0376ce6761c0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect diff --git a/go.sum b/go.sum index 432118e65..880f3c79e 100644 --- a/go.sum +++ b/go.sum @@ -1147,6 +1147,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= +github.com/imroc/biu v0.0.0-20170329141542-0376ce6761c0 h1:pkyNAS9IQiZgseFrdhZC4cloBo2k2O2Son/k+3NquwY= +github.com/imroc/biu v0.0.0-20170329141542-0376ce6761c0/go.mod h1:wscexmyH+oDXfQr1q8PAZUXfKnxCUcNm62D/M5Ec8Lw= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= diff --git a/proto/exocore/oracle/v1/native_token.proto b/proto/exocore/oracle/v1/native_token.proto new file mode 100644 index 000000000..e0bbdf0b9 --- /dev/null +++ b/proto/exocore/oracle/v1/native_token.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package exocore.oracle.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/oracle/types"; + +message PriceInfo { + string price = 1[(gogoproto.customtype)="cosmossdk.io/math.LegacyDec",(gogoproto.nullable) = false ]; + uint64 block = 2; + uint64 round_id = 3 [(gogoproto.customname)="RoundID"]; +} + +message OperatorInfo { + string operator_addr = 1; + string total_amount = 2[(gogoproto.customtype)="cosmossdk.io/math.Int",(gogoproto.nullable) = false]; + repeated PriceInfo price_list = 3; +} + +message StakerInfo { + string staker_addr = 1; + int64 staker_index = 2; + repeated uint64 validator_indexs = 3; + string total_deposit = 4[(gogoproto.customtype)="cosmossdk.io/math.Int",(gogoproto.nullable) = false]; + repeated PriceInfo price_list = 5; +} + +message NativeTokenPrice { + string token = 1; + repeated PriceInfo prece_list = 2; +} + +message StakerList { + repeated string staker_addrs = 1; +} + +message DelegationInfo { + string operator_addr = 1; + string amount = 2[(gogoproto.customtype)="cosmossdk.io/math.Int",(gogoproto.nullable) = false]; +} +message StakerDelegationInfo { + repeated DelegationInfo delegations = 1; +} diff --git a/x/assets/keeper/bank.go b/x/assets/keeper/bank.go index 576ceded1..cec14d7a8 100644 --- a/x/assets/keeper/bank.go +++ b/x/assets/keeper/bank.go @@ -8,6 +8,8 @@ import ( assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common/hexutil" ) type DepositWithdrawParams struct { @@ -43,6 +45,11 @@ func (k Keeper) PerformDepositOrWithdraw(ctx sdk.Context, params *DepositWithdra return errorsmod.Wrapf(assetstypes.ErrInvalidOperationType, "the operation type is: %v", params.Action) } + if assetstypes.IsNativeToken(assetID) { + // TODO: we skip check for case like withdraw amount>withdrawable is fine since it will fail for later check and the state will be rollback + actualOpAmount = k.UpdateNativeTokenByDepositOrWithdraw(ctx, assetID, hexutil.Encode(params.StakerAddress), params.OpAmount) + } + changeAmount := assetstypes.DeltaStakerSingleAsset{ TotalDepositAmount: actualOpAmount, WithdrawableAmount: actualOpAmount, diff --git a/x/assets/types/expected_keepers.go b/x/assets/types/expected_keepers.go index c1fe65043..0d276cba4 100644 --- a/x/assets/types/expected_keepers.go +++ b/x/assets/types/expected_keepers.go @@ -1,10 +1,12 @@ package types import ( + sdkmath "cosmossdk.io/math" oracletypes "github.com/ExocoreNetwork/exocore/x/oracle/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type OracleKeeper interface { GetSpecifiedAssetsPrice(ctx sdk.Context, assetID string) (oracletypes.Price, error) + UpdateNativeTokenByDepositOrWithdraw(ctx sdk.Context, assetID, stakerAddr string, amount sdkmath.Int) sdkmath.Int } diff --git a/x/assets/types/general.go b/x/assets/types/general.go index f89641506..74912dc20 100644 --- a/x/assets/types/general.go +++ b/x/assets/types/general.go @@ -27,8 +27,16 @@ const ( MaxChainTokenMetaInfoLength = 200 MinClientChainAddrLength = 20 + + // TODO: update before merge + NativeETHAssetID = "0x01_0x01" + ETHAssetID = "0x02_0x01" ) +var NativeTokenBaseMap = map[string]string{ + NativeETHAssetID: ETHAssetID, +} + const ( Deposit CrossChainOpType = iota WithdrawPrincipal @@ -162,3 +170,17 @@ func UpdateAssetDecValue(valueToUpdate *math.LegacyDec, changeValue *math.Legacy } return nil } + +func IsNativeToken(assetID string) bool { + // TODO: native token should be a list which able to config, we currently only support ETH, so it's fine for now + return assetID == NativeETHAssetID +} + +func GetNativeTokenAssetIDs() []string { + // TODO: we currently have native_eth only + return []string{NativeETHAssetID} +} + +func GetBaseTokenForNativeToken(assetID string) string { + return NativeTokenBaseMap[assetID] +} diff --git a/x/delegation/keeper/abci.go b/x/delegation/keeper/abci.go index 6f54e2237..c71960d60 100644 --- a/x/delegation/keeper/abci.go +++ b/x/delegation/keeper/abci.go @@ -45,8 +45,8 @@ func (k *Keeper) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Valida panic(err) } // and the other is the fact that it matures at the next block - err = k.StorePendingUndelegationRecord(ctx, recordKey, record) - if err != nil { + if err = k.StorePendingUndelegationRecord(ctx, recordKey, record); err != nil { + // TODO: remove previous index with currentHeight for pendingUndelegationRecord panic(err) } continue diff --git a/x/delegation/keeper/delegation.go b/x/delegation/keeper/delegation.go index 902927599..9faa1a7b7 100644 --- a/x/delegation/keeper/delegation.go +++ b/x/delegation/keeper/delegation.go @@ -9,6 +9,8 @@ import ( assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ethereum/go-ethereum/common/hexutil" ) // DelegateTo : It doesn't need to check the active status of the operator in middlewares when @@ -46,7 +48,9 @@ func (k *Keeper) delegateTo( if err != nil { return err } - + if assetstype.IsNativeToken(assetID) { + params.OpAmount = k.oracleKeeper.UpdateNativeTokenByDelegation(ctx, assetID, params.OperatorAddress.String(), hexutil.Encode(params.StakerAddress), params.OpAmount) + } if info.WithdrawableAmount.LT(params.OpAmount) { return errorsmod.Wrap(delegationtype.ErrDelegationAmountTooBig, fmt.Sprintf("the opAmount is:%s the WithdrawableAmount amount is:%s", params.OpAmount, info.WithdrawableAmount)) } @@ -116,6 +120,10 @@ func (k *Keeper) UndelegateFrom(ctx sdk.Context, params *delegationtype.Delegati // get staker delegation state, then check the validation of Undelegation amount stakerID, assetID := assetstype.GetStakeIDAndAssetID(params.ClientChainID, params.StakerAddress, params.AssetsAddress) + if assetstype.IsNativeToken(assetID) { + params.OpAmount = k.oracleKeeper.UpdateNativeTokenByDelegation(ctx, assetID, params.OperatorAddress.String(), hexutil.Encode(params.StakerAddress), params.OpAmount.Neg()).Neg() + } + // verify the undelegation amount share, err := k.ValidateUndelegationAmount(ctx, params.OperatorAddress, stakerID, assetID, params.OpAmount) if err != nil { diff --git a/x/delegation/keeper/keeper.go b/x/delegation/keeper/keeper.go index 170d901f2..d5ec89eb4 100644 --- a/x/delegation/keeper/keeper.go +++ b/x/delegation/keeper/keeper.go @@ -17,6 +17,7 @@ type Keeper struct { assetsKeeper delegationtype.AssetsKeeper slashKeeper delegationtype.SlashKeeper operatorKeeper delegationtype.OperatorKeeper + oracleKeeper delegationtype.OracleKeeper hooks delegationtype.DelegationHooks } @@ -26,6 +27,7 @@ func NewKeeper( assetsKeeper delegationtype.AssetsKeeper, slashKeeper delegationtype.SlashKeeper, operatorKeeper delegationtype.OperatorKeeper, + oracleKeeper delegationtype.OracleKeeper, ) Keeper { return Keeper{ storeKey: storeKey, @@ -33,6 +35,7 @@ func NewKeeper( assetsKeeper: assetsKeeper, slashKeeper: slashKeeper, operatorKeeper: operatorKeeper, + oracleKeeper: oracleKeeper, } } diff --git a/x/delegation/types/expected_keepers.go b/x/delegation/types/expected_keepers.go index 33113e03d..89516835a 100644 --- a/x/delegation/types/expected_keepers.go +++ b/x/delegation/types/expected_keepers.go @@ -53,3 +53,7 @@ type AssetsKeeper interface { ClientChainExists(ctx sdk.Context, index uint64) bool } + +type OracleKeeper interface { + UpdateNativeTokenByDelegation(ctx sdk.Context, assetID, operatorAddr, stakerAddr string, amountOriginal sdkmath.Int) (amount sdkmath.Int) +} diff --git a/x/delegation/types/hooks.go b/x/delegation/types/hooks.go index 48350d44f..0d99ff6de 100644 --- a/x/delegation/types/hooks.go +++ b/x/delegation/types/hooks.go @@ -1,6 +1,8 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) var _ DelegationHooks = &MultiDelegationHooks{} diff --git a/x/operator/keeper/abci.go b/x/operator/keeper/abci.go index 189272672..2421a1606 100644 --- a/x/operator/keeper/abci.go +++ b/x/operator/keeper/abci.go @@ -2,8 +2,10 @@ package keeper import ( "errors" + "strings" sdkmath "cosmossdk.io/math" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" operatortypes "github.com/ExocoreNetwork/exocore/x/operator/types" oracletypes "github.com/ExocoreNetwork/exocore/x/oracle/types" abci "github.com/cometbft/cometbft/abci/types" @@ -62,6 +64,11 @@ func (k *Keeper) UpdateVotingPower(ctx sdk.Context, avsAddr string) error { SelfUSDValue: sdkmath.LegacyNewDec(0), ActiveUSDValue: sdkmath.LegacyNewDec(0), } + for _, assetID := range assetstypes.GetNativeTokenAssetIDs() { + if _, ok := prices[assetID]; ok { + prices[assetID], err = k.oracleKeeper.GetSpecifiedAssetsPrice(ctx, strings.Join([]string{assetID, operator}, "_")) + } + } stakingInfo, err := k.CalculateUSDValueForOperator(ctx, false, operator, assets, decimals, prices) if err != nil { return err diff --git a/x/operator/keeper/usd_value.go b/x/operator/keeper/usd_value.go index 7c4dbc2d9..f1e46ec40 100644 --- a/x/operator/keeper/usd_value.go +++ b/x/operator/keeper/usd_value.go @@ -3,6 +3,7 @@ package keeper import ( "errors" "fmt" + "strings" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" delegationkeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper" @@ -299,6 +300,9 @@ func (k *Keeper) CalculateUSDValueForOperator( if isForSlash { // when calculated the USD value for slashing, the input prices map is null // so the price needs to be retrieved here + if assetstype.IsNativeToken(assetID) { + assetID = strings.Join([]string{assetID, operator}, "_") + } price, err = k.oracleKeeper.GetSpecifiedAssetsPrice(ctx, assetID) if err != nil { // TODO: when assetID is not registered in oracle module, this error will finally lead to panic diff --git a/x/oracle/keeper/native_token.go b/x/oracle/keeper/native_token.go new file mode 100644 index 000000000..473613fb7 --- /dev/null +++ b/x/oracle/keeper/native_token.go @@ -0,0 +1,450 @@ +package keeper + +import ( + "errors" + "strings" + + sdkmath "cosmossdk.io/math" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" + "github.com/ExocoreNetwork/exocore/x/oracle/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// deposit: update staker's totalDeposit +// withdoraw: update staker's totalDeposit +// delegate: update operator's price, operator's totalAmount, operator's totalShare, staker's share +// undelegate: update operator's price, operator's totalAmount, operator's totalShare, staker's share +// msg(refund or slash on beaconChain): update staker's price, operator's price + +var stakerList types.StakerList + +func (k Keeper) GetStakerInfo(ctx sdk.Context, assetID, stakerAddr string) types.StakerInfo { + store := ctx.KVStore(k.storeKey) + stakerInfo := types.StakerInfo{} + value := store.Get(types.NativeTokenStakerKey(assetID, stakerAddr)) + if value == nil { + return stakerInfo + } + k.cdc.MustUnmarshal(value, &stakerInfo) + return stakerInfo +} + +func (k Keeper) GetStakerDelegations(ctx sdk.Context, assetID, stakerAddr string) types.StakerDelegationInfo { + store := ctx.KVStore(k.storeKey) + value := store.Get(types.NativeTokenStakerDelegationKey(assetID, stakerAddr)) + stakerDelegation := types.StakerDelegationInfo{} + if value == nil { + return stakerDelegation + } + k.cdc.MustUnmarshal(value, &stakerDelegation) + return stakerDelegation +} + +func (k Keeper) GetOperatorInfo(ctx sdk.Context, assetID, operator string) types.OperatorInfo { + store := ctx.KVStore(k.storeKey) + value := store.Get(types.NativeTokenOperatorKey(assetID, operator)) + operatorInfo := types.OperatorInfo{} + if value == nil { + return operatorInfo + } + k.cdc.MustUnmarshal(value, &operatorInfo) + return operatorInfo +} + +// TODO, NOTE: price changes will effect reward/slash calculation, every time one staker's price changed, it's reward/slash amount(LST) should be cleaned or recalculated immediately +// TODO: validatorIndex +// amount: represents for originalToken +func (k Keeper) UpdateNativeTokenByDepositOrWithdraw(ctx sdk.Context, assetID, stakerAddr string, amount sdkmath.Int) sdkmath.Int { + // TODO: just convert the number for assets module, and don't store state in oracleModule, can use cache only here + // TODO: we havn't included validatorIndex here, need the bridge info + store := ctx.KVStore(k.storeKey) + key := types.NativeTokenStakerKey(assetID, stakerAddr) + stakerInfo := &types.StakerInfo{} + if value := store.Get(key); value == nil { + // create a new item for this staker + stakerInfo = types.NewStakerInfo(stakerAddr) + } else { + k.cdc.MustUnmarshal(value, stakerInfo) + } + latestIndex := len(stakerInfo.PriceList) - 1 + // calculate amount of virtual LST from nativetoken with price + amountInt := convertAmountOriginalIntToAmountFloat(amount, stakerInfo.PriceList[latestIndex].Price).RoundInt() + stakerInfo.TotalDeposit = stakerInfo.TotalDeposit.Add(amountInt) + + keyStakerList := types.NativeTokenStakerListKey(assetID) + valueStakerList := store.Get(keyStakerList) + stakerList := &types.StakerList{} + if valueStakerList != nil { + k.cdc.MustUnmarshal(valueStakerList, stakerList) + } + exists := false + for idx, stakerExists := range stakerList.StakerAddrs { + if stakerExists == stakerAddr { + if !stakerInfo.TotalDeposit.IsPositive() { + stakerList.StakerAddrs = append(stakerList.StakerAddrs[:idx], stakerList.StakerAddrs[idx+1:]...) + valueStakerList = k.cdc.MustMarshal(stakerList) + store.Set(keyStakerList, valueStakerList) + } + exists = true + stakerInfo.StakerIndex = int64(idx) + break + } + } + + // update totalDeposit of staker, and price won't change on either deposit or withdraw + if !stakerInfo.TotalDeposit.IsPositive() { + store.Delete(key) + } else { + bz := k.cdc.MustMarshal(stakerInfo) + store.Set(key, bz) + } + + if !exists { + if !stakerInfo.TotalDeposit.IsPositive() { + // this should not happened, if a staker execute the 'withdraw' action, he must have already been in the stakerList + return amountInt + } + stakerList.StakerAddrs = append(stakerList.StakerAddrs, stakerAddr) + valueStakerList = k.cdc.MustMarshal(stakerList) + store.Set(keyStakerList, valueStakerList) + } + return amountInt +} + +// UpdateNativeTokenByDelegation update operator's price, operator's totalAmount, operator's totalShare, staker's share bsed on either delegation or undelegation +// this amount passed in from delegation hooks represent originalToken(not virtualLST) +func (k Keeper) UpdateNativeTokenByDelegation(ctx sdk.Context, assetID, operatorAddr, stakerAddr string, amountOriginal sdkmath.Int) sdkmath.Int { + store := ctx.KVStore(k.storeKey) + keyOperator := types.NativeTokenOperatorKey(assetID, operatorAddr) + operatorInfo := &types.OperatorInfo{} + valueOperator := store.Get(keyOperator) + if valueOperator == nil { + operatorInfo = types.NewOperatorInfo(operatorAddr) + } else { + k.cdc.MustUnmarshal(valueOperator, operatorInfo) + } + stakerInfo := &types.StakerInfo{} + keyStaker := types.NativeTokenStakerKey(assetID, stakerAddr) + value := store.Get(keyStaker) + if value == nil { + panic("staker must exist before delegation") + } + k.cdc.MustUnmarshal(value, stakerInfo) + + operatorAmountFloat, operatorAmountOriginalFloat := getOperatorAmountFloat(operatorInfo) + amountFloat, amountOriginalFloat := parseStakerAmountOriginalInt(amountOriginal, stakerInfo) + + operatorAmountOriginalFloat = operatorAmountOriginalFloat.Add(amountOriginalFloat) + operatorAmountFloat = operatorAmountFloat.Add(amountFloat) + + // update operator's price for native token base on new delegation + if valueOperator == nil { + // undelegation should not happen on nil operatorInfo, this is delegate case + operatorInfo.PriceList = []*types.PriceInfo{ + { + Price: operatorAmountOriginalFloat.Quo(operatorAmountFloat), + Block: uint64(ctx.BlockHeight()), + }, + } + } else if operatorAmountFloat.IsPositive() { + // if amount <=0 thies operatorInfo will be rmoved, no need to append any price + operatorInfo.PriceList = append(operatorInfo.PriceList, &types.PriceInfo{ + Price: operatorAmountOriginalFloat.Quo(operatorAmountFloat), + Block: uint64(ctx.BlockHeight()), + }) + } + // update operator's total amount for native token, for this 'amount' we don't disginguish different tokens from different stakers. That difference reflects in 'operator price' + operatorInfo.TotalAmount = operatorAmountFloat.RoundInt() + if operatorInfo.TotalAmount.IsPositive() { + bz := k.cdc.MustMarshal(operatorInfo) + store.Set(keyOperator, bz) + } else { + store.Delete(keyOperator) + } + amountInt := amountFloat.RoundInt() + // update staker's related operator list + keyDelegation := types.NativeTokenStakerDelegationKey(assetID, stakerAddr) + stakerDelegation := &types.StakerDelegationInfo{} + if value = store.Get(keyDelegation); value == nil { + stakerDelegation.Delegations = []*types.DelegationInfo{ + { + OperatorAddr: operatorAddr, + Amount: amountInt, + }, + } + } else { + k.cdc.MustUnmarshal(value, stakerDelegation) + for idx, delegationInfo := range stakerDelegation.Delegations { + if delegationInfo.OperatorAddr == operatorAddr { + if delegationInfo.Amount = delegationInfo.Amount.Add(amountInt); !delegationInfo.Amount.IsPositive() { + stakerDelegation.Delegations = append(stakerDelegation.Delegations[:idx], stakerDelegation.Delegations[idx+1:]...) + } + value = k.cdc.MustMarshal(stakerDelegation) + store.Set(keyDelegation, value) + return amountInt + } + } + stakerDelegation.Delegations = append(stakerDelegation.Delegations, &types.DelegationInfo{ + OperatorAddr: operatorAddr, + Amount: amountInt, + }) + } + // update staker delegation infos for related operators + value = k.cdc.MustMarshal(stakerDelegation) + store.Set(keyDelegation, value) + + return amountInt +} + +func (k Keeper) GetNativeTokenPriceUSDForOperator(ctx sdk.Context, assetID string) (types.Price, error) { + parsedAssetID := strings.Split(assetID, "_") + if len(parsedAssetID) != 3 { + return types.Price{}, types.ErrGetPriceAssetNotFound + } + assetID = strings.Join([]string{parsedAssetID[0], parsedAssetID[1]}, "_") + operatorAddr := parsedAssetID[2] + + store := ctx.KVStore(k.storeKey) + key := types.NativeTokenOperatorKey(assetID, operatorAddr) + value := store.Get(key) + if value == nil { + return types.Price{}, types.ErrGetPriceAssetNotFound + } + operatorInfo := &types.OperatorInfo{} + k.cdc.MustUnmarshal(value, operatorInfo) + baseTokenUSDPrice, err := k.GetSpecifiedAssetsPrice(ctx, assetstypes.GetBaseTokenForNativeToken(assetID)) + if err != nil { + return types.Price{}, types.ErrGetPriceAssetNotFound + } + operatorPriceFloat := getLatestOperatorPriceFloat(operatorInfo) + baseTokenUSDPrice.Value = (baseTokenUSDPrice.Value.ToLegacyDec().Mul(operatorPriceFloat)).RoundInt() + return baseTokenUSDPrice, nil +} + +func (k Keeper) GetStakerList(ctx sdk.Context, assetID string) types.StakerList { + store := ctx.KVStore(k.storeKey) + value := store.Get(types.NativeTokenStakerListKey(assetID)) + if value == nil { + return types.StakerList{} + } + stakerList := &types.StakerList{} + k.cdc.MustUnmarshal(value, stakerList) + return *stakerList +} + +func (k Keeper) UpdateNativeTokenByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error { + if len(rawData) < 32 { + return errors.New("length of indicate maps for stakers shoule be exactly 32 bytes") + } + sl := k.getStakerList(ctx, assetID) + if len(sl.StakerAddrs) == 0 { + return errors.New("staker list is empty") + } + stakerChanges, err := parseBalanceChange(rawData, sl) + if err != nil { + return err + } + store := ctx.KVStore(k.storeKey) + for stakerAddr, change := range stakerChanges { + key := types.NativeTokenStakerKey(assetID, stakerAddr) + value := store.Get(key) + if value == nil { + return errors.New("stakerInfo does not exist") + } + stakerInfo := &types.StakerInfo{} + k.cdc.MustUnmarshal(value, stakerInfo) + changeOriginalFloat := sdkmath.LegacyNewDec(int64(change)) + totalAmountFloat, totalAmountOriginalFloat := parseStakerAmountInt(stakerInfo.TotalDeposit, stakerInfo) + totalAmountOriginalFloat = totalAmountOriginalFloat.Add(changeOriginalFloat) + prevStakerPrice := getLatestStakerPriceFloat(stakerInfo) + // update staker price based on beacon chain effective balance change + stakerPrice := totalAmountOriginalFloat.Quo(totalAmountFloat) + stakerInfo.PriceList = append(stakerInfo.PriceList, &types.PriceInfo{ + Price: stakerPrice, + Block: uint64(ctx.BlockHeight()), + RoundID: roundID, + }) + bz := k.cdc.MustMarshal(stakerInfo) + store.Set(key, bz) + // update related operator's price + keyStakerDelegations := types.NativeTokenStakerDelegationKey(assetID, stakerAddr) + value = store.Get(keyStakerDelegations) + if value != nil { + delegationInfo := &types.StakerDelegationInfo{} + k.cdc.MustUnmarshal(value, delegationInfo) + for _, delegation := range delegationInfo.Delegations { + keyOperator := types.NativeTokenOperatorKey(assetID, delegation.OperatorAddr) + value = store.Get(keyOperator) + if value == nil { + panic("staker delegation related to operator not exists") + } + operatorInfo := &types.OperatorInfo{} + k.cdc.MustUnmarshal(value, operatorInfo) + AmountFloat, prevAmountOriginalFloat := getOperatorAmountFloat(operatorInfo) + delta := delegation.Amount.ToLegacyDec().Mul(stakerPrice.Sub(prevStakerPrice)) + operatorInfo.PriceList = append(operatorInfo.PriceList, &types.PriceInfo{ + Price: prevAmountOriginalFloat.Add(delta).Quo(AmountFloat), + Block: uint64(ctx.BlockHeight()), + RoundID: roundID, + }) + bz := k.cdc.MustMarshal(operatorInfo) + store.Set(keyOperator, bz) + } + + } + + } + return nil +} + +func (k Keeper) getStakerList(ctx sdk.Context, assetID string) types.StakerList { + if len(stakerList.StakerAddrs) == 0 { + stakerList = k.GetStakerList(ctx, assetID) + } + return stakerList +} + +func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, error) { + indexs := rawData[:32] + changes := rawData[32:] + index := -1 + byteIndex := 0 + bitOffset := 0 + lengthBits := 5 + stakerChanges := make(map[string]int) + for _, b := range indexs { + for i := 7; i >= 0; i-- { + index++ + if (b>>i)&1 == 1 { + lenValue := changes[byteIndex] << bitOffset + bitsLeft := 8 - bitOffset + lenValue >>= (8 - lengthBits) + if bitsLeft < lengthBits { + byteIndex++ + lenValue |= changes[byteIndex] >> (8 - lengthBits + bitsLeft) + bitOffset = lengthBits - bitsLeft + } else { + if bitOffset += lengthBits; bitOffset == 8 { + bitOffset = 0 + } + if bitsLeft == lengthBits { + byteIndex++ + } + } + + symbol := lenValue & 1 + lenValue >>= 1 + if lenValue <= 0 { + return stakerChanges, errors.New("length of change value must be at least 1 bit") + } + + bitsExtracted := 0 + stakerChange := 0 + for bitsExtracted < int(lenValue) { + bitsLeft := 8 - bitOffset + byteValue := changes[byteIndex] << bitOffset + if (int(lenValue) - bitsExtracted) < bitsLeft { + bitsLeft = int(lenValue) - bitsExtracted + bitOffset += bitsLeft + } else { + byteIndex++ + bitOffset = 0 + } + byteValue >>= (8 - bitsLeft) + stakerChange = (stakerChange << bitsLeft) | int(byteValue) + bitsExtracted += bitsLeft + } + stakerChange++ + if symbol == 1 { + stakerChange *= -1 + } + stakerChanges[sl.StakerAddrs[index]] = stakerChange + } + } + } + return stakerChanges, nil +} + +// func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, error) { +// indexs := rawData[:32] +// changes := rawData[32:] +// // lenChanges := len(changes) +// index := -1 +// byteIndex := -1 +// bitOffset := 5 +// stakerChanges := make(map[string]int) +// for _, b := range indexs { +// for i := 7; i >= 0; i-- { +// // staker's index start from 1 +// index++ +// if (b>>i)&1 == 1 { +// // effect balance f stakerAddr[index] has changed +// lenValue := int(changes[byteIndex] >> 4) +// if lenValue <= 0 { +// return stakerChanges, errors.New("length of change value must be at least 1 bit") +// } +// symbol := (changes[byteIndex] >> 3) & 1 +// bitsExtracted := 0 +// stakerChange := 0 +// for j := 0; j < lenValue; j++ { +// byteIndex++ +// byteValue := changes[byteIndex] << bitOffset +// // byteValue <<= bitOffset +// bitsLeft := 8 - bitOffset +// if bitsExtracted+bitsLeft > lenValue { +// bitsLeft = lenValue - bitsExtracted +// bitOffset = bitsLeft +// } else { +// bitOffset = 0 +// } +// byteValue = (byteValue >> (8 - bitsLeft)) & ((1 << bitsLeft) - 1) +// stakerChange = (stakerChange << bitsLeft) | int(byteValue) +// } +// if symbol == 1 { +// stakerChange *= -1 +// } +// stakerChanges[sl.StakerAddrs[index]] = stakerChange +// } +// } +// } +// return stakerChanges, nil +// } + +func getLatestOperatorPriceFloat(operatorInfo *types.OperatorInfo) sdkmath.LegacyDec { + latestIndex := len(operatorInfo.PriceList) - 1 + return operatorInfo.PriceList[latestIndex].Price +} + +func getLatestStakerPriceFloat(stakerInfo *types.StakerInfo) sdkmath.LegacyDec { + latestIndex := len(stakerInfo.PriceList) - 1 + return stakerInfo.PriceList[latestIndex].Price +} + +func convertAmountOriginalIntToAmountFloat(amount sdkmath.Int, price sdkmath.LegacyDec) sdkmath.LegacyDec { + amountFloat := amount.ToLegacyDec() + return amountFloat.Quo(price) +} + +func getOperatorAmountFloat(operatorInfo *types.OperatorInfo) (amountFloat, amountOriginalFloat sdkmath.LegacyDec) { + latestIndexOperator := len(operatorInfo.PriceList) - 1 + price := operatorInfo.PriceList[latestIndexOperator].Price + amountFloat = operatorInfo.TotalAmount.ToLegacyDec() + amountOriginalFloat = amountFloat.Mul(price) + return +} + +func parseStakerAmountInt(amount sdkmath.Int, stakerInfo *types.StakerInfo) (amountFloat, amountOriginalFloat sdkmath.LegacyDec) { + latestIndex := len(stakerInfo.PriceList) - 1 + price := stakerInfo.PriceList[latestIndex].Price + amountFloat = amount.ToLegacyDec() + amountOriginalFloat = amountFloat.Mul(price) + return +} + +func parseStakerAmountOriginalInt(amountOriginalInt sdkmath.Int, stakerInfo *types.StakerInfo) (amountFloat, amountOriginalFloat sdkmath.LegacyDec) { + latestIndex := len(stakerInfo.PriceList) - 1 + price := stakerInfo.PriceList[latestIndex].Price + amountOriginalFloat = amountOriginalInt.ToLegacyDec() + amountFloat = amountOriginalFloat.Quo(price) + return +} diff --git a/x/oracle/keeper/native_token_test.go b/x/oracle/keeper/native_token_test.go new file mode 100644 index 000000000..c1d393f51 --- /dev/null +++ b/x/oracle/keeper/native_token_test.go @@ -0,0 +1,396 @@ +package keeper_test + +import ( + "encoding/binary" + "strings" + + sdkmath "cosmossdk.io/math" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" + "github.com/ExocoreNetwork/exocore/x/oracle/types" + "github.com/ethereum/go-ethereum/common" + "github.com/imroc/biu" +) + +// workflow: +// 1. Deposit. into staker_A +// 1. stakerInfo {totalDeposit, price} - new +// 2. stakerList - new +// +// 2. Delegate. into operator_A +// 1. stakerDelegation_AA {amount, operator} - new +// 2. operatorInfo_A {totalAmount, price} - new +// +// 3. Msg. minus staker_A's amountOriginal +// 1. stakerInfo_A {price-change} - update +// 2. operatorInfo_A {price-change} - update +// +// 4. Deposit more. into staker_A +// 1. stakerInfo {totalDeposit-change} -update +// +// 5. Msg. add staker_A's amountOriginal +// 1. stakerInfo_A {price-change} - update +// 2. operatorInfo_A {price-change} - update +// +// 6. delegate into operator_A +// 1. stakerDelegation_AA {amount-change} - update +// 2. operatorInfo_A {totalAmount-change} - update +// +// 7. Undelegate from operator_A +// 1. stakerDelegation_AA {amount-chagne} - update +// 2. operatorInfo_A {price-change, totalAmount-change} - update +// +// 8. UndelegateAll from operator_A +// 1. stakerDelegation_AA item-removed +// 2. operatorInfo_A totalAmount->0-> operatorInfo removed +// +// 9. withdrawAll from staker_A +// 1. stakerInfo removed +// 2. stakerList removed + +func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() { + operator := ks.Operators[0] + operatorStr := operator.String() + stakerStr := common.Address(operator.Bytes()).String() + assetID := assetstypes.NativeETHAssetID + // 1. deposit amount 100 + amount100 := sdkmath.NewIntFromUint64(100) + ks.k.UpdateNativeTokenByDepositOrWithdraw(ks.ctx, assetID, stakerStr, amount100) + // - 1.1 check stakerInfo + stakerInfo := ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) + ks.Equal(stakerInfo.TotalDeposit, amount100) + // - 1.2 check stakerList + stakerList := ks.k.GetStakerList(ks.ctx, assetID) + ks.Equal(stakerList.StakerAddrs[0], stakerStr) + // 2. delegateTo operator with amount 80 + amount80 := sdkmath.NewIntFromUint64(80) + ks.k.UpdateNativeTokenByDelegation(ks.ctx, assetID, operatorStr, stakerStr, amount80) + // - 2.1 check stakerDelegatioin + stakerDelegation := ks.k.GetStakerDelegations(ks.ctx, assetID, stakerStr) + ks.Equal(len(stakerDelegation.Delegations), 1) + ks.Equal(stakerDelegation.Delegations[0].OperatorAddr, operatorStr) + ks.Equal(stakerDelegation.Delegations[0].Amount, amount80) + // - 2.2 check operatorInfo + operatorInfo := ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(operatorInfo, types.OperatorInfo{ + OperatorAddr: operatorStr, + TotalAmount: amount80, + PriceList: []*types.PriceInfo{ + { + Price: sdkmath.LegacyNewDec(1), + Block: 2, + RoundID: 0, + }, + }, + }) + // 3. Msg. minus staker's amountOriginal + stakerChanges := [][]int{ + {0, -50}, + } + rawData := convertBalanceChangeToBytes(stakerChanges) + ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 9) + // - 3.1 check stakerInfo + stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) + ks.Equal(stakerInfo.PriceList[len(stakerInfo.PriceList)-1].Price, sdkmath.LegacyNewDecWithPrec(5, 1)) + // - 3.2 check operatorInfo + operatorInfo = ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(operatorInfo.PriceList[len(operatorInfo.PriceList)-1].Price, sdkmath.LegacyNewDecWithPrec(5, 1)) + ks.Equal(operatorInfo.PriceList[len(operatorInfo.PriceList)-1].RoundID, uint64(9)) + + // 4. deposit more. 100 + ks.k.UpdateNativeTokenByDepositOrWithdraw(ks.ctx, assetID, stakerStr, amount100) + // - 4.1 check stakerInfo + stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) + amount300 := sdkmath.NewInt(300) + ks.Equal(stakerInfo.TotalDeposit, amount300) + // 5. Msg. add staker's amountOriginal + stakerChanges = [][]int{ + {0, 30}, + } + rawData = convertBalanceChangeToBytes(stakerChanges) + ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 11) + // - 5.1 check stakerInfo + stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) + ks.Equal(types.PriceInfo{ + Price: sdkmath.LegacyNewDecWithPrec(6, 1), + Block: 2, + RoundID: 11, + }, *stakerInfo.PriceList[2]) + ks.Equal(amount300, stakerInfo.TotalDeposit) + // - 5.2 check operatorInfo + operatorInfo = ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(sdkmath.LegacyNewDecWithPrec(6, 1), operatorInfo.PriceList[len(operatorInfo.PriceList)-1].Price) + + // 6. delegate more. 60->100 + amount60 := sdkmath.NewInt(60) + ks.k.UpdateNativeTokenByDelegation(ks.ctx, assetID, operatorStr, stakerStr, amount60) + // - 6.1 check delegation-record + stakerDelegation = ks.k.GetStakerDelegations(ks.ctx, assetID, stakerStr) + amount180 := sdkmath.NewInt(180) + ks.Equal(amount180, stakerDelegation.Delegations[0].Amount) + // - 6.2 check operatorInfo + operatorInfo = ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(amount180, operatorInfo.TotalAmount) + + // 7. undelegate. 72->120 + amount72N := sdkmath.NewInt(-72) + ks.k.UpdateNativeTokenByDelegation(ks.ctx, assetID, operatorStr, stakerStr, amount72N) + // - 7.1 check delegation-record + stakerDelegation = ks.k.GetStakerDelegations(ks.ctx, assetID, stakerStr) + ks.Equal(amount60, stakerDelegation.Delegations[0].Amount) + // - 7.2 check operatorInfo + operatorInfo = ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(amount60, operatorInfo.TotalAmount) + + // 8. undelegate all + amount36N := sdkmath.NewInt(-36) + ks.k.UpdateNativeTokenByDelegation(ks.ctx, assetID, operatorStr, stakerStr, amount36N) + // - 8.1 check delegation-record + stakerDelegation = ks.k.GetStakerDelegations(ks.ctx, assetID, stakerStr) + ks.Equal(0, len(stakerDelegation.Delegations)) + // - 8.2 check operatorInfo + operatorInfo = ks.k.GetOperatorInfo(ks.ctx, assetID, operatorStr) + ks.Equal(types.OperatorInfo{}, operatorInfo) + + // 9. withdraw all + amount180N := sdkmath.NewInt(-180) + ks.k.UpdateNativeTokenByDepositOrWithdraw(ks.ctx, assetID, stakerStr, amount180N) + // - 9.1 check stakerInfo + stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) + ks.Equal(types.StakerInfo{}, stakerInfo) + // - 9.2 check stakerList + stakerList = ks.k.GetStakerList(ks.ctx, assetID) + ks.Equal(0, len(stakerList.StakerAddrs)) +} + +func convertBalanceChangeToBytes(stakerChanges [][]int) []byte { + if len(stakerChanges) == 0 { + return nil + } + str := "" + index := 0 + changeBytesList := make([][]byte, 0, len(stakerChanges)) + bitsList := make([]int, 0, len(stakerChanges)) + for _, stakerChange := range stakerChanges { + str += strings.Repeat("0", stakerChange[0]-index) + "1" + index = stakerChange[0] + 1 + + // change amount -> bytes + change := stakerChange[1] + var changeBytes []byte + symbol := 1 + if change < 0 { + symbol = -1 + change *= -1 + } + change-- + bits := 0 + if change == 0 { + bits = 1 + changeBytes = []byte{byte(0)} + } else { + tmpChange := change + for tmpChange > 0 { + bits++ + tmpChange /= 2 + } + if change < 256 { + // 1 byte + changeBytes = []byte{byte(change)} + changeBytes[0] <<= (8 - bits) + } else { + // 2 byte + changeBytes = make([]byte, 2) + binary.BigEndian.PutUint16(changeBytes, uint16(change)) + moveLength := 16 - bits + changeBytes[0] <<= moveLength + tmp := changeBytes[1] >> (8 - moveLength) + changeBytes[0] |= tmp + changeBytes[1] <<= moveLength + } + } + + // use lower 4 bits to represent the length of valid change value in bits format + bitsLengthBytes := []byte{byte(bits)} + bitsLengthBytes[0] <<= 4 + if symbol < 0 { + bitsLengthBytes[0] |= 8 + } + + tmp := changeBytes[0] >> 5 + bitsLengthBytes[0] |= tmp + if bits <= 3 { + changeBytes = nil + } else { + changeBytes[0] <<= 3 + } + + if len(changeBytes) == 2 { + tmp = changeBytes[1] >> 5 + changeBytes[0] |= tmp + if bits <= 11 { + changeBytes = changeBytes[:1] + } else { + changeBytes[1] <<= 3 + } + } + bitsLengthBytes = append(bitsLengthBytes, changeBytes...) + changeBytesList = append(changeBytesList, bitsLengthBytes) + bitsList = append(bitsList, bits) + } + + l := len(bitsList) + changeResult := changeBytesList[l-1] + bitsList[len(bitsList)-1] = bitsList[len(bitsList)-1] + 5 + for i := l - 2; i >= 0; i-- { + prev := changeBytesList[i] + + byteLength := 8 * len(prev) + bitsLength := bitsList[i] + 5 + // delta must <8 + delta := byteLength - bitsLength + if delta == 0 { + changeResult = append(prev, changeResult...) + bitsList[i] = bitsLength + bitsList[i+1] + } else { + // delta : (0,8) + tmp := changeResult[0] >> (8 - delta) + prev[len(prev)-1] |= tmp + if len(changeResult) > 1 { + for j := 1; j < len(changeResult); j++ { + changeResult[j-1] <<= delta + tmp := changeResult[j] >> (8 - delta) + changeResult[j-1] |= tmp + } + } + changeResult[len(changeResult)-1] <<= delta + left := bitsList[i+1] % 8 + if bitsList[i+1] > 0 && left == 0 { + left = 8 + } + if left <= delta { + changeResult = changeResult[:len(changeResult)-1] + } + changeResult = append(prev, changeResult...) + bitsList[i] = bitsLength + bitsList[i+1] + } + } + str += strings.Repeat("0", 256-index) + bytesIndex := biu.BinaryStringToBytes(str) + + result := append(bytesIndex, changeResult...) + return result +} + +// func convertBalanceChangeToBytes(stakerChanges [][]int) []byte { +// if len(stakerChanges) == 0 { +// return nil +// } +// str := "" +// index := 0 +// changeBytesList := make([][]byte, 0, len(stakerChanges)) +// bitsList := make([]int, 0, len(stakerChanges)) +// for _, stakerChange := range stakerChanges { +// str += strings.Repeat("0", stakerChange[0]-index) + "1" +// index = stakerChange[0] + 1 +// +// // change amount -> bytes +// change := stakerChange[1] +// var changeBytes []byte +// symbol := 1 +// if change < 0 { +// symbol = -1 +// change *= -1 +// change-- +// } +// bits := 0 +// if change == 0 { +// bits = 1 +// changeBytes = []byte{byte(0)} +// } else { +// for change > 0 { +// bits++ +// change /= 2 +// } +// if change < 256 { +// // 1 byte +// changeBytes = []byte{byte(change)} +// changeBytes[0] <<= (8 - bits) +// } else { +// // 2 byte +// changeBytes = make([]byte, 0, 2) +// binary.BigEndian.PutUint16(changeBytes, uint16(change)) +// moveLength := 16 - bits +// changeBytes[0] <<= moveLength +// tmp := changeBytes[1] >> (8 - moveLength) +// changeBytes[0] |= tmp +// changeBytes[1] <<= moveLength +// } +// } +// +// // use lower 4 bits to represent the length of valid change value in bits format +// bitsLengthBytes := []byte{byte(bits)} +// bitsLengthBytes[0] <<= 4 +// if symbol < 0 { +// bitsLengthBytes[0] |= 8 +// } +// +// tmp := changeBytes[0] >> 5 +// bitsLengthBytes[0] |= tmp +// if bits <= 3 { +// changeBytes = nil +// } else { +// changeBytes[0] <<= 3 +// } +// +// if len(changeBytes) == 2 { +// tmp = changeBytes[1] >> 5 +// changeBytes[0] |= tmp +// if bits <= 11 { +// changeBytes = changeBytes[:1] +// } else { +// changeBytes[1] <<= 3 +// } +// } +// bitsLengthBytes = append(bitsLengthBytes, changeBytes...) +// changeBytesList = append(changeBytesList, bitsLengthBytes) +// bitsList = append(bitsList, bits) +// } +// +// l := len(bitsList) +// changeResult := changeBytesList[l-1] +// bitsList[len(bitsList)-1] = bitsList[len(bitsList)-1] + 5 +// for i := l - 2; i >= 0; i-- { +// prev := changeBytesList[i] +// +// byteLength := 8 * len(prev) +// bitsLength := bitsList[i] + 5 +// // delta must <8 +// delta := byteLength - bitsLength +// if delta == 0 { +// changeResult = append(prev, changeResult...) +// bitsList[i] = bitsLength + bitsList[i+1] +// } else { +// // delta : (0,8) +// tmp := changeResult[0] >> (8 - delta) +// prev[len(prev)-1] |= tmp +// if len(changeResult) > 1 { +// for j := 1; j < len(changeResult); j++ { +// changeResult[j-1] <<= delta +// tmp := changeResult[j] >> (8 - delta) +// changeResult[j-1] |= tmp +// } +// } +// changeResult[len(changeResult)-1] <<= delta +// if bitsList[i+1]%8 <= delta { +// changeResult = changeResult[:len(changeResult)-1] +// } +// changeResult = append(prev, changeResult...) +// bitsList[i] = bitsLength + bitsList[i+1] +// } +// } +// str += strings.Repeat("0", 256-index) +// bytesIndex := biu.BinaryStringToBytes(str) +// +// result := append(bytesIndex, changeResult...) +// return result +// } diff --git a/x/oracle/keeper/prices.go b/x/oracle/keeper/prices.go index c0cc8d7dc..ef350c569 100644 --- a/x/oracle/keeper/prices.go +++ b/x/oracle/keeper/prices.go @@ -2,8 +2,10 @@ package keeper import ( "encoding/binary" + "strings" sdkmath "cosmossdk.io/math" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" "github.com/ExocoreNetwork/exocore/x/oracle/types" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -53,6 +55,10 @@ func (k Keeper) GetSpecifiedAssetsPrice(ctx sdk.Context, assetID string) (types. } else { p = k.GetParams(ctx) } + // if this asset represents for native token fetch price identified by operator + if parsedAssetID := strings.Split(assetID, "_"); len(parsedAssetID) == 3 && assetstypes.IsNativeToken(strings.Join([]string{parsedAssetID[0], parsedAssetID[1]}, "_")) { + return k.GetNativeTokenPriceUSDForOperator(ctx, assetID) + } tokenID := p.GetTokenIDFromAssetID(assetID) if tokenID == 0 { return types.Price{}, types.ErrGetPriceAssetNotFound.Wrapf("assetID does not exist in oracle %s", assetID) @@ -187,13 +193,32 @@ func (k Keeper) AppendPriceTR(ctx sdk.Context, tokenID uint64, priceTR types.Pri if expiredRoundID := nextRoundID - agc.GetParamsMaxSizePrices(); expiredRoundID > 0 { store.Delete(types.PricesRoundKey(expiredRoundID)) } - k.IncreaseNextRoundID(ctx, tokenID) + roundID := k.IncreaseNextRoundID(ctx, tokenID) + + // update for native tokens + // TODO: set hooks as a genral approach + var p types.Params + // get params from cache if exists + if agc != nil { + p = agc.GetParams() + } else { + p = k.GetParams(ctx) + } + assetIDs := p.GetAssetIDsFromTokenID(tokenID) + for _, assetID := range assetIDs { + if assetstypes.IsNativeToken(assetID) { + if err := k.UpdateNativeTokenByBalanceChange(ctx, assetID, []byte(priceTR.Price), roundID); err != nil { + // we just report this error in log to notify validators + k.Logger(ctx).Error(types.ErrUpdateNativeTokenVirtualPriceFail.Error(), "error", err) + } + } + } + return true } // GrowRoundID Increases roundID with the previous price func (k Keeper) GrowRoundID(ctx sdk.Context, tokenID uint64) (price string, roundID uint64) { - // logInfo := fmt.Sprintf("add new round with previous price under fail aggregation, tokenID:%d", tokenID) if pTR, ok := k.GetPriceTRLatest(ctx, tokenID); ok { pTR.RoundID++ k.AppendPriceTR(ctx, tokenID, pTR) @@ -259,12 +284,13 @@ func (k Keeper) GetNextRoundID(ctx sdk.Context, tokenID uint64) (nextRoundID uin } // IncreaseNextRoundID increases nextRoundID persisted by 1 of a token -func (k Keeper) IncreaseNextRoundID(ctx sdk.Context, tokenID uint64) { +func (k Keeper) IncreaseNextRoundID(ctx sdk.Context, tokenID uint64) uint64 { store := k.getPriceTRStore(ctx, tokenID) nextRoundID := k.GetNextRoundID(ctx, tokenID) b := make([]byte, 8) binary.BigEndian.PutUint64(b, nextRoundID+1) store.Set(types.PricesNextRoundIDKey, b) + return nextRoundID } func (k Keeper) getPriceTRStore(ctx sdk.Context, tokenID uint64) prefix.Store { diff --git a/x/oracle/types/errors.go b/x/oracle/types/errors.go index d45033ce4..0c3183507 100644 --- a/x/oracle/types/errors.go +++ b/x/oracle/types/errors.go @@ -13,14 +13,16 @@ const ( invalidParams getPriceFailedAssetNotFound getPriceFailedRoundNotFound + updateNativeTokenVirtualPriceFail ) // x/oracle module sentinel errors var ( - ErrInvalidMsg = sdkerrors.Register(ModuleName, invalidMsg, "invalid input create price") - ErrPriceProposalIgnored = sdkerrors.Register(ModuleName, priceProposalIgnored, "price proposal ignored") - ErrPriceProposalFormatInvalid = sdkerrors.Register(ModuleName, priceProposalFormatInvalid, "price proposal message format invalid") - ErrInvalidParams = sdkerrors.Register(ModuleName, invalidParams, "invalid params") - ErrGetPriceAssetNotFound = sdkerrors.Register(ModuleName, getPriceFailedAssetNotFound, "get price failed for asset not found") - ErrGetPriceRoundNotFound = sdkerrors.Register(ModuleName, getPriceFailedRoundNotFound, "get price failed for round not found") + ErrInvalidMsg = sdkerrors.Register(ModuleName, invalidMsg, "invalid input create price") + ErrPriceProposalIgnored = sdkerrors.Register(ModuleName, priceProposalIgnored, "price proposal ignored") + ErrPriceProposalFormatInvalid = sdkerrors.Register(ModuleName, priceProposalFormatInvalid, "price proposal message format invalid") + ErrInvalidParams = sdkerrors.Register(ModuleName, invalidParams, "invalid params") + ErrGetPriceAssetNotFound = sdkerrors.Register(ModuleName, getPriceFailedAssetNotFound, "get price failed for asset not found") + ErrGetPriceRoundNotFound = sdkerrors.Register(ModuleName, getPriceFailedRoundNotFound, "get price failed for round not found") + ErrUpdateNativeTokenVirtualPriceFail = sdkerrors.Register(ModuleName, updateNativeTokenVirtualPriceFail, "update native token balance change failed") ) diff --git a/x/oracle/types/key_native_token.go b/x/oracle/types/key_native_token.go new file mode 100644 index 000000000..1ea037a87 --- /dev/null +++ b/x/oracle/types/key_native_token.go @@ -0,0 +1,32 @@ +package types + +import "strings" + +const ( + // NativeTokenKeyPrefix is the prefix to retrieve all NativeToken + NativeTokenKeyPrefix = "NativeToken/" + NativeTokenPriceKeyPrefix = NativeTokenKeyPrefix + "price/value/" + NativeTokenStakerInfoKeyPrefix = NativeTokenKeyPrefix + "stakerInfo/value/" + NativeTokenOperatorInfoKeyPrefix = NativeTokenKeyPrefix + "operatorInfo/value/" + NativeTokenStakerListKeyPrefix = NativeTokenKeyPrefix + "stakerList/value/" + NativeTokenStakerDelegationKeyPrefix = NativeTokenKeyPrefix + "stakerDelegation/value/" +) + +func NativeTokenStakerDelegationKey(assetID, stakerAddr string) []byte { + assetID = strings.Join([]string{assetID, stakerAddr}, "/") + return append([]byte(NativeTokenStakerDelegationKeyPrefix), []byte(assetID)...) +} + +func NativeTokenStakerListKey(assetID string) []byte { + return append([]byte(NativeTokenStakerListKeyPrefix), []byte(assetID)...) +} + +func NativeTokenStakerKey(assetID, stakerAddr string) []byte { + assetID = strings.Join([]string{assetID, stakerAddr}, "/") + return append([]byte(NativeTokenStakerInfoKeyPrefix), []byte(assetID)...) +} + +func NativeTokenOperatorKey(assetID, operatorAddr string) []byte { + assetID = strings.Join([]string{assetID, operatorAddr}, "/") + return append([]byte(NativeTokenOperatorInfoKeyPrefix), []byte(assetID)...) +} diff --git a/x/oracle/types/keys.go b/x/oracle/types/keys.go index 140564af9..2f329bc03 100644 --- a/x/oracle/types/keys.go +++ b/x/oracle/types/keys.go @@ -12,26 +12,19 @@ const ( // MemStoreKey defines the in-memory store key MemStoreKey = "mem_oracle" -) - -var ParamsKey = []byte{0x11} - -func KeyPrefix(p string) []byte { - return []byte(p) -} -const ( + // TODO: rename for prefix and keys ValidatorsKey = "Validators/value/" -) -const ( ValidatorUpdateBlockKey = "ValidatorUpdateBlock/value/" -) -const ( IndexRecentParamsKey = "IndexRecentParams/value/" -) -const ( IndexRecentMsgKey = "IndexRecentMsg/value/" ) + +var ParamsKey = []byte{0x11} + +func KeyPrefix(p string) []byte { + return []byte(p) +} diff --git a/x/oracle/types/native_token.go b/x/oracle/types/native_token.go new file mode 100644 index 000000000..e9b591c96 --- /dev/null +++ b/x/oracle/types/native_token.go @@ -0,0 +1,39 @@ +package types + +import sdkmath "cosmossdk.io/math" + +// TODO: vlaidatorIndex need bridge data +// func NewStakerInfo(stakerAddr string, validatorIndex uint64) *StakerInfo { +func NewStakerInfo(stakerAddr string) *StakerInfo { + return &StakerInfo{ + StakerAddr: stakerAddr, + StakerIndex: 0, + // TODO: need bridge information + // ValidatorIndexs: []uint64{validatorIndex}, + ValidatorIndexs: make([]uint64, 0, 1), + TotalDeposit: sdkmath.NewInt(0), + PriceList: []*PriceInfo{ + { + // default price should be 1 + Price: sdkmath.LegacyNewDec(1), + Block: 0, + RoundID: 0, + }, + }, + } +} + +func NewOperatorInfo(operatorAddr string) *OperatorInfo { + return &OperatorInfo{ + OperatorAddr: operatorAddr, + TotalAmount: sdkmath.NewInt(0), + PriceList: []*PriceInfo{ + { + // default price should be 1 + Price: sdkmath.LegacyNewDec(1), + Block: 0, + RoundID: 0, + }, + }, + } +} diff --git a/x/oracle/types/native_token.pb.go b/x/oracle/types/native_token.pb.go new file mode 100644 index 000000000..cdce2c0a0 --- /dev/null +++ b/x/oracle/types/native_token.pb.go @@ -0,0 +1,1915 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/oracle/v1/native_token.proto + +package types + +import ( + cosmossdk_io_math "cosmossdk.io/math" + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type PriceInfo struct { + Price cosmossdk_io_math.LegacyDec `protobuf:"bytes,1,opt,name=price,proto3,customtype=cosmossdk.io/math.LegacyDec" json:"price"` + Block uint64 `protobuf:"varint,2,opt,name=block,proto3" json:"block,omitempty"` + RoundID uint64 `protobuf:"varint,3,opt,name=round_id,json=roundId,proto3" json:"round_id,omitempty"` +} + +func (m *PriceInfo) Reset() { *m = PriceInfo{} } +func (m *PriceInfo) String() string { return proto.CompactTextString(m) } +func (*PriceInfo) ProtoMessage() {} +func (*PriceInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{0} +} +func (m *PriceInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PriceInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PriceInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PriceInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_PriceInfo.Merge(m, src) +} +func (m *PriceInfo) XXX_Size() int { + return m.Size() +} +func (m *PriceInfo) XXX_DiscardUnknown() { + xxx_messageInfo_PriceInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_PriceInfo proto.InternalMessageInfo + +func (m *PriceInfo) GetBlock() uint64 { + if m != nil { + return m.Block + } + return 0 +} + +func (m *PriceInfo) GetRoundID() uint64 { + if m != nil { + return m.RoundID + } + return 0 +} + +type OperatorInfo struct { + OperatorAddr string `protobuf:"bytes,1,opt,name=operator_addr,json=operatorAddr,proto3" json:"operator_addr,omitempty"` + TotalAmount cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=total_amount,json=totalAmount,proto3,customtype=cosmossdk.io/math.Int" json:"total_amount"` + PriceList []*PriceInfo `protobuf:"bytes,3,rep,name=price_list,json=priceList,proto3" json:"price_list,omitempty"` +} + +func (m *OperatorInfo) Reset() { *m = OperatorInfo{} } +func (m *OperatorInfo) String() string { return proto.CompactTextString(m) } +func (*OperatorInfo) ProtoMessage() {} +func (*OperatorInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{1} +} +func (m *OperatorInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *OperatorInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_OperatorInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *OperatorInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_OperatorInfo.Merge(m, src) +} +func (m *OperatorInfo) XXX_Size() int { + return m.Size() +} +func (m *OperatorInfo) XXX_DiscardUnknown() { + xxx_messageInfo_OperatorInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_OperatorInfo proto.InternalMessageInfo + +func (m *OperatorInfo) GetOperatorAddr() string { + if m != nil { + return m.OperatorAddr + } + return "" +} + +func (m *OperatorInfo) GetPriceList() []*PriceInfo { + if m != nil { + return m.PriceList + } + return nil +} + +type StakerInfo struct { + StakerAddr string `protobuf:"bytes,1,opt,name=staker_addr,json=stakerAddr,proto3" json:"staker_addr,omitempty"` + StakerIndex int64 `protobuf:"varint,2,opt,name=staker_index,json=stakerIndex,proto3" json:"staker_index,omitempty"` + ValidatorIndexs []uint64 `protobuf:"varint,3,rep,packed,name=validator_indexs,json=validatorIndexs,proto3" json:"validator_indexs,omitempty"` + TotalDeposit cosmossdk_io_math.Int `protobuf:"bytes,4,opt,name=total_deposit,json=totalDeposit,proto3,customtype=cosmossdk.io/math.Int" json:"total_deposit"` + PriceList []*PriceInfo `protobuf:"bytes,5,rep,name=price_list,json=priceList,proto3" json:"price_list,omitempty"` +} + +func (m *StakerInfo) Reset() { *m = StakerInfo{} } +func (m *StakerInfo) String() string { return proto.CompactTextString(m) } +func (*StakerInfo) ProtoMessage() {} +func (*StakerInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{2} +} +func (m *StakerInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakerInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakerInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakerInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakerInfo.Merge(m, src) +} +func (m *StakerInfo) XXX_Size() int { + return m.Size() +} +func (m *StakerInfo) XXX_DiscardUnknown() { + xxx_messageInfo_StakerInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_StakerInfo proto.InternalMessageInfo + +func (m *StakerInfo) GetStakerAddr() string { + if m != nil { + return m.StakerAddr + } + return "" +} + +func (m *StakerInfo) GetStakerIndex() int64 { + if m != nil { + return m.StakerIndex + } + return 0 +} + +func (m *StakerInfo) GetValidatorIndexs() []uint64 { + if m != nil { + return m.ValidatorIndexs + } + return nil +} + +func (m *StakerInfo) GetPriceList() []*PriceInfo { + if m != nil { + return m.PriceList + } + return nil +} + +type NativeTokenPrice struct { + Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` + PreceList []*PriceInfo `protobuf:"bytes,2,rep,name=prece_list,json=preceList,proto3" json:"prece_list,omitempty"` +} + +func (m *NativeTokenPrice) Reset() { *m = NativeTokenPrice{} } +func (m *NativeTokenPrice) String() string { return proto.CompactTextString(m) } +func (*NativeTokenPrice) ProtoMessage() {} +func (*NativeTokenPrice) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{3} +} +func (m *NativeTokenPrice) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *NativeTokenPrice) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_NativeTokenPrice.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *NativeTokenPrice) XXX_Merge(src proto.Message) { + xxx_messageInfo_NativeTokenPrice.Merge(m, src) +} +func (m *NativeTokenPrice) XXX_Size() int { + return m.Size() +} +func (m *NativeTokenPrice) XXX_DiscardUnknown() { + xxx_messageInfo_NativeTokenPrice.DiscardUnknown(m) +} + +var xxx_messageInfo_NativeTokenPrice proto.InternalMessageInfo + +func (m *NativeTokenPrice) GetToken() string { + if m != nil { + return m.Token + } + return "" +} + +func (m *NativeTokenPrice) GetPreceList() []*PriceInfo { + if m != nil { + return m.PreceList + } + return nil +} + +type StakerList struct { + StakerAddrs []string `protobuf:"bytes,1,rep,name=staker_addrs,json=stakerAddrs,proto3" json:"staker_addrs,omitempty"` +} + +func (m *StakerList) Reset() { *m = StakerList{} } +func (m *StakerList) String() string { return proto.CompactTextString(m) } +func (*StakerList) ProtoMessage() {} +func (*StakerList) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{4} +} +func (m *StakerList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakerList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakerList.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakerList) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakerList.Merge(m, src) +} +func (m *StakerList) XXX_Size() int { + return m.Size() +} +func (m *StakerList) XXX_DiscardUnknown() { + xxx_messageInfo_StakerList.DiscardUnknown(m) +} + +var xxx_messageInfo_StakerList proto.InternalMessageInfo + +func (m *StakerList) GetStakerAddrs() []string { + if m != nil { + return m.StakerAddrs + } + return nil +} + +type DelegationInfo struct { + OperatorAddr string `protobuf:"bytes,1,opt,name=operator_addr,json=operatorAddr,proto3" json:"operator_addr,omitempty"` + Amount cosmossdk_io_math.Int `protobuf:"bytes,2,opt,name=amount,proto3,customtype=cosmossdk.io/math.Int" json:"amount"` +} + +func (m *DelegationInfo) Reset() { *m = DelegationInfo{} } +func (m *DelegationInfo) String() string { return proto.CompactTextString(m) } +func (*DelegationInfo) ProtoMessage() {} +func (*DelegationInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{5} +} +func (m *DelegationInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *DelegationInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_DelegationInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *DelegationInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_DelegationInfo.Merge(m, src) +} +func (m *DelegationInfo) XXX_Size() int { + return m.Size() +} +func (m *DelegationInfo) XXX_DiscardUnknown() { + xxx_messageInfo_DelegationInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_DelegationInfo proto.InternalMessageInfo + +func (m *DelegationInfo) GetOperatorAddr() string { + if m != nil { + return m.OperatorAddr + } + return "" +} + +type StakerDelegationInfo struct { + Delegations []*DelegationInfo `protobuf:"bytes,1,rep,name=delegations,proto3" json:"delegations,omitempty"` +} + +func (m *StakerDelegationInfo) Reset() { *m = StakerDelegationInfo{} } +func (m *StakerDelegationInfo) String() string { return proto.CompactTextString(m) } +func (*StakerDelegationInfo) ProtoMessage() {} +func (*StakerDelegationInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_ed348d855b8fd9a8, []int{6} +} +func (m *StakerDelegationInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *StakerDelegationInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_StakerDelegationInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *StakerDelegationInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_StakerDelegationInfo.Merge(m, src) +} +func (m *StakerDelegationInfo) XXX_Size() int { + return m.Size() +} +func (m *StakerDelegationInfo) XXX_DiscardUnknown() { + xxx_messageInfo_StakerDelegationInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_StakerDelegationInfo proto.InternalMessageInfo + +func (m *StakerDelegationInfo) GetDelegations() []*DelegationInfo { + if m != nil { + return m.Delegations + } + return nil +} + +func init() { + proto.RegisterType((*PriceInfo)(nil), "exocore.oracle.v1.PriceInfo") + proto.RegisterType((*OperatorInfo)(nil), "exocore.oracle.v1.OperatorInfo") + proto.RegisterType((*StakerInfo)(nil), "exocore.oracle.v1.StakerInfo") + proto.RegisterType((*NativeTokenPrice)(nil), "exocore.oracle.v1.NativeTokenPrice") + proto.RegisterType((*StakerList)(nil), "exocore.oracle.v1.StakerList") + proto.RegisterType((*DelegationInfo)(nil), "exocore.oracle.v1.DelegationInfo") + proto.RegisterType((*StakerDelegationInfo)(nil), "exocore.oracle.v1.StakerDelegationInfo") +} + +func init() { + proto.RegisterFile("exocore/oracle/v1/native_token.proto", fileDescriptor_ed348d855b8fd9a8) +} + +var fileDescriptor_ed348d855b8fd9a8 = []byte{ + // 550 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x6f, 0xd3, 0x40, + 0x10, 0x8d, 0x9b, 0xa6, 0x25, 0xe3, 0x14, 0x8a, 0x15, 0x24, 0x8b, 0x0f, 0x27, 0x4d, 0x11, 0x0a, + 0x17, 0x9b, 0x16, 0x71, 0x40, 0x5c, 0x68, 0x08, 0x87, 0xa0, 0xaa, 0x54, 0x86, 0x13, 0x1c, 0xa2, + 0x8d, 0x77, 0x49, 0x57, 0x71, 0x3c, 0xd1, 0xee, 0x26, 0xa4, 0x77, 0x7e, 0x00, 0xbf, 0x85, 0x5f, + 0xd1, 0x63, 0x8f, 0x88, 0x43, 0x84, 0x92, 0xbf, 0xc1, 0x01, 0x79, 0xd7, 0x8e, 0x42, 0xcb, 0x21, + 0xbd, 0x65, 0x66, 0xde, 0xcb, 0xbc, 0xf7, 0x34, 0x5e, 0x78, 0xcc, 0xa6, 0x18, 0xa1, 0x60, 0x01, + 0x0a, 0x12, 0xc5, 0x2c, 0x98, 0x1c, 0x04, 0x09, 0x51, 0x7c, 0xc2, 0xba, 0x0a, 0x07, 0x2c, 0xf1, + 0x47, 0x02, 0x15, 0x3a, 0x77, 0x33, 0x94, 0x6f, 0x50, 0xfe, 0xe4, 0xe0, 0x7e, 0xb5, 0x8f, 0x7d, + 0xd4, 0xd3, 0x20, 0xfd, 0x65, 0x80, 0x8d, 0x6f, 0x16, 0x94, 0x4f, 0x05, 0x8f, 0x58, 0x27, 0xf9, + 0x82, 0xce, 0x4b, 0x28, 0x8d, 0xd2, 0xc2, 0xb5, 0xea, 0x56, 0xb3, 0xdc, 0xda, 0xbf, 0x98, 0xd5, + 0x0a, 0xbf, 0x66, 0xb5, 0x07, 0x11, 0xca, 0x21, 0x4a, 0x49, 0x07, 0x3e, 0xc7, 0x60, 0x48, 0xd4, + 0x99, 0x7f, 0xcc, 0xfa, 0x24, 0x3a, 0x6f, 0xb3, 0x28, 0x34, 0x0c, 0xa7, 0x0a, 0xa5, 0x5e, 0x8c, + 0xd1, 0xc0, 0xdd, 0xa8, 0x5b, 0xcd, 0xcd, 0xd0, 0x14, 0xce, 0x13, 0xb8, 0x25, 0x70, 0x9c, 0xd0, + 0x2e, 0xa7, 0x6e, 0x31, 0x1d, 0xb4, 0xec, 0xf9, 0xac, 0xb6, 0x1d, 0xa6, 0xbd, 0x4e, 0x3b, 0xdc, + 0xd6, 0xc3, 0x0e, 0x6d, 0xfc, 0xb0, 0xa0, 0xf2, 0x7e, 0xc4, 0x04, 0x51, 0x28, 0xb4, 0x92, 0x7d, + 0xd8, 0xc1, 0xac, 0xee, 0x12, 0x4a, 0x85, 0x51, 0x14, 0x56, 0xf2, 0xe6, 0x11, 0xa5, 0xc2, 0x79, + 0x0d, 0x15, 0x85, 0x8a, 0xc4, 0x5d, 0x32, 0xc4, 0x71, 0xa2, 0xf4, 0xea, 0x72, 0xeb, 0x51, 0xa6, + 0xfa, 0xde, 0x75, 0xd5, 0x9d, 0x44, 0x85, 0xb6, 0xa6, 0x1c, 0x69, 0x86, 0xf3, 0x0a, 0x40, 0xcb, + 0xef, 0xc6, 0x5c, 0x2a, 0xb7, 0x58, 0x2f, 0x36, 0xed, 0xc3, 0x87, 0xfe, 0xb5, 0xf0, 0xfc, 0x65, + 0x44, 0x61, 0x59, 0xe3, 0x8f, 0xb9, 0x54, 0x8d, 0x3f, 0x16, 0xc0, 0x07, 0x45, 0x06, 0xcc, 0x48, + 0xae, 0x81, 0x2d, 0x75, 0xb5, 0x2a, 0x18, 0x4c, 0x4b, 0xcb, 0xdd, 0x83, 0x4a, 0x06, 0xe0, 0x09, + 0x65, 0x53, 0x2d, 0xb7, 0x18, 0x66, 0xa4, 0x4e, 0xda, 0x72, 0x9e, 0xc2, 0xee, 0x84, 0xc4, 0x9c, + 0x6a, 0xdf, 0x1a, 0x25, 0xb5, 0xaa, 0xcd, 0xf0, 0xce, 0xb2, 0xaf, 0x91, 0xd2, 0x69, 0xc1, 0x8e, + 0x31, 0x4f, 0xd9, 0x08, 0x25, 0x57, 0xee, 0xe6, 0x3a, 0xee, 0x4d, 0x60, 0x6d, 0x43, 0xb9, 0x62, + 0xbf, 0x74, 0x33, 0xfb, 0x0c, 0x76, 0x4f, 0xf4, 0xe5, 0x7d, 0x4c, 0x0f, 0xef, 0x34, 0xbf, 0x02, + 0x7d, 0x86, 0x99, 0x7b, 0x53, 0x98, 0x35, 0x2c, 0x5f, 0xb3, 0xb1, 0xde, 0x1a, 0x96, 0xad, 0x09, + 0xf2, 0x90, 0xd3, 0x6a, 0x25, 0xc3, 0x34, 0x64, 0xe9, 0x5a, 0xf5, 0x62, 0xb3, 0x9c, 0x67, 0x98, + 0xa6, 0x2c, 0x1b, 0x31, 0xdc, 0x6e, 0xb3, 0x98, 0xf5, 0x89, 0xe2, 0x98, 0xac, 0x7f, 0x4c, 0x2f, + 0x60, 0xeb, 0x26, 0x67, 0x94, 0x81, 0x1b, 0x9f, 0xa1, 0x6a, 0xe4, 0x5d, 0xd9, 0xf9, 0x06, 0x6c, + 0xba, 0xec, 0x18, 0x9d, 0xf6, 0xe1, 0xde, 0x7f, 0x4c, 0xff, 0xcb, 0x0b, 0x57, 0x59, 0xad, 0x77, + 0x17, 0x73, 0xcf, 0xba, 0x9c, 0x7b, 0xd6, 0xef, 0xb9, 0x67, 0x7d, 0x5f, 0x78, 0x85, 0xcb, 0x85, + 0x57, 0xf8, 0xb9, 0xf0, 0x0a, 0x9f, 0x9e, 0xf5, 0xb9, 0x3a, 0x1b, 0xf7, 0xfc, 0x08, 0x87, 0xc1, + 0x5b, 0xf3, 0x9f, 0x27, 0x4c, 0x7d, 0x45, 0x31, 0x08, 0xf2, 0x07, 0x62, 0x9a, 0x3f, 0x11, 0xea, + 0x7c, 0xc4, 0x64, 0x6f, 0x4b, 0x7f, 0xf0, 0xcf, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xdb, 0xb2, + 0xeb, 0x4b, 0x41, 0x04, 0x00, 0x00, +} + +func (m *PriceInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PriceInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PriceInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.RoundID != 0 { + i = encodeVarintNativeToken(dAtA, i, uint64(m.RoundID)) + i-- + dAtA[i] = 0x18 + } + if m.Block != 0 { + i = encodeVarintNativeToken(dAtA, i, uint64(m.Block)) + i-- + dAtA[i] = 0x10 + } + { + size := m.Price.Size() + i -= size + if _, err := m.Price.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func (m *OperatorInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *OperatorInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *OperatorInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PriceList) > 0 { + for iNdEx := len(m.PriceList) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PriceList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + { + size := m.TotalAmount.Size() + i -= size + if _, err := m.TotalAmount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.OperatorAddr) > 0 { + i -= len(m.OperatorAddr) + copy(dAtA[i:], m.OperatorAddr) + i = encodeVarintNativeToken(dAtA, i, uint64(len(m.OperatorAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakerInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakerInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakerInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PriceList) > 0 { + for iNdEx := len(m.PriceList) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PriceList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + } + } + { + size := m.TotalDeposit.Size() + i -= size + if _, err := m.TotalDeposit.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + if len(m.ValidatorIndexs) > 0 { + dAtA2 := make([]byte, len(m.ValidatorIndexs)*10) + var j1 int + for _, num := range m.ValidatorIndexs { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintNativeToken(dAtA, i, uint64(j1)) + i-- + dAtA[i] = 0x1a + } + if m.StakerIndex != 0 { + i = encodeVarintNativeToken(dAtA, i, uint64(m.StakerIndex)) + i-- + dAtA[i] = 0x10 + } + if len(m.StakerAddr) > 0 { + i -= len(m.StakerAddr) + copy(dAtA[i:], m.StakerAddr) + i = encodeVarintNativeToken(dAtA, i, uint64(len(m.StakerAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *NativeTokenPrice) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *NativeTokenPrice) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *NativeTokenPrice) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.PreceList) > 0 { + for iNdEx := len(m.PreceList) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.PreceList[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.Token) > 0 { + i -= len(m.Token) + copy(dAtA[i:], m.Token) + i = encodeVarintNativeToken(dAtA, i, uint64(len(m.Token))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakerList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakerList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakerList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.StakerAddrs) > 0 { + for iNdEx := len(m.StakerAddrs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.StakerAddrs[iNdEx]) + copy(dAtA[i:], m.StakerAddrs[iNdEx]) + i = encodeVarintNativeToken(dAtA, i, uint64(len(m.StakerAddrs[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *DelegationInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *DelegationInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *DelegationInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size := m.Amount.Size() + i -= size + if _, err := m.Amount.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.OperatorAddr) > 0 { + i -= len(m.OperatorAddr) + copy(dAtA[i:], m.OperatorAddr) + i = encodeVarintNativeToken(dAtA, i, uint64(len(m.OperatorAddr))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *StakerDelegationInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *StakerDelegationInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *StakerDelegationInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Delegations) > 0 { + for iNdEx := len(m.Delegations) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Delegations[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintNativeToken(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func encodeVarintNativeToken(dAtA []byte, offset int, v uint64) int { + offset -= sovNativeToken(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PriceInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Price.Size() + n += 1 + l + sovNativeToken(uint64(l)) + if m.Block != 0 { + n += 1 + sovNativeToken(uint64(m.Block)) + } + if m.RoundID != 0 { + n += 1 + sovNativeToken(uint64(m.RoundID)) + } + return n +} + +func (m *OperatorInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddr) + if l > 0 { + n += 1 + l + sovNativeToken(uint64(l)) + } + l = m.TotalAmount.Size() + n += 1 + l + sovNativeToken(uint64(l)) + if len(m.PriceList) > 0 { + for _, e := range m.PriceList { + l = e.Size() + n += 1 + l + sovNativeToken(uint64(l)) + } + } + return n +} + +func (m *StakerInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.StakerAddr) + if l > 0 { + n += 1 + l + sovNativeToken(uint64(l)) + } + if m.StakerIndex != 0 { + n += 1 + sovNativeToken(uint64(m.StakerIndex)) + } + if len(m.ValidatorIndexs) > 0 { + l = 0 + for _, e := range m.ValidatorIndexs { + l += sovNativeToken(uint64(e)) + } + n += 1 + sovNativeToken(uint64(l)) + l + } + l = m.TotalDeposit.Size() + n += 1 + l + sovNativeToken(uint64(l)) + if len(m.PriceList) > 0 { + for _, e := range m.PriceList { + l = e.Size() + n += 1 + l + sovNativeToken(uint64(l)) + } + } + return n +} + +func (m *NativeTokenPrice) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Token) + if l > 0 { + n += 1 + l + sovNativeToken(uint64(l)) + } + if len(m.PreceList) > 0 { + for _, e := range m.PreceList { + l = e.Size() + n += 1 + l + sovNativeToken(uint64(l)) + } + } + return n +} + +func (m *StakerList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.StakerAddrs) > 0 { + for _, s := range m.StakerAddrs { + l = len(s) + n += 1 + l + sovNativeToken(uint64(l)) + } + } + return n +} + +func (m *DelegationInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddr) + if l > 0 { + n += 1 + l + sovNativeToken(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovNativeToken(uint64(l)) + return n +} + +func (m *StakerDelegationInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Delegations) > 0 { + for _, e := range m.Delegations { + l = e.Size() + n += 1 + l + sovNativeToken(uint64(l)) + } + } + return n +} + +func sovNativeToken(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozNativeToken(x uint64) (n int) { + return sovNativeToken(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PriceInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PriceInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PriceInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Price", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Price.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Block", wireType) + } + m.Block = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Block |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RoundID", wireType) + } + m.RoundID = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RoundID |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *OperatorInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: OperatorInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: OperatorInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalAmount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PriceList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PriceList = append(m.PriceList, &PriceInfo{}) + if err := m.PriceList[len(m.PriceList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakerInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakerInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakerInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerIndex", wireType) + } + m.StakerIndex = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.StakerIndex |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ValidatorIndexs = append(m.ValidatorIndexs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.ValidatorIndexs) == 0 { + m.ValidatorIndexs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ValidatorIndexs = append(m.ValidatorIndexs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorIndexs", wireType) + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalDeposit", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.TotalDeposit.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PriceList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PriceList = append(m.PriceList, &PriceInfo{}) + if err := m.PriceList[len(m.PriceList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *NativeTokenPrice) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: NativeTokenPrice: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: NativeTokenPrice: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Token = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PreceList", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PreceList = append(m.PreceList, &PriceInfo{}) + if err := m.PreceList[len(m.PreceList)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakerList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakerList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakerList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field StakerAddrs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.StakerAddrs = append(m.StakerAddrs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *DelegationInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: DelegationInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: DelegationInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *StakerDelegationInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: StakerDelegationInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: StakerDelegationInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Delegations", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowNativeToken + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthNativeToken + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthNativeToken + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Delegations = append(m.Delegations, &DelegationInfo{}) + if err := m.Delegations[len(m.Delegations)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipNativeToken(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthNativeToken + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipNativeToken(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowNativeToken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowNativeToken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowNativeToken + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthNativeToken + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupNativeToken + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthNativeToken + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthNativeToken = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowNativeToken = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupNativeToken = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/oracle/types/params.go b/x/oracle/types/params.go index fc29e449f..d4c096428 100644 --- a/x/oracle/types/params.go +++ b/x/oracle/types/params.go @@ -493,6 +493,13 @@ func (p Params) GetTokenIDFromAssetID(assetID string) int { return 0 } +func (p Params) GetAssetIDsFromTokenID(tokenID uint64) []string { + if tokenID >= uint64(len(p.Tokens)) { + return nil + } + return strings.Split(p.Tokens[tokenID].AssetID, ",") +} + func (p Params) IsDeterministicSource(sourceID uint64) bool { return p.Sources[sourceID].Deterministic }