The Technicals
Primary functions
Stake shards
stakeFractions(...)
Moves the caller’s slice tokens into the vault and updates theUserPosition
PDA:secondsDebt
– snapshot of the caller’s slice-seconds balance.rewardDebt[mint]
– one entry per reward mint so newcomers don’t skim past earlier rewards.
Unstake shards
unstakeFractions(...)
Mirrors the maths, returns the staked tokens, and shrinks both debts.
Claim rewards
claim(...)
Computes the pending amountCPI-transfers it from the reward vault, then resets
secondsDebt
to the current stake-seconds.
The Authority (Contract Owner)
Refill / withdraw inventory
depositFractionTokens(...)
&withdrawFractionTokens(...)
move slice tokens between the Authority and the slice-vault.
Change price or mints
updateSwapConfig(...)
updates token mints or the fixed exchange-rate.
Inject rewards
depositRewards(...)
deposits any SPL mint into the reward-vault, snapshots the epoch, calculates the stake-second value, and bumps the reward-drop counter.
Initialize
initialize(...)
sets up the whole program (vault PDAs, config, etc.).
Buyers
Any address can call depositQuoteTokens(amount)
to purchase slices (shards) in one atomic transaction the contract:
CPI-transfers the quote tokens into the payment vault.
Divides
amount
by the fixed exchange-rate, pulls slice tokens from the slice-vault, and sends them to the buyer.Writes/updates a
BuyerRecord
PDA for the audit trail: who paid, how much, when.
Mathematics Behind Reward Calculation
TLDR; the smart contract functions as one big clock that tallies how long every token has been staked, then splits each reward by that tally—so you automatically get your slice and any leftovers roll into the treasury.
The pool tracks a single global timer, accSecondsPerShare
, which grows by “seconds since last update ÷ totalStaked” whenever someone stakes or unstakes, logging stake-seconds per token. Each reward drop snapshots its own accRewardPerShare[mint]
(scaled 1e18 for integer math), so your payout is just your stake × (new-minus-old snapshot) ÷ 1e18. Any reward slices tied to tokens that weren’t staked at epoch close get swept into the protocol treasury, so unclaimed yield becomes protocol revenue instead of disappearing. Now, here are the technicals:
Global accumulator The pool keeps
accSecondsPerShare
(Q128.64 fixed-point). Each time stake changes,syncSeconds()
adds to that value.Per-reward accumulator Every reward drop stores an
accRewardPerShare[mint]
, scaled by1e18
.Treasury credits Unsold or unstaked slices at epoch close are treated as treasury credits: the rewards meant for “nobody” accumulate under the contract’s own key instead of disappearing.
Last updated