Liquid Finance Technical Specification
Last updated
Last updated
Introduction
This document describes the implementation of the Liquid Finance Smart Contract Layer.
The figure below is the core flows of contracts interaction:
With the current design, we have 8 contracts in total:
Liquid Staking: for staking, unstaking and claiming unstaked tokens.
Liquid Swap: acts as the swap contract for the liquid staking token to the native token.
Liquid Token: is cw20-base contract.
Liquid Treasury: store incentives for many different uses.
Multisig: the admin of all the contracts in the platform.
Group: contain the whitelist of members who can sign the multisig contract action.
Liquid Looping: make sure depositors’ ARCHs keep staying in the liquidity pool to receive LP rewards.
This contract is a staking pool for users to deposit native tokens in and receive liquid staking tokens in return. The contract bonds users tokens to a whitelist of validators and auto-compounds rewards (bond earned staking rewards) to increase the users interest rate.
New deposits are used to process users unstaking requests, so unstaking here can be faster than the typical unbonding duration.
Data Source
admin (Addr): should be multi-sig, is able to update the config.
pause_admin (Addr): should be single-sig, is able to pause the contract.
bond_denom (String): the denomination of the native token that can be staked.
liquid_token_addr (Addr): Liquid Token contract address.
swap_contract_addr (Addr): Liquid Swap contract address.
treasury_contract_addr (Addr): Liquid Treasury contract address.
team_wallet_addr (Addr): team wallet address.
commission_percentage (u16): percentage of commission taken off of staking rewards.
team_percentage (u16): percentage of rewards for the team.
liquidity_percentage (u16): percentage of rewards for the liquidity providers.
delegations (Vec<DelegationPercentage>): a whitelist of validators, each validator has a delegation percentage.
contract_state (Uint128): the state of contract (true is active, false is paused).
native (Uint128): total supply of native token pool.
unstakings (Uint128): total amount of native tokens in the unstaking queue.
claims (Uint128): total amount of native token reserved paying back those who unstaked.
maximum_processed (Uint128): max processing amount allowed in the queue in a processed_time period.
current_processed (Uint128): total processed amount in the queue for the current period.
processed_time (u64): the minimum number of blocks until the current_processed reset to Zero.
processed_period (Expiration): unstaking queue can only process after this period.
unstaking_time (u64): the minimum number of blocks between each contract unbond request.
unstaking_period (Expiration): contract only unbond from delegators after this period.
mint_cap (Uint128): max amount of liquid token can be minted.
CLAIMABLE (Map<&Addr, Uint128>): store the claimable native token amounts of each address.
UNDER_UNSTAKING (Map<&Addr, Uint128>): store the total native token amounts waiting in the unstaking queue of each address.
staking_linked_list: store unstaking queue data.
Messages
Stake { to: Option<String> } - Moves native tokens sent along the message to the staking pool, and gives back liquid staking tokens to the sender (or to the address sender put into the optional to param).
Claim {} - Gives sender their claimable unstaked native token, should be called after the sender's unstaking request is processed.
SetAdmin { admin: Option<String>, pause_admin: Option<String> } - Updates admin’s addresses, only the current admin can call this.
SetContractState { state: bool } - Updates contract state (active or paused), only the current admin and pause admin can call this.
SetLiquidToken { address: String } - Set the liquid token address, only the admin can call this. This can only be called once after deploying the liquid token contract.
SetRewardsConfig { swap_contract_addr: Option<String>, treasury_contract_addr: Option<String>, team_wallet_addr: Option<String>, commission_percentage: Option<u16>, team_percentage: Option<u16>, liquidity_percentage: Option<u16> } - Update the configs relate to the incentives handling of staking rewards.
SetLimitConfig { maximum_processed: Option<Uint128>, processed_time: Option<Uint128>, unstaking_time: Option<Uint128>, mint_cap: Option<Uint128> } - Update the limit configs.
SetDelegations { delegations: Vec<DelegationPercentage> } - Update the validators whitelist, only the admin can call this.
BondUnbondValidators {} - Bond available coin or unbond to process unstaking requests.
ProcessUnstakingQueue {} - Use available coin to process unstaking requests.
DistributeRewards {} - Distribute staking rewards.
BotRoutine {} Bot or users call this daily to multicall the following: DistributeRewards, ProcessUnstakingQueue, BondUnbondValidators.
Receive(Cw20ReceiveMsg) - handle Send messages from cw20 token contract, only the liquid token contract can call this. This is for the unstaking process.
Queries
ClaimableOf { address: String } - Returns the amount of native tokens the address can claim. Returns "0" if the address is unknown to the contract. Return type is:
ConfigInfo {} - Returns the configuration of the contract. Return type is:
StatusInfo {} - Returns the staking status of the contract. Return type is:
UnstakingQueue {} - Returns the first 50 nodes in the unstaking queue of the contract. Return type is:
UnderUnstakingOf { address: String } - Returns the total amount of native token the address has in the unstaking queue. Return type is:
LimitInfo {} - Returns the limit status of the contract. Return type is:
UnclaimedRewards { address: String } - Returns the unclaimed staking rewards. Return type is:
This contract is the instant unstaking swap pool for those who want to convert liquid staking tokens to native tokens without waiting for the delayed unstaking period. Liquidity providers for this pool receive some percentage of staking rewards from the Liquid Staking contract. Rewards contract receives the swap fee.
Data Source
admin (Addr): should be multi-sig, is able to update the config.
pause_admin (Addr): should be single-sig, is able to pause the contract.
bond_denom (String): the denomination of the native token that can be staked.
liquid_token_addr (Addr): Liquid Token contract address.
staking_manager_addr (Addr): Liquid Staking contract address.
treasury_contract_addr (Addr): Liquid Treasury contract address.
team_wallet_addr (Addr): team wallet address.
swap_fee_percentage (u16): percentage of liquid token taken as fee from instant unstakers.
team_percentage (u16): percentage of swap fee for the team.
liquidity_min (Uint128): minimal amount of new native token being added for liquidity.
contract_state (Uint128): the state of contract (true is active, false is paused).
liquidity (Uint128): the total amount of native token supplied to the liquidity pool.
issued (Uint128): total supply of rewards shares this contract has issued.
claims (Uint128): the total amount of swapped liquid token that liquidity providers can claim.
total_unclaimed (Uint128): the total amount of native token rewards that liquidity providers can claim.
CLAIMABLE (Map<&Addr, Uint128>): store the claimable staked token amount of each address.
UNCLAIMED (Map<&Addr, Uint128>): store the claimable native token amount of each address.
QUEUE_ID (Map<&Addr, Uint128>): store the linked list queue id of each address.
swap_linked_list: store liquidity queue data.
Messages
Add {} - Moves native tokens sent along the message to the swap pool, and updates sender account in the liquidity queue.
Remove {} - Liquidity providers call this to withdraw all their native tokens from the liquidity pool.
Claim {} - Gives sender his claimable swapped liquid token, and native token rewards for being liquidity provider.
SetAdmin { admin: Option<String>, pause_admin: Option<String> } - Updates admin’s addresses, only the current admin can call this.
SetContractState { state: bool } - Updates contract state (active or paused), only the current admin and pause admin can call this.
SetRewardsConfig { team_wallet_addr: Option<String>, swap_fee_percentage: Option<u16>, team_percentage: Option<u16> } - Update the configs relate to the incentives handling of swap fee.
SetLiquidityMin { liquidity_min: Uint128 } - Updates the minimum amount of native token being added as liquidity, only the admin can call this.
Receive(Cw20ReceiveMsg) - Handle Send messages from cw20 token contract. This is for swapping cw20 liquid token sender to native token.
Queries
ClaimableOf { address: String } - Returns the claimable swapped liquid token and native token rewards the address can claim. Return type is:
ConfigInfo {} - Returns the configuration of the contract. Return type is:
StatusInfo {} - Returns the staking status of the contract. Return type is:
OrderBook {} - Returns the first 50 orders in the liquidity queue. Return type is:
OrderInfoOf { address: String } - Returns the order info of the address in the liquidity queue. Return type is:
Simulation { offer_asset: Asset } - Return the amount of native token swapper should get. Return type is:
ReverseSimulation { ask_asset: Asset } - Return the amount of liquid token swapper should put in to get an ask_asset. Return type is:
The Liquid Treasury contract can be used to store incentives to be distributed towards different protocols, supplement the instant unstaking pool incentives, provide liquidity and/or be used as an insurance fund for slashing risk on the Liquid Staking ARCH pool.
Data Source
admin (Addr): able to update the config.
archway_rewards (Vec<ArchwayRewardsPercentage>): a whitelist of archway rewards receiver with percentage.
Messages
Distribute { asset_info: AssetInfo, to: Vec<SendingInfo> } - Sends a specific token, be native or cw20 token, to a list of receivers. Only the admin can call this.
SetAdmin { address: String } - Updates admin’s address, only the current admin can call this.
SetRewardsConfig{ archway_rewards: Vec } - Updates Archway rewards config, only the current admin can call this.
DistributeArchwayRewards {} - Claim and distribute archway rewards to whitelist receivers.
Queries
ConfigInfo {} - Returns the configuration of the contract. Return type is:
OutstandingRewards {} - Returns the claimable rewards of the contract. Return type is:
UnclaimedRewardsDistribution {} - Returns the detail of distribution for unclaimed archway rewards. Return type is:
This is the contract for liquidity providers to deposit ARCH tokens in order to automatically earn LP rewards without having to manually claim rewards, unstake swapped sARCH then re-add liquidity.
The figure below is the token flows of loop liquidity:
Data Source
admin (Addr): should be multi-sig, is able to update the config.
pause_admin (Addr): should be single-sig, is able to pause the contract.
bond_denom (String): the denomination of the native token that can be staked.
liquid_token_addr (Addr): Liquid Token contract address.
staking_manager_addr (Addr): Liquid Staking contract address.
swap_contract_addr (Addr): Liquid Swap contract address.
contract_state (Uint128): the state of contract (true is active, false is paused).
issued (Uint128): total supply of loop shares this contract has issued.
withdrawings (Uint128): total amount of native token in the withdrawing queue.
claims (Uint128): total amount of native tokens reserved for paying back those who withdrew their shares.
LOOP_SHARE (Map<&Addr, Uint128>): store the liquidity shares of each address.
CLAIMABLE (Map<&Addr, Uint128>): store the claimable native token amount of each address.
UNDER_WITHDRAWING (Map<&Addr, Uint128>): store the total native token amount waiting in the withdrawing queue of each address.
linked_list (staking_linked_list): store withdrawing queue data.
Messages
Deposit {} - Moves native tokens sent along the message to the instant unstaking liquidity pool, and gives back loop shares to the sender to represent his liquidity.
Withdraw { amount: Uint128 } - Withdraw liquidity from the instant unstaking liquidity pool by putting the representive loop shares amount in the param.
Claim {} - Gives sender his claimable withdrawn native token, should be called after sender’s withdrawing request is processed.
SetAdmin { admin: Option<String>, pause_admin: Option<String> } - Updates admin’s addresses, only the current admin can call this.
SetContractState { state: bool } - Updates contract state (active or paused), only the current admin and pause admin can call this.
Queries
Balance { address: String } - Returns the loop shares the address has that represents his liquidity. Returns "0" if the address is unknown to the contract. Return type is:
ClaimableOf { address: String } - Returns the amount of native token the address can claim. Returns "0" if the address is unknown to the contract. Return type is:
ConfigInfo {} - Returns the configuration of the contract. Return type is:
StatusInfo {} - Returns the status of the contract. Return type is:
WithdrawingQueue {} - Returns the first 50 nodes in the withdrawing queue of the contract. Return type is:
UnderWithdrawingOf { address: String } - Returns the total amount of native token the address has in the withdrawing queue. Return type is:
Validator multisig owns the Liquid Staking, Liquid Swap, Liquid Token, Multisig, Group and Liquid Looping smart contracts. Multisig signers are in charge of governing the upgradeability of these smart contracts, the addition/removal of multisig signers, the addition/removal of participants within the Validator set and changing the protocol’s configuration parameters.
Functions controlled by Validator multisig:
Liquid Staking
SetAdmin { admin: Option<String>, pause_admin: Option<String> }
SetContractState { state: bool }
SetRewardsConfig { swap_contract_addr: Option<String>, treasury_contract_addr: Option<String>, team_wallet_addr: Option<String>, commission_percentage: Option<u16>, team_percentage: Option<u16>, liquidity_percentage: Option<u16> }
SetLimitConfig { maximum_processed: Option<Uint128>, processed_time: Option<Uint128>, unstaking_time: Option<Uint128>, mint_cap: Option<Uint128> }
SetDelegations { delegations: Vec<DelegationPercentage> }
Liquid Swap
SetAdmin { admin: Option<String>, pause_admin: Option<String> }
SetContractState { state: bool }
SetRewardsConfig { team_wallet_addr: Option<String>, swap_fee_percentage: Option<u16>, team_percentage: Option<u16> }
SetLiquidityMin { liquidity_min: Uint128 }
Liquid Token
None
Multisig
Propose{title, description, msgs, earliest, latest}
Proposals should be limited to multisig participants only (This is not in the spec but left open to the implementation)
Vote{proposal_id, vote}
Voters should only be able to vote yes or no
Execute{proposal_id}
Close{proposal_id}
Group
Members are defined by an address and a weight.
Each member gets a weight of 1. If our multisig has 9 participants we will require a weight of 5 yes votes for the proposal to pass
UpdateAdmin{admin}
AddHook{addr}
RemoveHook{addr}
Liquid Looping
SetAdmin { admin: Option<String>, pause_admin: Option<String> }
SetContractState { state: bool }
Lydia Labs team wallet owns the Treasury smart contract. This will allow the LL team to distribute incentives across different strategies in an efficient manner.
Functions controlled by LL team wallet:
Treasury
Distribute { asset_info: AssetInfo, to: Vec<SendingInfo> }
SetAdmin { address: String }
SetRewardsConfig{ archway_rewards: Vec }