Skip to content

Commit

Permalink
gwx reward refreshUserReward
Browse files Browse the repository at this point in the history
  • Loading branch information
ridev6 committed Aug 7, 2023
1 parent 5832b71 commit 1778379
Show file tree
Hide file tree
Showing 2 changed files with 515 additions and 80 deletions.
144 changes: 64 additions & 80 deletions ride/gwx_reward.ride
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,12 @@
# * "%s%s__config__referralsContractAddress": String
# * "%s__latestPeriod": Integer

# TODO: seems like we can use keyGwxRewardEmissionStartHeight for integral start height

let SEP = "__"
let SCALE = 1000
let MULT8 = 1_0000_0000
let zeroBigInt = 0.toBigInt()
let processingStageTotal = 0
let processingStageShares = 1
let MULT18 = 1_000_000_000_000_000_000
let MULT18BI = MULT18.toBigInt()

let wavesString = "WAVES"

Expand Down Expand Up @@ -260,56 +256,6 @@ func mustManager(i: Invocation) = {
}
}

func keyRewardPerGwxIntegral() = ["%s", "rewardPerGwxIntegral"].makeString(SEP)

# call when reward or total gwx amount are changed
func refreshRewardPerGwxIntegral() = {
# rewardPerGwx = dh * emissionPerBlock / totalGwxAmount + rewardPerGwxPrevious
let rewardPerGwxIntegralPrevious = {
match this.getString(keyRewardPerGwxIntegral()) {
case s: String => s.parseBigInt()
case _: Unit => unit
}
}.valueOrElse(zeroBigInt)
let rewardPerGwxIntegralLastHeight = this.getInteger(keyGwxRewardEmissionStartHeight())
.valueOrErrorMessage(wrapErr("invalid " + keyGwxRewardEmissionStartHeight()))
let emissionRate = emissionContract.getInteger(keyRatePerBlockCurrent())
.valueOrErrorMessage(wrapErr("invalid " + keyRatePerBlockCurrent()))
let gwxHoldersRewardCurrent = emissionContract.getInteger(keyGwxHoldersRewardCurrent())
.valueOrElse(0)
let gwxAmountTotal = boostingContractOrFail().invoke("getGwxTotalREADONLY", [], []).exactAs[Int]
let dh = { height - rewardPerGwxIntegralLastHeight }.toBigInt()
let rewardPerGwxIntegral = rewardPerGwxIntegralPrevious + fraction(
dh,
emissionRate.toBigInt() * gwxHoldersRewardCurrent.toBigInt() * MULT18BI,
gwxAmountTotal.toBigInt()
)

(
[
IntegerEntry(keyGwxRewardEmissionStartHeight(), height),
StringEntry(keyRewardPerGwxIntegral(), rewardPerGwxIntegral.toString())
],
rewardPerGwxIntegral
)
}

func keyRewardPerGwxIntegralUserLast(userAddress: Address) = ["%s%s", "rewardPerGwxIntegralUserLast", userAddress.toString()].makeString(SEP)

# call when user total gwx amount is changed
func refreshUserReward(userAddress: Address) = {
let rewardPerGwxIntegralUserLast = {
match this.getString(keyRewardPerGwxIntegralUserLast(userAddress)) {
case s: String => s.parseBigInt()
case _: Unit => unit
}
}.valueOrElse(zeroBigInt)

# userReward = userGwxAmount * (rewardPerGwxIntegral - rewardPerGwxIntegralUserLast) + userRewardPrevious - userRewardClaimed

unit
}

# user's weight = k * height + b, scaled by 10^8
func calcUserWeight(boostingContractAddress: Address, heightForPeriod: Int, period: Int, userIndex: Int) = {
let kLast = keyLastProcessedPeriodOfUser(userIndex)
Expand Down Expand Up @@ -545,33 +491,17 @@ func deposit() = {
@Callable(i)
func claimReward() = {
let cfgArray = readConfigArrayOrFail()
let userAddress = i.caller
let userAddressStr = userAddress.toString()
let (amountLegacy, actionsLegacy) = commonClaimReward(userAddressStr)
# TODO: calculate using integrals
let amount = 0
strict checkAmount = amount + amountLegacy > 0 || "nothing to claim".throw()

let userGwxAmount = boostingContractOrFail().invoke("getUserGwxAmount", [userAddressStr], []).exactAs[Int]
let referrer = referralsContractAddressOrFail.getString(userAddressStr.keyReferrer())
strict activeReferralInv = if (referrer == unit) then unit else {
referralsContractAddressOrFail.invoke("updateReferralActivity", [referralProgramName, userAddress, userGwxAmount >= referralMinGWxAmount], [])
}
strict referralInv = if (referrer == unit || userGwxAmount < referralMinGWxAmount) then unit else {
let referrerReward = amount.fraction(referrerRewardPermille, SCALE)
let referralReward = amount.fraction(referralRewardPermille, SCALE)
referralsContractAddressOrFail.invoke("incUnclaimed", [referralProgramName, userAddress, referrerReward, referralReward], [])
}

strict claimedReferral = referralsContractAddressOrFail.invoke("claim", [referralProgramName], []).exactAs[Int]
let address = i.caller.toString()
let (amount, actions) = commonClaimReward(address)
strict checkAmount = amount > 0 || "Nothing to claim".throw()
# remove if unused
let amountFromEmission = 0
let claimedReferral = referralsContractAddressOrFail.invoke("claim", [referralProgramName], []).exactAs[Int]
let totalAmount = amount + claimedReferral
(
[
ScriptTransfer(i.caller, amount, cfgArray[IdxCfgAssetId].fromBase58String()),
HistoryEntry("claim", userAddressStr, totalAmount, i)
] ++ actionsLegacy,
totalAmount
)
([
ScriptTransfer(i.caller, totalAmount, cfgArray[IdxCfgAssetId].fromBase58String()),
HistoryEntry("claim", address, amount, i)
] ++ actions, [totalAmount, amountFromEmission])
}

# returns total claimable reward by user address
Expand Down Expand Up @@ -627,6 +557,60 @@ func latestPeriodEmissionRewardsREADONLY(address: String) = {
([], [getNumberByKey(keyAuxEmissionRewardForPeriod(period))])
}

# LP Math

# D invariant calculation iteratively for 2 tokens
#
# A * sum(x_i) * n^n + D = A * D * n^n + D^(n+1) / (n^n * prod(x_i))
#
# Converging solution:
# D[j+1] = (A * n^n * sum(x_i) - D[j]^(n+1) / (n^n prod(x_i))) / (A * n^n - 1)
@Callable(i)
func calcD(
x1BigIntStr: String,
x2BigIntStr: String,
ampBigIntStr: String,
aPrecisionBigIntStr: String,
targetPrecisionBigIntStr: String
) = {
let nCoins = 2.toBigInt()
let aPrecision = aPrecisionBigIntStr.parseBigIntValue()
let targetPrecision = targetPrecisionBigIntStr.parseBigIntValue()
let x1 = x1BigIntStr.parseBigIntValue()
let x2 = x2BigIntStr.parseBigIntValue()
let amp = ampBigIntStr.parseBigIntValue() * aPrecision
let s = x1 + x2
if (s == zeroBigInt) then {
([], zeroBigInt.toString())
} else {
let ann = amp * nCoins
let arr = [0, 1, 2, 3, 4, 5, 6]
func calc(acc: (BigInt, BigInt|Unit, Int|Unit), cur: Int) = {
let (d, dPrev, found) = acc
if (found != unit) then acc else {
# dp0 = d
# dp1 = dp0 * d / (x1 * nCoins)
# dp2 = dp1 * d / (x2 * nCoins) = (dp0 * d / (x1 * nCoins)) * d / (x2 * nCoins) = d^3 / (x1 * x2 * nCoins^2)
let dp = d * d * d / (x1 * x2 * nCoins * nCoins)
let dNext = (ann * s / aPrecision + dp * nCoins) * d / ((ann - aPrecision) * d / aPrecision + (nCoins + 1.toBigInt()) * dp)
let dDiff = absBigInt(dNext - d.value())
if (dDiff <= targetPrecision) then {
(dNext, d, cur)
} else {
(dNext, d, unit)
}
}
}
let (dNext, dPrev, found) = FOLD<7>(arr, (s, unit, unit), calc)
if (found != unit) then {
([], dNext.toString())
} else {
let dDiff = { dNext - dPrev.value() }.absBigInt()
{ "D calculation error, dDiff = " + dDiff.toString() }.throw()
}
}
}

@Callable(i)
func tradeReward(userAddresses: List[String], rewards: List[Int]) = {
let argsComparison = userAddresses.size() == rewards.size()
Expand Down
Loading

0 comments on commit 1778379

Please sign in to comment.