Receipt Tokens
What this page is for: every receipt token rFlow currently supports — mainnet mint address, Pyth feed ID, accrual mechanism, and how the protocol values it at lock and settlement.
Overview#
A receipt token is what a DeFi protocol gives you when you deposit. It represents your position and appreciates as the underlying earns yield. rFlow locks these tokens in a PDA vault and lets you sell the appreciation between today and a fixed expiry.
Two accrual patterns
Balance stays constant; value rises via a growing exchange rate (mSOL, jitoSOL, bSOL, cUSDC, kUSDC). Settlement reads the rate from Pyth on mainnet.
Fees accrue on a position account and must be claimed (Meteora DAMM v2). During an active deal, the buyer claims directly.
Whitelist is on-chain
ProtocolConfig.allowed_mints can be locked. The list is admin-managed via update_config. Want a new mint listed? See Integration · whitelist a mint.Marinade Staked SOL (mSOL)#
Marinade Staked SOL
Marinade Finance · Liquid staking
mSOL is Marinade's liquid staking token. The supply stays constant; staking rewards accrue by making each mSOL redeemable for slightly more SOL. The Pyth MSOL/USD feed gives the program an authoritative value at settlement — no caller value accepted on mainnet.
Jito Staked SOL (jitoSOL)#
Jito Staked SOL
Jito · MEV-enhanced liquid staking
jitoSOL works like mSOL with an added MEV boost: a slice of the MEV captured by Jito-Solana validators is redistributed to stakers, pushing realized APY ~1–2% above standard staking.
Blaze Staked SOL (bSOL)#
Blaze Staked SOL
SolBlaze · Liquid staking
bSOL is SolBlaze's liquid staking token, designed for delegated staking to community validators. Same exchange-rate mechanism; settlement uses the Pyth BSOL/USD feed.
Kamino (kUSDC)#
Kamino kUSDC
Kamino Lend
Kamino kTokens are reserve-specific — the mint address for kUSDC depends on the Kamino market. Fetch the canonical mint via KaminoMarket.load() and reserve.state.collateral.mintPubkey from the Kamino SDK. rFlow does not assume a single kUSDC mint.
Because Kamino has no first-party Pyth USD feed for kTokens, settlement uses the bounded caller-value path: a value within ±10% of exchange_rate_at_lock is accepted.
Solend / Save (cUSDC)#
Solend cUSDC
Solend / Save · Lending
cTokens use the same Compound-style mechanism as kTokens — supply stays constant, value rises via an exchange rate that tracks accrued borrower interest. No first-party Pyth feed; settlement uses the bounded caller-value path.
Meteora LP Positions#
Meteora DAMM v2 Positions
Concentrated liquidity · Position NFT
Different from exchange-rate tokens
fee_a_at_lock and fee_b_at_lock snapshots and lets the buyer claim during the active deal.When you list a Meteora LP deal:
- Optionally split your position with
split_meteora_positionto sell only a portion - Lock the Position NFT in a rFlow NFT vault via
create_meteora_lp_deal - Fees accumulated before lock are snapshotted — claim those first if you want them
- During the deal, the buyer calls
claim_meteora_feesto harvest new fees - At settlement,
settle_meteora_lp_dealreturns the NFT to you - Unwind anytime after with
withdraw_meteora_liquidity
How values are calculated#
Exchange-rate tokens (mainnet path)
1// Pyth gives us a price and an exponent2// price * 10^exponent = current USD per unit token3//4// Combined exponent normalizes for token decimals and USDC's 6 decimals:5let combined_exponent = exponent + USDC_DECIMALS - token_decimals as i32;6let base_value = receipt_tokens_amount * price;78let oracle_value = if combined_exponent >= 0 {9 base_value * 10u128.pow(combined_exponent as u32)10} else {11 base_value / 10u128.pow((-combined_exponent) as u32)12};1314// Example: 1 jitoSOL at $200, exponent = -815// tokens = 1_000_000_000 (9 decimals)16// price = 20_000_000_00017// value = 200_000_000 // 200 USDC (6 decimals)Devnet / non-LST tokens (bounded caller value)
1// Expected value if exchange rate were exactly the one stored at lock2let expected_value = receipt_tokens_amount * exchange_rate_at_lock / EXCHANGE_RATE_SCALE;34// ±10% tolerance (ORACLE_TOLERANCE_BPS = 1000)5let tolerance = expected_value * ORACLE_TOLERANCE_BPS / 10_000;6let min_acceptable = expected_value - tolerance;7let max_acceptable = expected_value + tolerance;89require!(10 current_token_value >= min_acceptable && current_token_value <= max_acceptable,11 PayflowError::InvalidTokenValue12);