The following document contains instructions on common usage of the Rari Stable Pool smart contracts' APIs.
- See
API.md
for a more detailed API reference onRariFundController
,RariFundManager
,RariFundToken
,RariFundPriceConsumer
, andRariFundProxy
. - See EIP-20: ERC-20 Token Standard for reference on all common functions of ERC20 tokens like RSPT.
- Smart contract ABIs are available in the
abi
properties of the JSON files in thebuild
folder.
If you're using JavaScript, don't waste your time directly integrating our smart contracts: the Rari JavaScript SDK makes programmatic deposits and withdrawals as easy as just one line of code!
- Get current raw APY (before fees):
- Get raw currency/subpool allocations (including unclaimed fees on interest):
(string[], uint256[], RariFundController.LiquidityPool[][], uint256[][], uint256[]) RariFundProxy.getRawFundBalancesAndPrices()
returns an array of currency codes, an array of corresponding fund controller contract balances for each currency code, an array of arrays of pool indexes for each currency code, an array of arrays of corresponding balances at each pool index for each currency code, and an array of prices in USD (scaled by 1e18) for each currency code. - Multiply the APY of each pool of each currency by its fund controller balance (converted to USD).
- Divide the sum of these products by the sum of all fund controller contract balances and pool balances of each currency (converted to USD) to get the current Stable Pool APY.
- Get raw currency/subpool allocations (including unclaimed fees on interest):
- Get current APY (after fees): subtract the product of the current raw APY and
uint256 RariFundManager.getInterestFeeRate()
divided by 1e18 from the current raw Stable Pool APY. - Get APY over time range (after fees):
- Get RSPT exchange rates at start and end of time range: divide
RariFundManager.getFundBalance()
byRariFundToken.totalSupply()
to get the exchange rate of RSPT in USD (scaled by 1e18). - Divide the ending exchange rate by the starting exchange rate, raise this quotient to the power of 1 year divided by the length of the time range, and subtract one to get the Stable Pool APY over this time range.
- Get RSPT exchange rates at start and end of time range: divide
- Get my USD balance supplied:
uint256 RariFundManager.balanceOf(address account)
returns the total balance in USD (scaled by 1e18) supplied to the Rari Stable Pool byaccount
. - Get my interest accrued: Subtract total deposits and transfers in (in USD) and add total withdrawals and transfers out (in USD) from
uint256 RariFundManager.balanceOf(address account)
.
- User chooses to deposit one of our directly supported tokens (DAI, USDC, USDT, TUSD, BUSD, and sUSD), ETH, or one of the tokens listed by the 0x swap tokens API (see documentation and endpoint) in an amount no greater than the balance of their Ethereum account.
- User calls
string[] RariFundManager.getAcceptedCurrencies()
to get an array of currency codes currently accepted for direct deposit to the Stable Pool.- If desired deposit currency is accepted:
- Generally, user simply approves tokens and deposits them:
- User approves tokens to
RariFundManager
by callingapprove(address spender, uint256 amount)
on the ERC20 contract of the desired input token wherespender
isRariFundManager
(to approve unlimited funds, setamount
touint256(-1)
). - Deposit with
bool RariFundManager.deposit(string currencyCode, uint256 amount)
- User approves tokens to
- To avoid paying gas, if the user's Ethereum account has no past deposit, the deposit amount is >= 250 USD, and the ETH balance returned by
RelayHub(0xd216153c06e857cd7f72665e0af1d7d82172f494).balanceOf(0xb6b79d857858004bf475e4a57d4a446da4884866)
is enough to cover the necessary gas, the user can submit their transaction via the Gas Station Network (GSN):- User approves tokens to
RariFundProxy
by callingapprove(address spender, uint256 amount)
on the ERC20 contract of the desired input token wherespender
isRariFundProxy
(to approve unlimited funds, setamount
touint256(-1)
). - To get the necessary approval data (a signature from our trusted signer allowing the user to use our ETH for gas), POST the JSON body
{ from, to, encodedFunctionCall, txFee, gasPrice, gas, nonce, relayerAddress, relayHubAddress }
tohttps://app.rari.capital/checkSig.php
.- Note that
checkSig.php
may go offline at some point in the future, in which case the user should deposit normally as described above.
- Note that
- User calls
bool RariFundProxy.deposit(string currencyCode, uint256 amount)
via the Gas Station Network (GSN).
- User approves tokens to
- Generally, user simply approves tokens and deposits them:
- If desired deposit currency is not accepted, get exchange data from mStable (preferably) and/or 0x:
- If desired deposit currency is DAI, USDC, USDT, sUSD, or mUSD, until the user fulfills their entire deposit, exchange to any depositable currency among DAI, USDC, USDT, sUSD, or mUSD via mStable and deposit:
- Get exchange output from mStable:
- If desired deposit currency is DAI, USDC, USDT, or sUSD and accepted currency is mUSD, check
(uint256 mintOutput) Masset(0xe2f2a5c287993345a840db3b0845fbc70f5935a5).getMintOutput(address _input, uint256 _inputQuantity)
. The user can exchange_inputQuantity
of_input
formintOutput
of mUSD. - If desired deposit currency is mUSD and accepted currency is DAI, USDC, USDT, or sUSD, check
(uint256 bAssetOutput) Masset(0xe15aad5d6b7433e5988415274529311f6bf6e8a3).getRedeemValidity(address _output, uint256 _mAssetQuantity)
. The user can exchange_mAssetQuantity
of mUSD forbAssetOutput
of_output
. - If desired deposit currency is DAI, USDC, USDT, or sUSD and accepted currency is DAI, USDC, USDT, or sUSD, check
(uint256 swapOutput) Masset(0xe2f2a5c287993345a840db3b0845fbc70f5935a5).getMintOutput(address _input, address _output, uint256 _inputQuantity)
. The user can exchange_inputQuantity
of_input
forswapOutput
of_output
.
- If desired deposit currency is DAI, USDC, USDT, or sUSD and accepted currency is mUSD, check
- User calls
bool RariFundProxy.exchangeAndDeposit(string inputCurrencyCode, uint256 inputAmount, string outputCurrencyCode)
to exchange and deposit.
- Get exchange output from mStable:
- If exchange via mStable is not possible (or if the user wants to exchange the rest of their deposit via 0x if mStable cannot exchange it all), retrieve order data from 0x:
- User retrieves data from 0x swap quote API (see documentation and endpoint) where:
sellToken
is their input currencybuyToken
is a directly depositable currency to which the desired deposit currency will be exchangedsellAmount
is the input amount to be sent by the user
- User approves tokens to
RariFundProxy
by callingapprove(address spender, uint256 amount)
on the ERC20 contract of the desired input token wherespender
isRariFundProxy
(to approve unlimited funds, setamount
touint256(-1)
). - User calls
bool RariFundProxy.exchangeAndDeposit(address inputErc20Contract, uint256 inputAmount, string outputCurrencyCode, LibOrder.Order[] orders, bytes[] signatures, uint256 takerAssetFillAmount)
where:orders
is the orders array returned by the 0x APIsignatures
in an array of signatures from the orders array returned by the 0x APItakerAssetFillAmount
is the input amount sent by the user
- User retrieves data from 0x swap quote API (see documentation and endpoint) where:
- If desired deposit currency is DAI, USDC, USDT, sUSD, or mUSD, until the user fulfills their entire deposit, exchange to any depositable currency among DAI, USDC, USDT, sUSD, or mUSD via mStable and deposit:
- If desired deposit currency is accepted:
- User ensures that their account possesses enough USD (represented internally by RSPT) to make their withdrawal.
- User calls
uint256 RariFundManager.getRawFundBalance(string currencyCode)
to get the raw total balance (currently held by the Stable Pool and available for direct withdrawal) of the desired withdrawal currency.- If the returned balance >= withdrawal amount, user calls
bool RariFundManager.withdraw(string currencyCode, uint256 amount)
- If returned balance < withdrawal amount:
- Until the whole withdrawal amount (including the directly withdrawable balance returned above) is filled, try to withdraw and exchange each of the other currencies held by the Stable Pool (DAI, USDC, USDT, TUSD, BUSD, sUSD, and mUSD) to the desired output currency:
- User calls
uint256 RariFundManager.getRawFundBalance(string currencyCode)
to get the raw total balance held by the Stable Pool of the potential input currency in question. - Get exchange input from mStable (preferably) and/or 0x:
- If output currency is DAI, USDC, USDT, sUSD, or mUSD, try exchanging via mStable.
- If exchange via mStable is not entirely profitable, retrieve order data from 0x:
- If the raw total balance of this input currency is enough to cover the remaining withdrawal amount, user retrieves data from the 0x swap quote API (see documentation and endpoint) where:
sellToken
is the input currency to be directly withdrawn from the Stable PoolbuyToken
is the output currency to be sent to the userbuyAmount
is the amount of output currency to be sent to the user in this exchange only
- If the raw total balance of this input currency is not enough to cover the remaining withdrawal amount, user retrieves data from the 0x swap quote API (see documentation and endpoint) where:
sellToken
is the input currency to be directly withdrawn from the Stable PoolbuyToken
is the output currency to be sent to the usersellAmount
is the raw total balance of this input currency
- If the raw total balance of this input currency is enough to cover the remaining withdrawal amount, user retrieves data from the 0x swap quote API (see documentation and endpoint) where:
- User calls
- User calls
bool RariFundProxy.withdrawAndExchange(string[] inputCurrencyCodes, uint256[] inputAmounts, address outputErc20Contract, LibOrder.Order[][] orders, bytes[][] signatures, uint256[] makerAssetFillAmounts, uint256[] protocolFees)
where:inputCurrencyCodes
is an array of input currency codes- To directly withdraw the output currency without exchange in the same transaction, simply include the output currency code in
inputCurrencyCodes
.
- To directly withdraw the output currency without exchange in the same transaction, simply include the output currency code in
inputAmounts
is an array of input currency amounts- To directly withdraw as much of the output currency without exchange in the same transaction, set the corresponding
inputAmounts
item to the directly withdrawable raw total balance of that currency.
- To directly withdraw as much of the output currency without exchange in the same transaction, set the corresponding
outputErc20Contract
is the ERC20 token contract address of the output currency to be sent to the userorders
is an array of orders arrays returned by the 0x API- To exchange one of
inputCurrencyCodes
via mStable or to directly withdraw the output currency in the same transaction, set the correspondingorders
item to an empty array.
- To exchange one of
signatures
is an array of arrays of signatures from the orders array returned by the 0x API- To exchange one of
inputCurrencyCodes
via mStable or to directly withdraw the output currency in the same transaction, set the correspondingsignatures
item to an empty array.
- To exchange one of
makerAssetFillAmounts
is an array of output currency amounts to be sent to the user- To exchange one of
inputCurrencyCodes
via mStable or to directly withdraw the output currency in the same transaction, set the correspondingmakerAssetFillAmounts
item to 0.
- To exchange one of
protocolFees
is an array of protocol fee amounts in ETH wei to be sent to 0x- To exchange one of
inputCurrencyCodes
via mStable instead of 0x or to directly withdraw the output currency in the same transaction, set the correspondingprotocolFees
item to 0.
- To exchange one of
- Until the whole withdrawal amount (including the directly withdrawable balance returned above) is filled, try to withdraw and exchange each of the other currencies held by the Stable Pool (DAI, USDC, USDT, TUSD, BUSD, sUSD, and mUSD) to the desired output currency:
- If the returned balance >= withdrawal amount, user calls
Your RSPT (Rari Stable Pool Token) balance is a token-based representation of your Rari Stable Pool balance.
- RSPT is minted to you when you deposit to the Stable Pool and redeemed (i.e., burned) when you withdraw from the Stable Pool.
- Accrued interest is constantly added to your USD balance supplied to the Stable Pool, meaning the USD value of your RSPT increases. However, your RSPT balance itself does not increase: instead, the exchange rate of RSPT increases at the same rate for every user as they accrue interest.
- When you transfer your RSPT, you transfer your holdings supplied to the Stable Pool (deposits + interest).
- Get RSPT exchange rate: Divide
RariFundManager.getFundBalance()
byRariFundToken.totalSupply()
to get the exchange rate of RSPT in USD (scaled by 1e18). - Get my RSPT balance (internal representation of my USD balance supplied):
uint256 RariFundToken.balanceOf(address account)
returns the amount of RSPT owned byaccount
. - Transfer RSPT:
bool RariFundToken.transfer(address recipient, uint256 amount)
transfersamount
RSPT torecipient
(as with other ERC20 tokens like RSPT). - Approve RSPT:
bool RariFundToken.approve(address spender, uint256 amount)
approvesspender
to spend the specifiedamount
of RSPT on behalf ofmsg.sender
.- As with the
approve
functions of other ERC20 contracts, beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: ethereum/EIPs#20 (comment)
- As with the
- See EIP-20: ERC-20 Token Standard for reference on all common functions of ERC20 tokens like RSPT.
- Get total USD supplied (by all users):
uint256 RariFundManager.getFundBalance()
returns the total balance supplied by users to the Rari Stable Pool (all RSPT holders' funds but not unclaimed fees) in USD (scaled by 1e18). - Get total interest accrued (by all users):
int256 RariFundManager.getInterestAccrued()
returns the total amount of interest accrued (excluding the fees paid on interest) by past and current Rari Stable Pool users (i.e., RSPT holders) in USD (scaled by 1e18).
See this Notion article for more information about fees and where they go.
Rari Capital currently takes a 9.5% performance fee on all interest accrued by the Rari Stable Pool.
- This fee is liable to change in the future, but the following method returns its current value at any time.
- Get interest fee rate:
uint256 RariFundManager.getInterestFeeRate()
returns the fee rate on interest (proportion of raw interest accrued scaled by 1e18).
Rari Capital currently takes a 0.5% withdrawal fee on all withdrawals from the Rari Yield Pool.
- This fee is liable to change in the future, but the following method returns its current value at any time.
- Get withdrawal fee rate:
uint256 RariFundManager.getWithdrawalFeeRate()
returns the withdrawal fee rate (proportion of every withdrawal taken as a service fee scaled by 1e18).
- Get raw currency/subpool allocations (including unclaimed fees on interest) and prices:
(string[], uint256[], RariFundController.LiquidityPool[][], uint256[][], uint256[]) RariFundProxy.getRawFundBalancesAndPrices()
returns an array of currency codes, an array of corresponding fund controller contract balances for each currency code, an array of arrays of pool indexes for each currency code, an array of arrays of corresponding balances at each pool index for each currency code, and an array of prices in USD (scaled by 1e18) for each currency code.
- Get stablecoin prices (used internally by contracts):
uint256[] RariFundPriceConsumer.getCurrencyPricesInUsd()
returns an array of prices in USD (scaled by 1e18) for all supported stablecoins to which funds can be allocated (DAI, USDC, USDT, TUSD, BUSD, sUSD, and mUSD, in that order).- Use these prices to calculate the value added to a user's USD balance due to a direct deposit and the value subtracted from a user's USD balance due to a direct withdrawal.