Initializes the staking contract with required configuration.
env - The contract environmentadmin - The administrator address that will have privileged accesstreasury_address - Address where treasury fees are sentaqua_token - Contract address of the AQUA tokenblub_token - Contract address of the BLUB token (Stellar asset)liquidity_contract - Address of the AQUA/BLUB StableSwap pool contractice_contract - Address of the ICE locking contract for governanceOk(()) on successErr(Error::AlreadyInitialized) if contract is already initializedRequires authorization from the admin address.
fn initialize(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
treasury_address: soroban_sdk::Address,
aqua_token: soroban_sdk::Address,
blub_token: soroban_sdk::Address,
liquidity_contract: soroban_sdk::Address,
ice_tokens: IceTokens,
vault_treasury: soroban_sdk::Address,
vault_fee_bps: u32,
) -> Result<(), soroban_sdk::Error>
Retrieves the current contract configuration.
Ok(Config) - The contract configurationErr(Error::NotInitialized) if contract is not initializedfn get_config(env: soroban_sdk::Env) -> Result
Updates the admin for the BLUB Stellar Asset Contract (SAC).
admin - The current admin addressnew_admin - The new admin address to setOk(()) on successErr(Error::Unauthorized) if caller is not the adminRequires authorization from the current admin address.
fn update_sac_admin(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
new_admin: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Stake AQUA tokens and automatically mint BLUB tokens for staking.
This function performs the following operations:
user - The address of the user staking tokensamount - The amount of AQUA tokens to stakeduration_periods - The number of period units to lock tokens (multiplied by period_unit_minutes)Ok(()) - SuccessErr(Error::InvalidInput) if amount is <= 0Err(Error::ReentrancyDetected) if a reentrant call is detectedErr(Error::InsufficientBalance) if user doesn't have enough AQUARequires authorization from the user address.
fn lock(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
duration_periods: u64,
) -> Result<(), soroban_sdk::Error>
Records a lock entry for tracking purposes without performing token transfers.
This function only records metadata about a lock that occurred elsewhere. Useful for tracking locks that happened on a different chain or contract.
user - The address of the user whose lock is being recordedamount - The amount of tokens lockedduration_periods - The number of period units for the locktx_hash - The transaction hash from the external lockOk(()) - SuccessErr(Error::InvalidInput) if amount is <= 0Err(Error::ReentrancyDetected) if a reentrant call is detectedRequires authorization from the user address.
fn record_lock(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
duration_periods: u64,
tx_hash: soroban_sdk::Bytes,
) -> Result<(), soroban_sdk::Error>
Records an unlock event and transfers locked BLUB plus rewards to the user.
user - The address of the user unlocking tokensamount - The amount of tokens to unlocktx_hash - The transaction hash for trackingOk(()) - SuccessErr(Error::InvalidInput) if amount is <= 0Err(Error::ReentrancyDetected) if a reentrant call is detectedErr(Error::InsufficientBalance) if contract doesn't have enough BLUBRequires authorization from the user address.
fn record_unlock(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
tx_hash: soroban_sdk::Bytes,
) -> Result<(), soroban_sdk::Error>
Restake BLUB tokens to earn more BLUB rewards.
Allows users to stake their BLUB tokens (obtained from previous stakes or rewards) to earn additional BLUB rewards.
user - The address of the user staking BLUBamount - The amount of BLUB tokens to stakeduration_periods - The number of period units to lock tokensOk(()) - SuccessErr(Error::InvalidInput) if amount is <= 0Err(Error::ReentrancyDetected) if a reentrant call is detectedErr(Error::InsufficientBalance) if user doesn't have enough BLUBRequires authorization from the user address.
fn stake(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
duration_periods: u64,
) -> Result<(), soroban_sdk::Error>
Records a BLUB restake entry for tracking purposes.
user - The address of the user restaking BLUBamount - The amount of BLUB being restakedtx_hash - The transaction hash for trackingOk(()) - SuccessErr(Error::InvalidInput) if amount is <= 0Err(Error::ReentrancyDetected) if a reentrant call is detectedRequires authorization from the user address.
fn record_blub_restake(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
tx_hash: soroban_sdk::Bytes,
) -> Result<(), soroban_sdk::Error>
Records an LP (Liquidity Pool) deposit for a user.
admin - The admin address authorizing this operationuser - The address of the user depositing liquiditypool_id - The unique identifier of the liquidity poolamount_a - The amount of token A depositedamount_b - The amount of token B depositedtx_hash - The transaction hash for trackingOk(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if amounts are negativeRequires authorization from the admin address.
fn record_lp_deposit(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
user: soroban_sdk::Address,
pool_id: soroban_sdk::Bytes,
amount_a: i128,
amount_b: i128,
tx_hash: soroban_sdk::Bytes,
) -> Result<(), soroban_sdk::Error>
Calculates the total rewards for a user from both locked stakes and LP positions.
user - The address of the user to calculate rewards forOk(UserRewardTotals) - The user's reward totals including pending and accumulated rewardsErr(Error) if calculation failsThis is a view function that doesn't modify state. It calculates:
fn calculate_user_rewards(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
) -> Result
Records a reward distribution event.
admin - The admin address authorizing this operationkind - The type of reward distribution (0 = LP rewards, 1 = locked rewards)pool_id - The pool identifier (if applicable)total_reward - The total amount of rewards distributeddistributed_amount - The amount distributed to userstreasury_amount - The amount sent to treasurytx_hash - The transaction hash for trackingOk(u32) - The index of the distribution recordErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if amounts are negativeRequires authorization from the admin address.
fn record_reward_distribution(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
kind: u32,
pool_id: soroban_sdk::Bytes,
total_reward: i128,
distributed_amount: i128,
treasury_amount: i128,
tx_hash: soroban_sdk::Bytes,
) -> Result
Credits a reward amount to a specific user.
admin - The admin address authorizing this operationkind - The type of reward (0 = LP rewards, 1 = locked rewards)user - The address of the user receiving the rewardpool_id - The pool identifier (if applicable)amount - The amount of reward to credittx_hash - The transaction hash for trackingOk(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if amount is <= 0Requires authorization from the admin address.
fn credit_user_reward(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
kind: u32,
user: soroban_sdk::Address,
pool_id: soroban_sdk::Bytes,
amount: i128,
tx_hash: soroban_sdk::Bytes,
) -> Result<(), soroban_sdk::Error>
Records POL (Protocol Owned Liquidity) rewards claimed from AQUA-BLUB pair voting.
The rewards are split: 70% distributed to users, 30% to treasury.
admin - The admin address authorizing this operationreward_amount - The total amount of rewards claimedice_voting_power - The ICE voting power used to obtain these rewardsOk(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if reward_amount is <= 0Requires authorization from the admin address.
fn record_pol_rewards(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
reward_amount: i128,
ice_voting_power: i128,
) -> Result<(), soroban_sdk::Error>
Retrieves the global contract state.
Ok(GlobalState) - The current global state including locked amounts, supply, and reward ratesErr(Error::NotInitialized) if contract is not initializedfn get_global_state(env: soroban_sdk::Env) -> Result
Retrieves the lock totals for a specific user.
user - The address of the userSome(LockTotals) if user has locksNone if user has no locksfn get_user_lock_totals(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
) -> Option
Gets the number of lock entries for a user.
user - The address of the userThe count of lock entries (0 if none)
fn get_user_lock_count(env: soroban_sdk::Env, user: soroban_sdk::Address) -> u32
Retrieves a specific lock entry by index for a user.
user - The address of the userindex - The index of the lock entrySome(LockEntry) if the entry existsNone if the entry doesn't existfn get_user_lock_by_index(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
index: u32,
) -> Option
Gets all pool IDs that a user has LP positions in.
user - The address of the userA vector of pool IDs (empty if none)
fn get_user_pools(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
) -> soroban_sdk::Vec
Retrieves a user's LP position for a specific pool.
user - The address of the userpool_id - The pool identifierSome(LpPosition) if the position existsNone if no position foundfn get_user_lp(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
pool_id: soroban_sdk::Bytes,
) -> Option
Retrieves accumulated reward totals for a user.
user - The address of the userSome(UserRewardTotals) if user has rewardsNone if no rewards foundfn get_user_rewards(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
) -> Option
Gets the number of unlock entries for a user.
user - The address of the userThe count of unlock entries (0 if none)
fn get_unlock_count(env: soroban_sdk::Env, user: soroban_sdk::Address) -> u32
Retrieves a specific unlock entry by index for a user.
user - The address of the userindex - The index of the unlock entrySome(UnlockEntry) if the entry existsNone if the entry doesn't existfn get_unlock_by_index(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
index: u32,
) -> Option
Gets the number of BLUB restake entries for a user.
user - The address of the userThe count of BLUB restake entries (0 if none)
fn get_blub_restake_count(env: soroban_sdk::Env, user: soroban_sdk::Address) -> u32
Retrieves a specific BLUB restake entry by index for a user.
user - The address of the userindex - The index of the restake entrySome(BlubRestakeEntry) if the entry existsNone if the entry doesn't existfn get_blub_restake_by_index(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
index: u32,
) -> Option
Gets the total number of reward distributions recorded.
The count of distribution entries (0 if none)
fn get_distribution_count(env: soroban_sdk::Env) -> u32
Retrieves a specific reward distribution entry by index.
index - The index of the distribution entrySome(RewardDistribution) if the entry existsNone if the entry doesn't existfn get_distribution_by_index(
env: soroban_sdk::Env,
index: u32,
) -> Option
Retrieves the Protocol Owned Liquidity (POL) state.
The current POL state including AQUA/BLUB contributions and LP positions
fn get_protocol_owned_liquidity(env: soroban_sdk::Env) -> ProtocolOwnedLiquidity
Retrieves a daily POL snapshot for a specific day.
day - The day number (timestamp / 86400)Some(ProtocolOwnedLiquidity) if a snapshot exists for that dayNone if no snapshot foundfn get_daily_pol_snapshot(
env: soroban_sdk::Env,
day: u64,
) -> Option
Calculates the total POL contribution for a specific user.
Sums up all POL contributions from the user's lock entries.
user - The address of the userThe total amount of AQUA contributed to POL by this user
fn get_user_pol_contribution(env: soroban_sdk::Env, user: soroban_sdk::Address) -> i128
Retrieves the current reserves from the AQUA/BLUB liquidity pool.
Ok((i128, i128)) - A tuple of (aqua_reserve, blub_reserve)Err(Error::InvalidInput) if the pool query failsfn get_pool_reserves(env: soroban_sdk::Env) -> Result<(i128, i128), soroban_sdk::Error>
Retrieves the LP share token address from the liquidity pool.
Ok(Address) - The share token contract addressErr(Error::InvalidInput) if the pool query failsfn get_pool_share_token(
env: soroban_sdk::Env,
) -> Result
Withdraws liquidity from the pool (admin-only).
Used to manage Protocol Owned Liquidity or rebalance the pool.
admin - The admin address authorizing this operationshare_amount - The amount of LP share tokens to burnmin_aqua - Minimum AQUA to receive (slippage protection)min_blub - Minimum BLUB to receive (slippage protection)Ok((i128, i128)) - A tuple of (aqua_withdrawn, blub_withdrawn)Err(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if parameters are invalid or withdrawal failsRequires authorization from the admin address.
fn withdraw_from_pool(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
share_amount: i128,
min_aqua: i128,
min_blub: i128,
) -> Result<(i128, i128), soroban_sdk::Error>
Retrieves the virtual price of the liquidity pool.
The virtual price represents the price of an LP token in terms of underlying assets.
Ok(i128) - The virtual priceErr(Error::InvalidInput) if the pool query failsfn get_pool_virtual_price(env: soroban_sdk::Env) -> Result
Claims accumulated rewards from the liquidity pool (admin-only).
admin - The admin address authorizing this operationOk(i128) - The amount of rewards claimedErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if the claim failsRequires authorization from the admin address.
fn claim_pool_rewards(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
) -> Result
Retrieves the pending rewards available from the liquidity pool.
Ok(i128) - The amount of pending rewardsErr(Error::InvalidInput) if the pool query failsfn get_pool_pending_rewards(env: soroban_sdk::Env) -> Result
Updates the base reward rate (admin-only).
admin - The admin address authorizing this operationnew_rate - The new reward rate in basis points per period (max 1000 = 10%)Ok(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if new_rate > 1000Requires authorization from the admin address.
fn update_reward_rate(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
new_rate: i128,
) -> Result<(), soroban_sdk::Error>
Manually deposits accumulated POL to the AQUA-BLUB LP pool (admin-only).
admin - The admin address authorizing this operationaqua_amount - The amount of AQUA to deposit to LPblub_amount - The amount of BLUB to deposit to LPOk(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidInput) if amounts are <= 0Err(Error::InsufficientBalance) if contract doesn't have enough tokensRequires authorization from the admin address.
fn manual_deposit_pol(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
aqua_amount: i128,
blub_amount: i128,
) -> Result<(), soroban_sdk::Error>
Updates the liquidity pool contract address (admin-only).
admin - The admin address authorizing this operationnew_liquidity_contract - The new liquidity pool contract addressOk(()) on successErr(Error::Unauthorized) if caller is not the adminRequires authorization from the admin address.
fn update_liquidity_contract(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
new_liquidity_contract: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Updates BLUB token contract address (admin-only).
admin - The admin address authorizing this operationnew_blub_token - The new BLUB token contract addressOk(()) on successErr(Error::Unauthorized) if caller is not the adminRequires authorization from the admin address.
fn update_blub_token(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
new_blub_token: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Updates ICE token addresses (admin-only).
admin - The admin address authorizing this operationice_token - The ICE token contract addressgovern_ice_token - The governICE token contract addressupvote_ice_token - The upvoteICE token contract addressdownvote_ice_token - The downvoteICE token contract addressOk(()) on successErr(Error::Unauthorized) if caller is not the adminRequires authorization from the admin address.
fn update_ice_tokens(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
ice_token: soroban_sdk::Address,
govern_ice_token: soroban_sdk::Address,
upvote_ice_token: soroban_sdk::Address,
downvote_ice_token: soroban_sdk::Address,
) -> Result<(), soroban_sdk::Error>
Upgrades the contract to a new WASM hash (admin-only).
admin - The admin address authorizing this operationnew_wasm_hash - The hash of the new WASM to upgrade toRequires authorization from the admin address.
fn upgrade(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
new_wasm_hash: soroban_sdk::BytesN<32>,
) -> Result<(), soroban_sdk::Error>
Returns the current config version. For old config: returns the old version number For new config: returns encoded version (10100 = v1.1.0)
fn get_version(env: soroban_sdk::Env) -> Result
Test function to validate staking calculations without executing transactions.
aqua_amount - The amount of AQUA to simulate stakingOk((i128, i128, i128, i128, i128)) - A tuple containing:Err(Error::InvalidInput) if aqua_amount is <= 0fn test_staking_calculations(
env: soroban_sdk::Env,
aqua_amount: i128,
) -> Result<(i128, i128, i128, i128, i128), soroban_sdk::Error>
Retrieves the available POL balance that can be deposited to the LP pool.
Calculates available POL by subtracting currently locked/staked amounts from total balances.
Ok((i128, i128)) - A tuple of (available_aqua, available_blub)Err(Error) if unable to retrieve statefn get_available_pol_balance(
env: soroban_sdk::Env,
) -> Result<(i128, i128), soroban_sdk::Error>
Processes pending stake entries in batches.
This function avoids reentrancy by processing stakes in a separate transaction.
max_count - Maximum number of pending stakes to process (capped at 10)Ok(u32) - The number of stakes actually processedErr(Error) if processing failsfn process_pending_stakes(
env: soroban_sdk::Env,
max_count: u32,
) -> Result
Retrieves the total number of pending stake entries.
The count of pending stake entries (0 if none)
fn get_pending_stake_count(env: soroban_sdk::Env) -> u32
Retrieves a specific pending stake entry by index.
index - The index of the pending stake entrySome(PendingStake) if the entry existsNone if the entry doesn't existfn get_pending_stake(env: soroban_sdk::Env, index: u32) -> Option
Updates the staking period unit in minutes (admin-only).
admin - The admin address authorizing this operationperiod_unit_minutes - The new period unit in minutes (must be > 0)Ok(()) on successErr(Error::Unauthorized) if caller is not the adminErr(Error::InvalidPeriod) if period_unit_minutes is 0Requires authorization from the admin address.
fn update_period_unit(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
period_unit_minutes: u64,
) -> Result<(), soroban_sdk::Error>
Retrieves comprehensive staking information for a user.
user - The address of the userOk(UserStakingInfo) - Detailed staking information including:Err(Error) if calculation failsfn get_user_staking_info(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
) -> Result
Unstakes tokens and transfers them along with accumulated rewards to the user.
Users can unstake immediately without waiting for unlock periods. This function automatically calculates and includes pending rewards.
user - The address of the user unstaking tokensamount - The amount of BLUB to unstakeOk(()) on successErr(Error::InvalidInput) if amount is <= 0Err(Error::NotFound) if user has no lock entriesErr(Error::NoUnlockableAmount) if no tokens available to unstakeErr(Error::ReentrancyDetected) if a reentrant call is detectedErr(Error::InsufficientBalance) if contract doesn't have enough BLUBRequires authorization from the user address.
fn unstake(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
amount: i128,
) -> Result<(), soroban_sdk::Error>
One-time setup to establish trustlines for all 4 ICE token types. Must be called by admin before contract can receive ICE tokens.
Requires admin authorization
fn setup_ice_trustlines(env: soroban_sdk::Env) -> Result<(), soroban_sdk::Error>
Authorizes an ICE lock for a specific amount and duration. Backend cron will execute the actual locking on Stellar Classic.
aqua_amount - Amount of AQUA to lock for ICEduration_years - Lock duration (1-3 years)Lock ID for tracking
Requires admin authorization
fn authorize_ice_lock(
env: soroban_sdk::Env,
aqua_amount: i128,
duration_years: u64,
) -> Result
Transfers authorized AQUA from contract to admin for ICE locking. Backend calls this after authorization to move AQUA to admin wallet, then creates claimable balance on Stellar Classic.
lock_id - The authorization IDRequires admin authorization
fn transfer_authorized_aqua(
env: soroban_sdk::Env,
lock_id: u64,
) -> Result<(), soroban_sdk::Error>
Syncs all ICE token balances from SAC contracts. Backend calls this after ICE tokens are received.
Requires admin authorization
fn sync_all_ice_balances(env: soroban_sdk::Env) -> Result<(), soroban_sdk::Error>
Adds a new pool to the vault (max 10 pools).
pool_address - Aquarius pool contract addresstoken_a - First token in the pairtoken_b - Second token in the pairshare_token - LP token addressRequires admin authorization
fn add_pool(
env: soroban_sdk::Env,
pool_address: soroban_sdk::Address,
token_a: soroban_sdk::Address,
token_b: soroban_sdk::Address,
share_token: soroban_sdk::Address,
) -> Result
Updates a pool's active status.
Requires admin authorization
fn update_pool_status(
env: soroban_sdk::Env,
pool_id: u32,
active: bool,
) -> Result<(), soroban_sdk::Error>
Deposits tokens to a vault pool. User deposits token_a + token_b, contract adds liquidity to Aquarius pool.
user - User addresspool_id - Pool IDdesired_a - Amount of token_a to depositdesired_b - Amount of token_b to depositmin_shares - Minimum LP shares to receive (slippage protection)Requires user authorization
fn vault_deposit(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
pool_id: u32,
desired_a: i128,
desired_b: i128,
min_shares: u128,
) -> Result<(), soroban_sdk::Error>
Withdraws tokens from a vault pool. User withdraws their share, contract removes liquidity from Aquarius pool.
user - User addresspool_id - Pool IDshare_percent - Percentage of user's position to withdraw (0-10000 = 0-100%)min_a - Minimum amount of token_a to receive (slippage protection)min_b - Minimum amount of token_b to receive (slippage protection)Requires user authorization
fn vault_withdraw(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
pool_id: u32,
share_percent: u32,
min_a: u128,
min_b: u128,
) -> Result<(), soroban_sdk::Error>
Claims boosted rewards from a pool and auto-compounds. 30% to treasury, 70% auto-compound back to pool. Backend cron calls this 4x daily using ICE balance for boost.
pool_id - Pool ID to claim rewards fromRequires admin authorization
fn claim_and_compound(
env: soroban_sdk::Env,
pool_id: u32,
) -> Result<(), soroban_sdk::Error>
Gets pending AQUA available for ICE locking.
fn get_pending_aqua_for_ice(env: soroban_sdk::Env) -> Result
Gets all 4 ICE token balances.
fn get_all_ice_balances(
env: soroban_sdk::Env,
) -> Result<(i128, i128, i128, i128), soroban_sdk::Error>
Gets upvoteICE balance for voting.
fn get_upvote_ice_balance(env: soroban_sdk::Env) -> Result
Gets ICE lock authorization by ID.
fn get_ice_lock_authorization(
env: soroban_sdk::Env,
lock_id: u64,
) -> Result
Gets pool information by ID.
fn get_pool_info(
env: soroban_sdk::Env,
pool_id: u32,
) -> Result
Gets user's vault position in a specific pool.
fn get_user_vault_position(
env: soroban_sdk::Env,
user: soroban_sdk::Address,
pool_id: u32,
) -> Result
Gets total number of vault pools.
fn get_pool_count(env: soroban_sdk::Env) -> Result