Deposit backer money. Counts toward capacity after 7 days.
fn back(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
amount: i128,
) -> Result<(), PoolError>
fn pause(env: soroban_sdk::Env)
fn stake(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
amount: i128,
beneficiary: soroban_sdk::Address,
) -> Result<(), PoolError>
r3 (2026-09-29): permissionless. Redeems only the vault's growth above
book value and splits it (stakers / backers / protocol). Best effort:
returns 0 rather than failing. Also runs inside every yield payout,
so nobody has to call it. Replaces the admin-only extract_yield.
fn harvest(env: soroban_sdk::Env) -> i128
fn unpause(env: soroban_sdk::Env)
fn withdraw(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
beneficiary: soroban_sdk::Address,
) -> Result<(), PoolError>
fn get_admin(env: soroban_sdk::Env) -> soroban_sdk::Address
fn get_claim(env: soroban_sdk::Env, claim_id: soroban_sdk::BytesN<32>) -> Option
fn get_stake(
env: soroban_sdk::Env,
wallet: soroban_sdk::Address,
) -> Option
fn get_vault(env: soroban_sdk::Env) -> Option
fn is_paused(env: soroban_sdk::Env) -> bool
fn get_backer(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
) -> Option
fn get_oracle(env: soroban_sdk::Env) -> soroban_sdk::Address
r3: a staker takes their yield without unstaking. Paid to the
beneficiary (hash-checked as in withdraw).
fn claim_yield(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
beneficiary: soroban_sdk::Address,
) -> Result
fn get_setting(env: soroban_sdk::Env, key: SettingKey) -> i128
V8 isEligible: has an active, non-withdrawn, non-suspended
stake. Does NOT check the time gate, see is_claim_eligible.
fn is_eligible(env: soroban_sdk::Env, wallet: soroban_sdk::Address) -> bool
fn cancel_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
fn claim_stream(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
beneficiary: soroban_sdk::Address,
) -> Result
Staker principal + matured backer money: what claims are sized against.
fn get_capacity(env: soroban_sdk::Env) -> i128
fn get_guardian(env: soroban_sdk::Env) -> soroban_sdk::Address
fn set_pool_cap(env: soroban_sdk::Env, new_cap: i128) -> Result<(), PoolError>
CHANGED T2/D1: deadline + signature are now required arguments.
When caller is the oracle the contract verifies an Ed25519
signature over the verdict on-chain; when caller is the admin
(manual fallback) both are ignored, exactly as in V8. See
claim::submit_claim for the full auth-model rationale.
fn submit_claim(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
wallet: soroban_sdk::Address,
tx_hash: soroban_sdk::BytesN<32>,
entitlement: i128,
tier: u32,
hack_timestamp: u64,
deadline: u64,
signature: soroban_sdk::BytesN<64>,
) -> Result, PoolError>
Deploy-time initialization.
CHANGED 2026-08-17 (7a audit, Finding 3): was a separate initialize
entrypoint. Renamed to __constructor, the SDK-recognised constructor
hook, which runs as part of the deploy invocation itself.
Why this mattered: initialize authorized the admin argument
passed to it, and the only thing stopping a second call was the
AlreadyInitialized guard. That guard protects against
re-initialization but not against being first, between the deploy
transaction and the legitimate init transaction, anyone observing the
chain could call initialize with themselves as admin and satisfy
require_auth trivially. The T1 testnet deployment used two separate
transactions (README), so the window was real rather than theoretical.
Stellar's own guidance is explicit: prefer __constructor because it
"removes the front-running window between deploy and init", and note
that a contract deployed without one can never gain it afterwards,
which is why this had to change before D4's deploy,
fn __constructor(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
oracle: soroban_sdk::Address,
oracle_pubkey: soroban_sdk::BytesN<32>,
co_signer: soroban_sdk::Address,
guardian: soroban_sdk::Address,
xlm_token: soroban_sdk::Address,
pool_cap: i128,
) -> Result<(), PoolError>
NEW 2026-07-22 (Rule A), staker-authorized. Burns the wallet's
entire lifetime points balance, forfeits the stake, starts
cooldown/vesting. Must be called within APPROVE_WINDOW_LEDGERS of
the claim entering AwaitingApproval.
fn approve_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
Returns true once cancelled (standard changes need two roles).
fn cancel_change(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
kind: GovKind,
) -> Result
fn get_co_signer(env: soroban_sdk::Env) -> soroban_sdk::Address
fn suspend_stake(
env: soroban_sdk::Env,
wallet: soroban_sdk::Address,
) -> Result<(), PoolError>
fn approve_change(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
change: GovChange,
) -> Result<(), PoolError>
fn cancel_setting(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
key: SettingKey,
) -> Result<(), PoolError>
fn emergency_exit(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
) -> Result<(), PoolError>
fn execute_change(env: soroban_sdk::Env, kind: GovKind) -> Result<(), PoolError>
fn get_deploy_bps(env: soroban_sdk::Env) -> i128
r3: false until the first stake or backing; while false, vault / treasury / deploy-ceiling changes apply without the 7-day wait.
fn is_ever_funded(env: soroban_sdk::Env) -> bool
Permissionless: start counting a matured deposit toward capacity.
fn mature_backing(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
) -> Result
fn propose_change(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
change: GovChange,
) -> Result<(), PoolError>
Send already-liquid excess above staker principal to treasury.
fn withdraw_yield(env: soroban_sdk::Env, amount: i128) -> Result<(), PoolError>
fn approve_setting(
env: soroban_sdk::Env,
key: SettingKey,
value: i128,
) -> Result<(), PoolError>
Supply liquid XLM into the vault. Returns shares gained.
min_shares_out is the caller's floor against an adverse share
price: quote it off-chain via the vault's
get_asset_amounts_per_shares first.
fn deploy_to_vault(
env: soroban_sdk::Env,
amount: i128,
min_shares_out: i128,
) -> Result
fn execute_setting(env: soroban_sdk::Env, key: SettingKey) -> Result<(), PoolError>
Additive staker yield index. Starts at YIELD_INDEX_PRECISION; grows
only via credit_yield's staker-share split. Exposed mainly for
audit/observability: callers wanting a staker's actual withdrawable
balance should call get_withdrawable_amount instead of re-deriving
the ratio themselves.
fn get_yield_index(env: soroban_sdk::Env) -> i128
fn propose_setting(
env: soroban_sdk::Env,
key: SettingKey,
value: i128,
) -> Result<(), PoolError>
T2/D1: admin-only. Cancels a signed-but-not-yet-submitted oracle
approval. Takes the full approval parameters rather than a
precomputed hash (V8's shape); see claim::revoke_approval for why.
fn revoke_approval(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
wallet: soroban_sdk::Address,
tx_hash: soroban_sdk::BytesN<32>,
entitlement: i128,
tier: u32,
hack_timestamp: u64,
deadline: u64,
) -> Result<(), PoolError>
fn set_beneficiary(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
new_beneficiary: soroban_sdk::Address,
) -> Result<(), PoolError>
claim_id optional: pass the wallet's in-flight claim (if any) so
its Rule A/B deadline clock resets on unsuspend (eng review
blocker #1). None if the wallet has no claim needing a reset.
fn unsuspend_stake(
env: soroban_sdk::Env,
wallet: soroban_sdk::Address,
claim_id: Option>,
) -> Result<(), PoolError>
fn approve_override(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
wallet: soroban_sdk::Address,
tx_hash: soroban_sdk::BytesN<32>,
entitlement: i128,
tier: u32,
) -> Result<(), PoolError>
T3 (2026-08-24), permissionless sibling of provide_liquidity.
Pulls back only enough to cover total_allocated if liquid balance
is short of it. No caller input. Works while paused, same reasoning
as provide_liquidity. Returns 0 if nothing's short.
fn ensure_liquidity(env: soroban_sdk::Env) -> Result
fn get_paused_until(env: soroban_sdk::Env) -> u64
fn get_total_backed(env: soroban_sdk::Env) -> i128
fn get_total_staked(env: soroban_sdk::Env) -> i128
fn propose_recovery(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
change: GovChange,
) -> Result<(), PoolError>
fn get_total_stakers(env: soroban_sdk::Env) -> u32
The protocol's own realised, unwithdrawn yield share, "the
protocol's own money", withdrawable any time via
withdraw_yield. CHANGED 2026-09-18: now reads the explicit
ProtocolYieldBalance counter, not the removed residual formula
(documented bug history: see vault.rs).
fn get_yield_balance(env: soroban_sdk::Env) -> i128
V8 isClaimEligible: is_eligible AND the 90-day time gate has
passed.
fn is_claim_eligible(env: soroban_sdk::Env, wallet: soroban_sdk::Address) -> bool
Redeem shares so the XLM sits liquid in the contract, ready to fund
payouts and withdrawals. Nothing leaves the pool. Works while
paused, deliberately: emergency_exit depends on it.
fn provide_liquidity(
env: soroban_sdk::Env,
shares: i128,
min_asset_out: i128,
) -> Result
r3: a backer takes their yield, principal untouched. Paid to the backer.
fn claim_backer_yield(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
) -> Result
NEW 2026-07-22 (Rule B sweep), permissionless. Releases whatever's
left uncollected if the staker goes COLLECTION_INACTIVITY_LEDGERS
with zero claim_stream activity.
fn expire_stale_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
Real liquid XLM held by the contract, distinct from
get_total_staked, which counts XLM sitting in the vault too.
fn get_liquid_balance(env: soroban_sdk::Env) -> i128
fn get_pending_change(env: soroban_sdk::Env, kind: GovKind) -> Option
V8 pointsOf: live-computed if still staked and not withdrawn,
else the banked balance. NOT a raw storage read.
fn get_points_balance(env: soroban_sdk::Env, wallet: soroban_sdk::Address) -> i128
r3: set-aside yield (stakers, backers). Never deployed or spent on claims.
fn get_yield_reserved(env: soroban_sdk::Env) -> (i128, i128)
T3 (2026-08-24), permissionless. Sweeps a queued claim whose claim window ran out before capacity ever freed.
fn expire_queued_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
fn get_pending_setting(
env: soroban_sdk::Env,
key: SettingKey,
) -> Option
fn get_total_allocated(env: soroban_sdk::Env) -> i128
fn unlock_pending_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
T3 (2026-08-24), permissionless sibling of deploy_to_vault. Puts
idle liquidity (above what's reserved for live claims) to work
automatically, up to the existing deploy_bps ceiling. No caller
input: the contract computes the amount and its own slippage
floor. Requires at least one prior manual deploy_to_vault call
(needs a reference rate); returns 0 if nothing's idle or no room
remains under the ceiling.
fn auto_deploy_liquidity(env: soroban_sdk::Env) -> Result
r3: a backer's yield credited and not yet paid.
fn get_backer_yield_owed(env: soroban_sdk::Env, backer: soroban_sdk::Address) -> i128
r3: a staker's yield credited and not yet paid (excludes growth still in the vault until the next harvest).
fn get_staker_yield_owed(env: soroban_sdk::Env, staker: soroban_sdk::Address) -> i128
fn get_backer_yield_index(env: soroban_sdk::Env) -> i128
fn cancel_pending_override(
env: soroban_sdk::Env,
caller: soroban_sdk::Address,
wallet: soroban_sdk::Address,
tx_hash: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
NEW 2026-07-22 (Rule A sweep), permissionless, mirrors
unlock_pending_claim. Releases the reservation back to the pool
if the staker never approved within the window.
fn expire_pending_approval(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
A staker's current withdrawable value, principal plus their proportional share of yield realised since they staked. 0 for no stake, a withdrawn stake, or a forfeited (claimed) one.
fn get_withdrawable_amount(env: soroban_sdk::Env, staker: soroban_sdk::Address) -> i128
fn cancel_backer_withdrawal(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
) -> Result<(), PoolError>
Current deployed fraction in bps. May read above get_deploy_bps
after a large withdrawal: that is drift, not a breach; see vault.rs.
fn get_deployment_ratio_bps(env: soroban_sdk::Env) -> i128
fn get_total_backed_pending(env: soroban_sdk::Env) -> i128
XLM in the vault at ORIGINAL deposit value, never marked to market.
fn get_total_deployed_asset(env: soroban_sdk::Env) -> i128
T3 (2026-08-24), permissionless. Re-checks a queued claim's original
blocker (DailyStressCapExceeded/Insolvent) against current state;
admits it for real if that now passes, otherwise returns
QueueReleaseNotYetEligible and it stays Reserved.
fn try_release_queued_claim(
env: soroban_sdk::Env,
claim_id: soroban_sdk::BytesN<32>,
) -> Result<(), PoolError>
fn get_total_deployed_shares(env: soroban_sdk::Env) -> i128
fn get_total_extracted_yield(env: soroban_sdk::Env) -> i128
Start the notice period. Returns the earliest completion timestamp.
fn request_backer_withdrawal(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
amount: i128,
) -> Result
Pay a requested withdrawal to the backer's own address, once the notice has passed and only from capital open claims don't need.
fn complete_backer_withdrawal(
env: soroban_sdk::Env,
backer: soroban_sdk::Address,
) -> Result