Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

refactor(staker): add in-range staked liquidity tracker #438

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pool/pool.gno
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,8 @@ func tickTransition(step StepComputations, zeroForOne bool, state SwapState, poo
newState.liquidity = liquidityMathAddDelta(state.liquidity, liquidityNet)
}

pool.tickCrossHook(GetPoolPath(pool.token0Path, pool.token1Path, pool.fee), step.tickNext, zeroForOne)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you stack tickNext at this point, you're stacking the value before the change. If you want to stack the history of the change with tickTransition, it's better to record the updated tick in newState.tick.

if zeroForOne {
newState.tick = step.tickNext - 1
} else {
Expand Down
2 changes: 2 additions & 0 deletions pool/type.gno
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,8 @@ type Pool struct {
tickBitmaps TickBitmaps // maps tick index to tick bitmap

positions Positions // maps the key (caller, lower tick, upper tick) to a unique position

tickCrossHook func(poolPath string, tickId int32, zeroForOne bool)
r3v4s marked this conversation as resolved.
Show resolved Hide resolved
}

func newPool(poolInfo *createPoolParams) *Pool {
Expand Down
18 changes: 4 additions & 14 deletions staker/calculate_pool_position_reward.gno
Original file line number Diff line number Diff line change
Expand Up @@ -238,20 +238,10 @@ func CalcPoolPosition() {

// calculate each pool's total staked liquidity
poolTotalStakedLiquidity = make(map[string]*u256.Uint) // clear
for tokenId, deposit := range deposits {
poolPath := deposit.targetPoolPath
if _, exist := poolTotalStakedLiquidity[poolPath]; !exist {
poolTotalStakedLiquidity[poolPath] = u256.Zero()
}

isInRange := pn.PositionIsInRange(tokenId)
if isInRange == false {
continue
}

liqStr := pn.PositionGetPositionLiquidityStr(tokenId)
positionLiquidity := u256.MustFromDecimal(liqStr)
poolTotalStakedLiquidity[poolPath] = poolTotalStakedLiquidity[poolPath].Add(poolTotalStakedLiquidity[poolPath], positionLiquidity)
// FIXME: temporarily iterate all pools.
// after refactoring is complete, it will be removed
for poolPath, info := range stakerPoolInfo {
poolTotalStakedLiquidity[poolPath] = info.totalStakedLiquidityInRange
}

// calculate each position's liquidity ratio
Expand Down
81 changes: 81 additions & 0 deletions staker/staker.gno
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ var (
/* common */
// deposits stores deposit information for each tokenId
deposits map[uint64]Deposit = make(map[uint64]Deposit)

// depositOperations map[uint64][]DepositOperation = make(map[uint64][]DepositOperation)
)

const (
Expand Down Expand Up @@ -135,6 +137,8 @@ func StakeToken(tokenId uint64) (string, string, string) {
// after transfer, set caller(user) as position operator (to collect fee and reward)
pn.SetPositionOperator(tokenId, caller)

modifyStakerPoolInfo(poolPath, tokenId, liquidity)

token0Amount, token1Amount := getTokenPairBalanceFromPosition(tokenId)

prevAddr, prevRealm := getPrev()
Expand Down Expand Up @@ -349,6 +353,8 @@ func UnstakeToken(tokenId uint64, unwrapResult bool) (string, string, string) {
poolPath := pn.PositionGetPositionPoolKey(tokenId)
token0Amount, token1Amount := getTokenPairBalanceFromPosition(tokenId)

modifyStakerPoolInfo(poolPath, tokenId, i256.Zero().Neg(liquidity))

prevAddr, prevRealm := getPrev()
std.Emit(
"UnstakeToken",
Expand Down Expand Up @@ -744,3 +750,78 @@ func getIncentives() map[string]ExternalIncentive {
func getPoolIncentives() map[string][]string {
return poolIncentives
}


// TODO: separate into different file

type StakerPoolInfo struct {
//totalStakedLiquidity *u256.Uint
totalStakedLiquidityInRange *u256.Uint
}

type StakerTickInfo struct {
liquidityInRangeDelta *u256.Uint
}

var (
stakerPoolInfo = make(map[string]StakerPoolInfo)
r3v4s marked this conversation as resolved.
Show resolved Hide resolved
stakerTickInfo = make(map[int32]StakerTickInfo)
)

func modifyStakerPoolInfo(poolPath string, tokenId uint64, liquidity *u256.Uint) {
// update staker side pool info
pool, ok := stakerPoolInfo[poolPath]
if !ok {
pool = StakerPoolInfo{
totalStakedLiquidity: u256.Zero(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The StakerPoolInfo type declaration is commented out.

totalStakedLiquidityInRange: u256.Zero(),
}
}
//pool.totalStakedLiquidity = liquidityMathAddDelta(pool.totalStakedLiquidity, liquidity)
if pn.PositionIsInRange(tokenId) {
pool.totalStakedLiquidityInRange = liquidityMathAddDelta(pool.totalStakedLiquidityInRange, liquidity)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to calculate the reward correctly, we need to distinguish when tokenId is inrange and when it is not.
Currently, the history of tokenIds records all tokenIds in deposits. I would recommend that we consider an additional ledger, depositTokenId[poolPath][tokenId], that manages all tokenId leases deposited in poolPath, and an additional ledger, inRangeTokenIdList[poolPath][tokenId], that manages inRagneTokenIds.
In some cases, it may not be an inRange, so you will need a global ledger and an inRange ledger.

}
stakerPoolInfo[poolPath] = pool

// update staker side tick info
lowerTick, ok := stakerTickInfo[pn.PositionGetPositionTickLower(tokenId)]
if !ok {
lowerTick = StakerTickInfo{
liquidityInRangeDelta: u256.Zero(),
}
}
lowerTick.liquidityInRangeDelta = liquidityMathAddDelta(lowerTick.liquidityInRangeDelta, liquidity)
stakerTickInfo[pn.PositionGetPositionTickLower(tokenId)] = lowerTick

upperTick, ok := stakerTickInfo[pn.PositionGetPositionTickUpper(tokenId)]
if !ok {
upperTick = StakerTickInfo{
liquidityInRangeDelta: u256.Zero(),
}
}
upperTick.liquidityInRangeDelta = liquidityMathAddDelta(upperTick.liquidityInRangeDelta, i256.Zero().Neg(liquidity))
stakerTickInfo[pn.PositionGetPositionTickUpper(tokenId)] = upperTick
}

func tickCrossHook(poolPath string, tickId int32, zeroForOne bool) {
tick, ok := stakerTickInfo[tickId]
if !ok {
return
}

pool, ok := stakerPoolInfo[poolPath]
if !ok {
panic(addDetailToError(
errDataNotFound,
ufmt.Sprintf("staker.gno__tickCrossHook() || poolPath(%s) not found", poolPath),
))
}

liquidityInRangeDelta := tick.liquidityInRangeDelta
if zeroForOne {
liquidityInRangeDelta = i256.Zero().Neg(liquidityInRangeDelta)
}
pool.totalStakedLiquidityInRange = liquidityMathAddDelta(pool.totalStakedLiquidityInRange, liquidityInRangeDelta)

stakerPoolInfo[poolPath] = pool
}
2 changes: 1 addition & 1 deletion staker/tier_ratio.gno
Original file line number Diff line number Diff line change
Expand Up @@ -160,4 +160,4 @@ func calcAmount(avgBlockAmountX96 *u256.Uint, dur, pct uint64) (uint64, uint64)

durAmount := new(u256.Uint).Div(durAmountX96, _q96).Uint64()
return fullAmount, durAmount
}
}
21 changes: 21 additions & 0 deletions staker/type.gno
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,24 @@ type Deposit struct {
stakeHeight int64 // staked block height
targetPoolPath string // staked position's pool path
}

type DepositOperationType uint64

const (
DEPOSIT_OPERATION_TYPE_STAKE DepositOperationType = 1
DEPOSIT_OPERATION_TYPE_FILL_30 DepositOperationType = 2
DEPOSIT_OPERATION_TYPE_FILL_50 DepositOperationType = 3
DEPOSIT_OPERATION_TYPE_FILL_70 DepositOperationType = 4
DEPOSIT_OPERATION_TYPE_FILL_100 DepositOperationType = 5
)

type DepositOperation struct {
tokenId uint64 // token id
operationType DepositOperationType // operation type
}

type DepositPrediction struct {
totalAmount uint64 // total amount

operations []DepositOperation // operations
}
Loading