πStaking and Rewards [USDA-sUSDT LP]
An overview of the contract facilitating staking and reward distributions for the USDA-sUSDT liquidity pool within the BitFlow StableSwap.
This contract is designed to facilitate staking and reward distributions for the USDA-sUSDT liquidity pool within the BitFlow StableSwap. It allows users to perform actions, including staking liquidity pool tokens and claiming rewards.
Data Storage
These structures are used to enable the contract to maintain its state, monitor information, and ensure data integrity.
reward-cycle-index
(define-constant reward-cycle-index (list u1 u2 u3 u4 u5 u6 u7 u8 u9 u10 u11 u12 u13 u14 u15 u16 u17 u18 u19 u20 u21 u22 u23 u24 u25 u26 u27 u28 u29 u30 u31 u32 u33 u34 u35 u36 u37 u38 u39 u40 u41 u42 u43 u44 u45 u46 u47 u48 u49 u50 u51 u52 u53 u54 u55 u56 u57 u58 u59 u60 u61 u62 u63 u64 u65 u66 u67 u68 u69 u70 u71 u72 u73 u74 u75 u76 u77 u78 u79 u80 u81 u82 u83 u84 u85 u86 u87 u88 u89 u90 u91 u92 u93 u94 u95 u96 u97 u98 u99 u100 u101 u102 u103 u104 u105 u106 u107 u108 u109 u110 u111 u112 u113 u114 u115 u116 u117 u118 u119 u120))
A constant list that serves as an index for iterating through reward cycles.
helper-uint
(define-data-var helper-uint uint u0)
A data variable that is used for operations related to filtering null values and mapping an index to the succeeding cycle.
helper-uint-list
(define-data-var helper-uint-list (list 12000 uint) (list ))
A data variable that is used to filter out existing cycles in the cycles-staked
list.
StakerDataMap
(define-map StakerDataMap {x-token: principal, y-token: principal, lp-token: principal, user: principal} {
cycles-staked: (list 12000 uint),
cycles-to-unstake: (list 12000 uint),
total-currently-staked: uint
})
A map that records comprehensive staking data associated with a particular principal.
StakerDataPerCycleMap
(define-map StakerDataPerCycleMap {x-token: principal, y-token: principal, lp-token: principal, user: principal, cycle: uint} {
lp-token-staked: uint,
reward-claimed: bool,
lp-token-to-unstake: uint
})
A map that records staking data for each cycle linked to a principal.
DataPerCycleMap
(define-map DataPerCycleMap {x-token: principal, y-token: principal, lp-token: principal, cycle: uint} uint)
A map that records staking data across all stakers for a specific cycle.
TotalStakedPerPairMap
(define-map TotalStakedPerPairMap {x-token: principal, y-token: principal, lp-token: principal} {total-staked: uint})
A map that tracks the total amount of LP tokens staked across all participants for a specific token pair.
Error Codes
These error codes are displayed when there's a problem executing any of the functions defined in this smart contract.
err-no-pair-data
This error code indicates that the contract could not retrieve data for the requested token pair.
err-pair-not-approved
This error code indicates that the specified token pair has not been granted the necessary approval or permissions to proceed with the action.
err-cycles-too-high
This error code indicates that the user is attempting to stake for more than 121 cycles.
err-cycles-too-low
This error code indicates that the user is attempting to stake for less than 1 cycle.
err-amount-too-low
This error code indicates that the specified amount is too low.
err-lp-token-transfer-failed
This error code indicates that an issue occurred while attempting to transfer LP tokens.
err-cycles-staked-overflow
This error code indicates that the combined list of current and new staking cycles has exceeded the maximum allowed limit of 12,000 entries.
err-cycles-to-unstake-overflow
This error code indicates that the resulting list, after appending new unstaking cycles to the current cycles, has gone beyond the permissible limit of 12,000 entries.
err-no-cycle-data
This error code indicates that an issue occurred while trying to find data for a specific cycle.
err-no-rewards-to-claim
This error code indicates that the user has no available rewards to claim.
err-rewards-already-claimed
This error code indicates that the user has already claimed their rewards.
err-cycle-too-high
This error code occurs when the user tries to claim staking rewards from the current cycle.
err-y-token-transfer-failed
This error code indicates that an issue occurred while attempting to transfer token Y
.
err-x-token-transfer-failed
This error code indicates that an issue occurred while attempting to transfer token X
.
err-no-staker-data
This error code indicates that the user has no available staking data.
err-no-total-staked-per-pair
This error code indicates that an issue occurred while attempting to calculate the total amount staked for a specified token pair.
err-no-lp-tokens-to-unstake
This error code indicates that there are no LP tokens to unstake.
err-failed-to-transfer-lp-tokens
This error code indicates that an issue occurred while attempting to transfer LP tokens.
Public Functions
These functions can be accessed by external contracts or users, allowing for interaction with the contract and modification of its state.
stake-lp-tokens
(define-public (stake-lp-tokens (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <og-sip-010-trait>) (cycles uint) (amount uint))
(let
(
(current-staker-data (map-get? StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender}))
(current-cycles-staked (default-to (list ) (get cycles-staked current-staker-data)))
(current-cycles-to-unstake (default-to (list ) (get cycles-to-unstake current-staker-data)))
(updated-helper-uint-to-filter (var-set helper-uint cycles))
(filtered-null-list (filter filter-null-value reward-cycle-index))
(current-cycle (contract-call? .stableswap-usda-susdt get-current-cycle))
(updated-helper-uint-to-map (var-set helper-uint current-cycle))
(next-cycles (map map-filtered-null-list filtered-null-list))
(updated-helper-uint-list-current-cycles (var-set helper-uint-list current-cycles-staked))
(next-cycles-not-in-current-cycles (filter filter-list next-cycles))
(unstake-cycle (+ u1 (+ current-cycle cycles)))
(is-unstakeable-block-in-unstakeable-cycles (is-some (index-of current-cycles-to-unstake unstake-cycle)))
(current-all-staker-data (map-get? DataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), cycle: current-cycle}))
(pair-data (unwrap! (contract-call? .stableswap-usda-susdt get-pair-data x-token y-token lp-token) (err "err-no-pair-data")))
(total-currently-staked-data (default-to {total-staked: u0} (map-get? TotalStakedPerPairMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token)})))
(total-currently-staked-in-contract (get total-staked total-currently-staked-data))
(approved-pair (get approval pair-data))
)
;; Assert that pair is approved
(asserts! approved-pair (err "err-pair-not-approved"))
;; Assert that cycles is less than 121
(asserts! (< cycles u121) (err "err-cycles-too-high"))
;; Assert that cycles is greater than 0
(asserts! (> cycles u0) (err "err-cycles-too-low"))
;; Assert that amount is greater than 0
(asserts! (> amount u0) (err "err-amount-too-low"))
;; Transfer LP tokens from user to contract
(unwrap! (contract-call? lp-token transfer amount tx-sender (as-contract tx-sender) none) (err "err-lp-token-transfer-failed"))
;; Update lp-tokens-staked in the appropriate cycles
(fold update-staker-data-per-cycle-fold next-cycles {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), cycles-staked: current-cycles-staked, amount: amount})
;; Updating the total balance of LP tokens staked in this contract
(map-set TotalStakedPerPairMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token)} {total-staked: (+ total-currently-staked-in-contract amount)})
;; Update StakerDataMap
(if (is-some current-staker-data)
;; Staker already exists, update cycles-staked list
(map-set StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender} {
cycles-staked: (unwrap! (as-max-len? (concat current-cycles-staked next-cycles-not-in-current-cycles) u12000) (err "err-cycles-staked-overflow")),
cycles-to-unstake: (if is-unstakeable-block-in-unstakeable-cycles
;; Unstakeable cycle already exists, don't update cycles-to-unstake list
current-cycles-to-unstake
;; Unstakeable cycle doesn't exist, update cycles-to-unstake list
(unwrap! (as-max-len? (concat current-cycles-to-unstake (list unstake-cycle)) u12000) (err "err-cycles-to-unstake-overflow"))
),
total-currently-staked: (+ amount (default-to u0 (get total-currently-staked current-staker-data)))
})
;; Staker doesn't exist, create new staker
(map-set StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender} {
cycles-staked: next-cycles,
cycles-to-unstake: (list unstake-cycle),
total-currently-staked: amount
})
)
;; Update unstakeable lp-token StakerDataMap
(ok (if (is-some (map-get? StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender, cycle: unstake-cycle}))
;; Staker already exists, only update lp-token-to-unstake
(map-set StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender, cycle: unstake-cycle} (merge
(default-to { lp-token-staked: u0, reward-claimed: false, lp-token-to-unstake: u0} (map-get? StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender, cycle: unstake-cycle}))
{lp-token-to-unstake: (+ amount (default-to u0 (get lp-token-to-unstake (map-get? StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender, cycle: unstake-cycle}))))}
))
;; Staker doesn't exist, create new entry
(map-set StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender, cycle: unstake-cycle} {
lp-token-staked: u0,
reward-claimed: false,
lp-token-to-unstake: amount
})
))
)
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
og-sip-010-trait
cycles
uint
amount
uint
A public function that allows a user to stake liquidity provider (LP) tokens for a given number of cycles. The process begins by retrieving the current data of the staker, such as the cycles they've staked and those they wish to unstake in. After a series of checks (ensuring the staking pair is approved, validating the number of cycles, and verifying the staking amount), the function transfers the LP tokens from the user to the contract. The LP token amount is then updated for the appropriate cycles. Finally, the staking data is updated for the user, detailing the cycles they've staked in, the amount, and the time at which they can unstake.
claim-cycle-staking-rewards
(define-public (claim-cycle-staking-rewards (x-token principal) (y-token principal) (lp-token principal) (x-token-trait <og-sip-010-trait>) (y-token-trait <susdt-sip-010-trait>) (lp-token-trait <og-sip-010-trait>) (cycle uint))
(let
(
(current-cycle (contract-call? .stableswap-usda-susdt get-current-cycle))
(param-cycle-user-data (unwrap! (map-get? StakerDataPerCycleMap {x-token: x-token, y-token: y-token, lp-token: lp-token, user: tx-sender, cycle: cycle}) (err "err-no-cycle-data")))
(param-cycle-reward-claimed (get reward-claimed param-cycle-user-data))
(param-cycle-user-lp-staked (get lp-token-staked param-cycle-user-data))
(param-cycle-total-lp-staked (unwrap! (map-get? DataPerCycleMap {x-token: x-token, y-token: y-token, lp-token: lp-token, cycle: cycle}) (err "err-no-cycle-data")))
(param-cycle-fees (unwrap! (contract-call? .stableswap-usda-susdt get-cycle-data x-token y-token lp-token cycle) (err "err-no-cycle-data")))
(param-cycle-balance-x-fee (get cycle-fee-balance-x param-cycle-fees))
(param-cycle-balance-y-fee (get cycle-fee-balance-y param-cycle-fees))
(param-cycle-x-rewards (/ (* param-cycle-balance-x-fee param-cycle-user-lp-staked) param-cycle-total-lp-staked))
(param-cycle-y-rewards (/ (* param-cycle-balance-y-fee param-cycle-user-lp-staked) param-cycle-total-lp-staked))
(claimer tx-sender)
)
;; Assert that param-cycle-x or param-cycle-y rewards are greater than 0
(asserts! (or (> param-cycle-x-rewards u0) (> param-cycle-y-rewards u0)) (err "err-no-rewards-to-claim"))
;; Assert that param-cycle-reward-claimed is false
(asserts! (not param-cycle-reward-claimed) (err "err-rewards-already-claimed"))
;; Assert that claiming from a previous cycle
(asserts! (< cycle current-cycle) (err "err-cycle-too-high"))
;; Check if one of the param-cycle-x or param-cycle-y rewards is equal to 0
(if (or (is-eq param-cycle-balance-x-fee u0) (is-eq param-cycle-balance-y-fee u0))
;; One of them is equal to 0, only transfer the other
(if (is-eq param-cycle-balance-x-fee u0)
;; param-cycle-x-rewards is equal to 0, transfer param-cycle-y-rewards from contract to user
(unwrap! (as-contract (contract-call? y-token-trait transfer param-cycle-y-rewards tx-sender claimer none)) (err "err-y-token-transfer-failed"))
;; param-cycle-y-rewards is equal to 0, transfer param-cycle-x-rewards from contract to user
(unwrap! (as-contract (contract-call? x-token-trait transfer param-cycle-x-rewards tx-sender claimer none)) (err "err-x-token-transfer-failed"))
)
;; Neither of them are equal to 0, transfer both
(begin
;; Transfer param-cycle-x-rewards from contract to user
(unwrap! (as-contract (contract-call? x-token-trait transfer param-cycle-x-rewards tx-sender claimer none)) (err "err-x-token-transfer-failed"))
;; Transfer param-cycle-y-rewards from contract to user
(unwrap! (as-contract (contract-call? y-token-trait transfer param-cycle-y-rewards tx-sender claimer none)) (err "err-y-token-transfer-failed"))
)
)
;; Update StakerDataPerCycleMap with reward-claimed = true
(map-set StakerDataPerCycleMap {x-token: x-token, y-token: y-token, lp-token: lp-token, user: claimer, cycle: cycle} (merge
param-cycle-user-data
{reward-claimed: true}
))
(ok {x-token-reward: param-cycle-x-rewards, y-token-reward: param-cycle-y-rewards})
)
)
Parameter
Type
x-token
principal
y-token
principal
lp-token
principal
x-token-trait
og-sip-010-trait
y-token-trait
susdt-sip-010-trait
lp-token-trait
og-sip-010-trait
cycle
uint
A public function that allows a user to claim staking rewards for a specific cycle. Initially, it gathers necessary data about the current cycle, rewards, and fees. Various assertions are made to ensure rewards exist for the specified cycle and that the rewards haven't been claimed previously. After these checks, the function determines whether the user is eligible for either x-token
or y-token
rewards (or both). The eligible rewards are transferred from the contract to the user, and the user's claim status for the cycle is updated to reflect that the rewards have been claimed.
claim-all-staking-rewards
(define-public (claim-all-staking-rewards (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <og-sip-010-trait>))
(let
(
(current-cycle (contract-call? .stableswap-usda-susdt get-current-cycle))
(current-cycle-helper (var-set helper-uint current-cycle))
(current-staker-data (unwrap! (map-get? StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender}) (err "err-no-staker-data")))
(current-cycles-staked (get cycles-staked current-staker-data))
(rewards-to-claim (fold fold-from-all-cycles-to-cycles-unclaimed current-cycles-staked {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), total-rewards-x: u0, total-rewards-y: u0, current-cycle: current-cycle}))
(rewards-to-claim-x (get total-rewards-x rewards-to-claim))
(rewards-to-claim-y (get total-rewards-y rewards-to-claim))
(claimer tx-sender)
)
;; Check if one of the param-cycle-x or param-cycle-y rewards is equal to 0
(ok (if (or (is-eq rewards-to-claim-x u0) (is-eq rewards-to-claim-y u0))
;; One of them is equal to 0, only transfer the other
(if (is-eq rewards-to-claim-x u0)
;; param-cycle-x-rewards is equal to 0, transfer param-cycle-y-rewards from contract to user
(unwrap! (as-contract (contract-call? y-token transfer rewards-to-claim-y tx-sender claimer none)) (err "err-y-token-transfer-failed"))
;; param-cycle-y-rewards is equal to 0, transfer param-cycle-x-rewards from contract to user
(unwrap! (as-contract (contract-call? x-token transfer rewards-to-claim-x tx-sender claimer none)) (err "err-x-token-transfer-failed"))
)
;; Neither of them are equal to 0, transfer both
(begin
;; Transfer param-cycle-x-rewards from contract to user
(unwrap! (as-contract (contract-call? x-token transfer rewards-to-claim-x tx-sender claimer none)) (err "err-x-token-transfer-failed"))
;; Transfer param-cycle-y-rewards from contract to user
(unwrap! (as-contract (contract-call? y-token transfer rewards-to-claim-y tx-sender claimer none)) (err "err-y-token-transfer-failed"))
)
)
)
)
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
og-sip-010-trait
A public function that facilitates the claiming of all staking rewards by the user for all the cycles up to the current one. The function starts by fetching the current cycle and staker data, including the cycles the user has staked in. It then calculates the total rewards the user is eligible to claim for both x-token
and y-token
. If the rewards for either x-token
or y-token
are zero, the function will transfer only the non-zero rewards to the user. Otherwise, both rewards are transferred to the user.
unstake-all-lp-tokens
(define-public (unstake-all-lp-tokens (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <og-sip-010-trait>))
(let
(
(liquidity-provider tx-sender)
(current-cycle (contract-call? .stableswap-usda-susdt get-current-cycle))
(current-cycle-helper (var-set helper-uint current-cycle))
(current-staker-data (unwrap! (map-get? StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender}) (err "err-no-staker-data")))
(current-cycles-to-unstake (get cycles-to-unstake current-staker-data))
(current-staked-by-unstaker (get total-currently-staked current-staker-data))
(total-currently-staked-data (unwrap! (map-get? TotalStakedPerPairMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token)}) (err "err-no-total-staked-per-pair")))
(total-currently-staked-in-contract (get total-staked total-currently-staked-data))
(unstake-data (fold fold-from-all-cycles-to-unstakeable-cycles current-cycles-to-unstake {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), total-lps-to-unstake: u0, current-cycles-to-unstake: current-cycles-to-unstake}))
(lp-tokens-to-unstake (get total-lps-to-unstake unstake-data))
(updated-total-currently-staked (- total-currently-staked-in-contract lp-tokens-to-unstake))
(updated-total-currently-staked-by-unstaker (- current-staked-by-unstaker lp-tokens-to-unstake))
(updated-current-cycles-to-unstake (get current-cycles-to-unstake unstake-data))
)
(asserts! (> lp-tokens-to-unstake u0) (err "err-no-lp-tokens-to-unstake"))
;; Transfer LP tokens to unstake from the contract to the user
(unwrap! (as-contract (contract-call? lp-token transfer lp-tokens-to-unstake tx-sender liquidity-provider none)) (err "err-failed-to-transfer-lp-tokens"))
(map-set StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: tx-sender} (merge
current-staker-data
{total-currently-staked: updated-total-currently-staked-by-unstaker, cycles-to-unstake: updated-current-cycles-to-unstake}
))
;; Updating the total balance of LP tokens staked in this contract
(map-set TotalStakedPerPairMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token)} {total-staked: updated-total-currently-staked})
(ok lp-tokens-to-unstake)
)
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
og-sip-010-trait
A public function that enables a liquidity provider to fully unstake their liquidity pool (LP) tokens from a specified token pair. By taking the x-token
, y-token
, and lp-token
as parameters, it first ascertains the current staking cycle and extracts the relevant staker data. It calculates the total LP tokens available for unstaking, making sure there's a non-zero amount, and then transfers these tokens from the contract back to the user. Post withdrawal, the function updates both the user's staking data and the global staked LP token count.
Private Functions
These functions are confined to the contract in which they are defined, ensuring encapsulation and restricting external access to certain functionalities.
filter-null-value
(define-private (filter-null-value (value uint))
(if (<= value (var-get helper-uint))
true
false
)
)
Parameter
Type
value
uint
A private function that checks if the given value is less than or equal to the value of the global variable helper-uint
. It returns true
if the condition is met, otherwise it returns false
.
map-filtered-null-list
(define-private (map-filtered-null-list (index uint))
(+ (var-get helper-uint) index)
)
Parameter
Type
index
uint
A private function that takes an uint as its input and returns the sum of the value of the global variable helper-uint
and the given index
uint.
filter-list
(define-private (filter-list (value uint))
(if (is-some (index-of (var-get helper-uint-list) value))
false
true
)
)
Parameter
Type
value
uint
A private function that checks if the given value exists in the list stored in the global variable helper-uint-list
. It returns false
if the value exists in the list, otherwise, it returns true
.
filter-unstaked-cycle
(define-private (filter-unstaked-cycle (value uint))
(if (is-eq value (var-get helper-uint))
false
true
)
)
Parameter
Type
value
uint
A private function that checks if the provided value is equal to the value of the global variable helper-uint
. If they are equal, it returns false
; otherwise, it returns true
.
update-staker-data-per-cycle-fold
(define-private (update-staker-data-per-cycle-fold (next-cycle uint) (static-user-and-cycle-data {x-token: principal, y-token: principal, lp-token: principal, cycles-staked: (list 12000 uint), amount: uint}))
(let
(
(x-token-static (get x-token static-user-and-cycle-data))
(y-token-static (get y-token static-user-and-cycle-data))
(lp-token-static (get lp-token static-user-and-cycle-data))
(cycles-staked-static (get cycles-staked static-user-and-cycle-data))
(amount-static (get amount static-user-and-cycle-data))
(current-cycle-user-data (default-to {lp-token-staked: u0, reward-claimed: false, lp-token-to-unstake: u0} (map-get? StakerDataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, user: tx-sender, cycle: next-cycle})))
(current-cycle-lp-token-staked (get lp-token-staked current-cycle-user-data))
(current-cycle-lp-token-to-unstake (get lp-token-to-unstake current-cycle-user-data))
(current-cycle-reward-claimed (get reward-claimed current-cycle-user-data))
(current-all-staker-data (map-get? DataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, cycle: next-cycle}))
)
;; Check if staker is already staked in this cycle
(if (is-some (index-of cycles-staked-static next-cycle))
;; Staker is already staked in this cycle, update StakerDataPerCycleMap
(map-set StakerDataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, user: tx-sender, cycle: next-cycle} (merge
current-cycle-user-data
{lp-token-staked: (+ amount-static current-cycle-lp-token-staked)}
))
;; Staker is not already staked in this cycle, create new StakerDataPerCycleMap
(map-set StakerDataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, user: tx-sender, cycle: next-cycle} (merge
current-cycle-user-data
{
lp-token-staked: amount-static,
reward-claimed: false,
}))
)
;; Update DataPerCycleMap
(if (is-some current-all-staker-data)
;; Cycle data already exists, update total-lp-token-staked
(map-set DataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, cycle: next-cycle} (+ amount-static (default-to u0 current-all-staker-data)))
;; Staker doesn't exist, create new entry
(map-set DataPerCycleMap {x-token: x-token-static, y-token: y-token-static, lp-token: lp-token-static, cycle: next-cycle} amount-static)
)
static-user-and-cycle-data
)
)
Parameter
Type
next-cycle
uint
static-user-and-cycle-data
map
A private function that updates a staker's data for a particular staking cycle. It checks whether the staker has already staked in the given cycle and accordingly updates or creates a new entry in the StakerDataPerCycleMap
.
fold-from-all-cycles-to-cycles-unclaimed
(define-private (fold-from-all-cycles-to-cycles-unclaimed (cycle uint) (fold-data {x-token: principal, y-token: principal, lp-token: principal, total-rewards-x: uint, total-rewards-y: uint, current-cycle: uint}))
(let
(
(static-current-cycle (get current-cycle fold-data))
(static-x-token (get x-token fold-data))
(static-y-token (get y-token fold-data))
(static-lp-token (get lp-token fold-data))
(current-total-rewards-x (get total-rewards-x fold-data))
(current-total-rewards-y (get total-rewards-y fold-data))
(param-cycle-staking-rewards (get-staking-rewards-at-cycle static-x-token static-y-token static-lp-token cycle))
(param-cycle-rewards-x (match param-cycle-staking-rewards
ok-branch
(get x-token-reward ok-branch)
err-branch
u0
))
(param-cycle-rewards-y (match param-cycle-staking-rewards
ok-branch
(get y-token-reward ok-branch)
err-branch
u0
))
;; If the param-cycle is not in the past, then the rewards have to be zero.
(param-cycle-x-rewards (if (>= cycle static-current-cycle) u0 param-cycle-rewards-x))
(param-cycle-y-rewards (if (>= cycle static-current-cycle) u0 param-cycle-rewards-y))
(param-cycle-user-data (default-to {lp-token-staked: u0,reward-claimed: false, lp-token-to-unstake: u0} (map-get? StakerDataPerCycleMap {x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, user: tx-sender, cycle: cycle})))
)
(if (or (> param-cycle-x-rewards u0) (> param-cycle-y-rewards u0))
;; There are rewards to claim
(begin
;; Update StakerDataPerCycleMap with reward-claimed = true
(map-set StakerDataPerCycleMap {x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, user: tx-sender, cycle: cycle} (merge
param-cycle-user-data
{reward-claimed: true}
))
{x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, total-rewards-x: (+ current-total-rewards-x param-cycle-x-rewards), total-rewards-y: (+ current-total-rewards-y param-cycle-y-rewards), current-cycle: static-current-cycle}
)
;; There are no rewards to claim
fold-data
)
)
)
Parameter
Type
cycle
uint
fold-data
map
A private function that iterates through all staking cycles and calculates the unclaimed rewards for the staker. For each cycle, it checks the staking rewards available for the staker. If rewards are found, the function updates the StakerDataPerCycleMap
to mark the rewards as claimed. The cumulative rewards across all cycles are returned as the output.
fold-from-all-cycles-to-unstakeable-cycles
(define-private (fold-from-all-cycles-to-unstakeable-cycles (cycle uint) (fold-data {x-token: principal, y-token: principal, lp-token: principal, total-lps-to-unstake: uint, current-cycles-to-unstake: (list 12000 uint)}))
(let
(
(current-cycle (contract-call? .stableswap-usda-susdt get-current-cycle))
(current-total-lp-tokens-to-unstake (get total-lps-to-unstake fold-data))
(static-x-token (get x-token fold-data))
(static-y-token (get y-token fold-data))
(static-lp-token (get lp-token fold-data))
(current-cycles-to-unstake (get current-cycles-to-unstake fold-data))
(param-cycle-user-data (match (map-get? StakerDataPerCycleMap {x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, user: tx-sender, cycle: cycle})
;; StakerDataPerCycleMap entry exists, save it to param-cycle-user-data
unwrapped-value
unwrapped-value
;; StakerDataPerCycleMap entry doesn't exist (this should never happen)
{lp-token-staked: u0,
reward-claimed: false,
lp-token-to-unstake: u0}
))
(param-cycle-user-lp-tokens-to-unstake (get lp-token-to-unstake param-cycle-user-data))
(updated-helper-uint-to-filter (var-set helper-uint cycle))
(updated-cycles-to-unstake (filter filter-unstaked-cycle current-cycles-to-unstake))
)
(if (and (> param-cycle-user-lp-tokens-to-unstake u0) (<= cycle current-cycle))
;; There are lp-tokens to unstake
(begin
;; Update StakerDataPerCycleMap with lp-token-to-unstake = u0
(map-set StakerDataPerCycleMap {x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, user: tx-sender, cycle: cycle} (merge
param-cycle-user-data
{lp-token-to-unstake: u0}
))
{x-token: static-x-token, y-token: static-y-token, lp-token: static-lp-token, total-lps-to-unstake: (+ param-cycle-user-lp-tokens-to-unstake current-total-lp-tokens-to-unstake), current-cycles-to-unstake: updated-cycles-to-unstake}
)
;; There are no rewards to claim
fold-data
)
)
)
Parameter
Type
cycle
uint
fold-data
map
A private function that iterates through each staking cycle to determine the amount of LP tokens that can be unstaked. For every cycle that contains unstaked LP tokens and has not crossed the current cycle, the function updates the StakerDataPerCycleMap
to set the lp-token-to-unstake
field to zero. The overall tokens that can be unstaked are accumulated and returned along with the cycles that were checked.
Read-only Functions
These functions are read-only and are utilized for querying or retrieving data. While they can be invoked by external contracts or users, they do not alter the underlying state of the contract.
get-user-data
(define-read-only (get-user-data (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <lp-trait>) (user principal))
(map-get? StakerDataMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: user})
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
lp-trait
user
principal
A read-only function that retrieves the staking data for a specified principal given the x-token
, y-token
, and lp-token
parameters. It maps and fetches the data from the StakerDataMap
and returns it.
get-user-data-at-cycle
(define-read-only (get-user-data-at-cycle (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <lp-trait>) (user principal) (cycle uint))
(map-get? StakerDataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), user: user, cycle: cycle})
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
lp-trait
user
principal
cycle
uint
A read-only function that obtains the staking data for a specific principal at a given cycle, considering the x-token
, y-token
, and lp-token
parameters. It sources the information from the StakerDataPerCycleMap
based on the provided parameters.
get-data-at-cycle
(define-read-only (get-data-at-cycle (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <lp-trait>) (cycle uint))
(map-get? DataPerCycleMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token), cycle: cycle})
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
lp-trait
cycle
uint
A read-only function that fetches the overall staking data at a specified cycle for the given x-token
, y-token
, and lp-token
parameters. The data is extracted from the DataPerCycleMap
for the given cycle.
get-total-staked
(define-read-only (get-total-staked (x-token <og-sip-010-trait>) (y-token <susdt-sip-010-trait>) (lp-token <lp-trait>))
(map-get? TotalStakedPerPairMap {x-token: (contract-of x-token), y-token: (contract-of y-token), lp-token: (contract-of lp-token)})
)
Parameter
Type
x-token
og-sip-010-trait
y-token
susdt-sip-010-trait
lp-token
lp-trait
A read-only function that retrieves the total amount of x-token
, y-token
, and lp-token
staked. The data is sourced from the TotalStakedPerPairMap
.
get-staking-rewards-at-cycle
(define-read-only (get-staking-rewards-at-cycle (x-token principal) (y-token principal) (lp-token principal) (cycle uint))
(let
(
(param-cycle-user-data (unwrap! (map-get? StakerDataPerCycleMap {x-token: x-token, y-token: y-token, lp-token: lp-token, user: tx-sender, cycle: cycle}) (err u4)))
(param-cycle-reward-claimed (get reward-claimed param-cycle-user-data))
(param-cycle-user-lp-staked (get lp-token-staked param-cycle-user-data))
(param-cycle-total-lp-staked (unwrap! (map-get? DataPerCycleMap {x-token: x-token, y-token: y-token, lp-token: lp-token, cycle: cycle}) (err u5)))
(param-cycle-fees (unwrap! (contract-call? .stableswap-usda-susdt get-cycle-data x-token y-token lp-token cycle) (err u0)))
(param-cycle-balance-x-fee (get cycle-fee-balance-x param-cycle-fees))
(param-cycle-balance-y-fee (get cycle-fee-balance-y param-cycle-fees))
(param-cycle-x-rewards (/ (* param-cycle-balance-x-fee param-cycle-user-lp-staked) param-cycle-total-lp-staked))
(param-cycle-y-rewards (/ (* param-cycle-balance-y-fee param-cycle-user-lp-staked) param-cycle-total-lp-staked))
(claimer tx-sender)
)
;; Assert that param-cycle-x or param-cycle-y rewards are greater than 0
(asserts! (or (> param-cycle-x-rewards u0) (> param-cycle-y-rewards u0)) (err u1))
;; Assert that param-cycle-reward-claimed is false
(asserts! (not param-cycle-reward-claimed) (err u2))
(ok {x-token-reward: param-cycle-x-rewards, y-token-reward: param-cycle-y-rewards})
)
)
Parameter
Type
x-token
principal
y-token
principal
lp-token
principal
cycle
uint
A read-only function that calculates and returns the staking rewards for the invoking user (tx-sender
) at a given cycle. It considers x-token
and y-token
and computes the rewards based on the fees, the user's lp-token
staked amount, and the total LP tokens staked during the cycle.
Last updated