One-time initialisation. Reverts if called again.
Parameters
passkey_admin: Zion1 PasskeyID smart-wallet address.lobstr_admin: Distinct Lobstr G-address.reward_token: Zi SAC address (reward currency).lp_token: Zi/XLM LP pool-share token address (staking asset).
Immutable — cannot be changed after init.fn init(
env: soroban_sdk::Env,
passkey_admin: soroban_sdk::Address,
lobstr_admin: soroban_sdk::Address,
reward_token: soroban_sdk::Address,
lp_token: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Claim all pending Zi rewards without unstaking.
Not blocked by pause — claim is always available as an exit path.
fn claim(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Stake amount LP tokens.
Each call (re)sets the unlock timestamp to now + LOCK_PERIOD.
Accrued rewards up to this point are snapshotted into pending_rewards
so they are not lost.
Reverts if:
fn stake(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
amount: i128,
) -> Result<(), soroban_sdk::Error>
Withdraw all staked LP tokens. Auto-claims pending rewards.
Not blocked by pause — unstake is always available as an exit path. Reverts if the lock period has not yet expired.
fn unstake(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
LP token address (immutable after init).
fn lp_token(env: soroban_sdk::Env) -> Option
Extend the contract instance and an existing staker position to the configured TTL target. Anyone may call this method so an operations keeper can preserve one-year locked positions without holding user or admin credentials. It cannot create or modify a staking balance.
fn keep_alive(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Pause or unpause the contract. Admin only.
When paused: stake and fund_rewards revert.
When paused: claim and unstake still succeed (exit paths).
fn set_paused(env: soroban_sdk::Env, paused: bool) -> Result<(), soroban_sdk::Error>
Actual Zi token balance held by this contract. Source of truth for solvency — use this in the admin panel, not any tracked pool counter.
fn zi_balance(env: soroban_sdk::Env) -> i128
Current reward emission rate (Zi stroops per second).
fn reward_rate(env: soroban_sdk::Env) -> i128
Staker position: (staked_lp, unlock_time, pending_rewards).
Frontend reads are simulations and do not persist a TTL extension. The
operations keeper must submit keep_alive before the entry reaches its
threshold.
fn staker_info(
env: soroban_sdk::Env,
staker: soroban_sdk::Address,
) -> (i128, u64, i128)
Deposit Zi into the reward pool. Admin only.
Why admin-only: allowing anyone to call fund_rewards enables a
griefing attack where the attacker resets the one-year reward window
with a tiny amount, collapsing the reward rate to near-zero.
The funder parameter identifies whose Zi is transferred; both the
admin and the funder must authorise so that treasury and operational
keys can be separate accounts or contracts.
Unspent rewards from any in-progress period roll forward into the new
period budget. The new rate is total_budget / SECONDS_PER_YEAR.
The contract does not enforce a 23% APR; it emits whatever rate the
deposited budget can sustain.
fn fund_rewards(
env: soroban_sdk::Env,
funder: soroban_sdk::Address,
amount: i128,
) -> Result<(), soroban_sdk::Error>
Configured Lobstr G-address admin.
fn lobstr_admin(env: soroban_sdk::Env) -> soroban_sdk::Address
Reward token address (Zi SAC).
fn reward_token(env: soroban_sdk::Env) -> Option
Total LP tokens currently staked across all accounts.
fn total_staked(env: soroban_sdk::Env) -> i128
Configured Zion1 PasskeyID admin address.
fn passkey_admin(env: soroban_sdk::Env) -> soroban_sdk::Address
Timestamp (seconds) when the current reward period ends.
fn period_finish(env: soroban_sdk::Env) -> u64
Pending Zi rewards for staker at the current ledger timestamp.
Informational — uses saturating arithmetic (no state written).
fn pending_rewards(env: soroban_sdk::Env, staker: soroban_sdk::Address) -> i128
Replace the Lobstr admin. Both current admins and the replacement must authorize, and the two configured identities must remain distinct.
fn transfer_lobstr_admin(
env: soroban_sdk::Env,
new_admin: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Transfer the admin role to new_admin. Both current and new admin
must authorise (prevents accidental transfer to an inaccessible address).
new_admin may be a Soroban multisig policy contract for 2-of-3 or
threshold schemes without any custom cryptography in this contract.
fn transfer_passkey_admin(
env: soroban_sdk::Env,
new_admin: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>