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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.