Skip to main content

Collateral

Why is there a need for collateral?#

Collateral is needed to ensure that platform doesn't suffer losses. User's collateral is kept as a CollateralEntry in an array of up to 32 different ones. It is kept inside ExchangeAccount together with an index to it.

Collateral allows users to have debt and to mint tokens up to the mint limit calculated based on it.

Deposit#

To have a collateral user has to deposit it. Method responsible for it takes amount (u64) and a following context:

struct Deposit<'info> {
pub state: Loader<'info, State>,
pub exchange_account: Loader<'info, ExchangeAccount>,
pub reserve_address: Account<'info, TokenAccount>,
pub user_collateral_account: Account<'info, TokenAccount>,
pub token_program: AccountInfo<'info>,
pub assets_list: Loader<'info, AssetsList>,
pub owner: AccountInfo<'info>,
pub exchange_authority: AccountInfo<'info>,
}
  • state - account with data of the program
  • exchange_account - account with user-specific data
  • reserve_address - account belonging to exchange where deposited collaterals are kept
  • user_collateral_account - user's account with deposited tokens
  • token_program - address of Solana's Token Program
  • assets_list - list of assets, structured as this
  • owner - the owner of the collateral, doesn't have to own an Exchange Account
  • exchange_authority - pubkey belonging to the exchange, used to sign transactions

Deposit instruction has to be preceded by an approval allowing exchange authority to transfer funds.

Withdrawal#

Unused collateral can be withdrawn. Tokens can be withdrawn up to a difference between debt and collateral value multiplied by health factor. Passing u64::MAX will withdraw maximum valid amount. Method is defined here, which takes amount (u64) and a following context:

pub struct Withdraw<'info> {
pub state: Loader<'info, State>,
pub assets_list: Loader<'info, AssetsList>,
pub exchange_authority: AccountInfo<'info>,
pub reserve_account: Account<'info, TokenAccount>,
pub user_collateral_account: Account<'info, TokenAccount>,
pub token_program: AccountInfo<'info>,
pub exchange_account: Loader<'info, ExchangeAccount>,
pub owner: AccountInfo<'info>,
}
  • state - account with data of the program
  • assets_list - list of assets, structured as this
  • exchange_authority - pubkey of the exchange
  • reserve_account - the account, where deposited tokens are kept. Must be the same as in Collateral struct
  • user_collateral_account - tokens where collateral will be sent
  • token_program - address of Solana's Token Program
  • exchange_account - account with user data
  • owner - the owner of the exchange account

Collateral in account#

Collateral is stored inside ExchangeAccount as one of up to 32 CollateralEntries. Each of them corresponds to different deposited token and look like this:

pub struct CollateralEntry {
pub amount: u64,
pub collateral_address: Pubkey,
pub index: u8,
}
  • amount - the amount of tokens, with decimals as in Collateral structure
  • collateral_address - address of deposited tokens
  • index - corresponds to the index of Collateral in AssetList

Liquidation#

When the value of user's debt in USD exceeds the value of their collateral, there is a risk of liquidation. This can happen due to a drop in the price of collateral tokens or an increase in debt per debt_share. When that happens and the account is checked (see below), liquidation deadline is set. If user doesn't deposit collateral after a certain buffer time or burn synthetics, account will be liquidated and part of the collateral taken.

Checking collateralization#

Function responsible for it is defined here. It takes minimal context of:

struct CheckCollateralization<'info> {
pub state: Loader<'info, State>,
pub exchange_account: Loader<'info, ExchangeAccount>,
pub assets_list: Loader<'info, AssetsList>,
}

The method calculates debt with the interest rate. as well as max_debt. based on collateral and compares them. If the debt is greater liquidation_deadline is set at the current slot increased by liquidation_buffer. When the slot number catches up to it user can be liquidated.

User Liquidation#

Liquidation method is defined here and takes amount (u64) and this context:

pub struct Liquidate<'info> {
pub state: Loader<'info, State>,
pub exchange_authority: AccountInfo<'info>,
pub assets_list: Loader<'info, AssetsList>,
pub token_program: AccountInfo<'info>,
pub usd_token: Account<'info, anchor_spl::token::Mint>,
pub liquidator_usd_account: Account<'info, TokenAccount>,
pub liquidator_collateral_account: Account<'info, TokenAccount>,
pub exchange_account: Loader<'info, ExchangeAccount>,
pub signer: AccountInfo<'info>,
pub liquidation_fund: Account<'info, TokenAccount>,
pub reserve_account: Account<'info, TokenAccount>,
}
  • state - account with data of the program
  • exchange_authority - pubkey belonging to the exchange, which is used to sing transactions
  • assets_list - list of assets containing prices
  • token_program - address of Solana's Token Program
  • usd_token - address of xUSD token
  • liquidator_usd_account - signer's account with xUSD tokens
  • liquidator_collateral_account - account with collateral tokens that is liquidated
  • exchange_account - account with data of the liquidated user
  • signer - liquidator that signed transaction
  • liquidation_fund - the account keeping liquidation penalty
  • reserve_account - the account with collateral tokens belonging to the exchange program

This method checks if liquidation_deadline has passed and debt exceeds the value of the collateral. If so, it proceeds to liquidate a specified amount, up to liquidation_rate of total collateral increased by liquidation penalties. Liquidator's xUSD is burned and liquidated user's debtshares decreases. Collateral, together with _penalty_to_liquidator, (percentage of liquidated amount) goes to a user's account and penalty_to_exchange to liquidation_fund.