The aim of Idle Perpetual Yield Tranches is to pool capital of users (eg DAI), deposit it into a lending provider and split the interest received between 2 classes of users with different risk profiles.
One will gain more interest and will be more risky (BB or junior tranche) and the other will have a lower APR but more safety (AA or senior tranche). In the case of an hack or a loss of funds of the lending provider integrated (or any other protocol integrated by this provider), all funds still available will be used to refund senior tranche holders first with the aim of making them whole, and with remaining funds, if any, junior holders after.
There are no locking period or epochs and users are free to enter and exit at any time, the interest earned (and governance tokens, after being sold in the market) will be split between the two classes according to a dynamic ratio called trancheAPRSplitRatio
which is updated, based on the TVL of both tranches, at each deposit/redeem. The apr is variable for both classes of tranches.
https://docs.idle.finance/developers/perpetual-yield-tranches
The main contract which will be used by users is IdleCDO
which allows to deposit underlying and mint tranche tokens (ERC20), either AA or BB, and redeem principal+interest from it.
The IdleCDO uses an IIdleCDOStrategy
for interacting with a specific lending protocol. Governance tokens collected as rewards, are not redistributed to users directly in the IdleCDO contract but rather sold to the market (harvest
method) and the underlyings reinvested in the downstream lending provider where possible.
These are the main contracts used:
-
IdleCDO.sol: contract which holds all the users pooled assets (both underlyings, eg DAI, and interest bearing tokens, eg cDAI or aDAI) and entry point for the user to mint tranche tokens and burn them to redeem principal + interest. When users deposit into the CDO they will: update the global accounting of the system (ie split accrued rewards) and mint their chosen tranche tokens. Funds won't get put in lending right away. The
harvest
method will be called periodically to put new deposits in lending, get fees and update the accounting. During the harvest call rewards will be sold into the market (via uniswap) and released linearly over x (currently set a 6400) blocks, to increase the value of all tranche holders. On redeem users will burn their tranche tokens and get underlyings back. -
IdleCDOTranche.sol: ERC20 representing a specific (either AA or BB) tranche token. Only IdleCDO contract can mint and burn tranche tokens.
-
strategies/**.sol: strategies for lending assets in different lending providers.
yarn install
forge install
For foundry setup here
- One line change is needed in node_modules/@uniswap/v3-core/contracts/libraries/FullMath.sol to make compilation working see -> https://ethereum.stackexchange.com/questions/96642/unary-operator-minus-cannot-be-applied-to-type-uint256
Tests were initially done using Hardhat and then new ones with Foundry. Foundry tests are located in test/foundry/
and are the ones that should be used for testing new features.
New tests should be written using Foundry.
For unit tests run:
yarn test
For foundry tests (located in test/foundry/
)
first set in env the rpc url like so:
export ETH_RPC_URL=https://eth-mainnet.alchemyapi.io/v2/XXXXX
(if you need to run test on polygon zkEVM set POLYGON_ZK_RPC_URL
env var)
then run:
forge test -vvv
or
forge test -vvv --match-contract=MyTestContract
to run a specific test.
Deployment of new IdleCDOs is done with Hardhat using a factory contract which will deploy a new IdleCDO and initialize it with the correct params.
npx hardhat deploy-with-factory-params --network YOUR_CONFIGURED_NETWORK --cdoname CDO_NAME
CDO_NAME
should be the name of the key of the deployTokens
object in utils/addresses.js
with all params for deployment.
This is an example of config for deploying an IdleCDO with Lido strategy:
lido: {
underlying: mainnetContracts.stETH, // underlying token for the IdleCDO
decimals: 18, // underlying token decimals
proxyCdoAddress: CDOs.idleDAI.cdoAddr, // address of another IdleCDO where we will get the implementation to use
strategyName: 'IdleLidoStrategy', // name of the strategy contract
strategyParams: [ // strategy params for `initialize` call
mainnetContracts.wstETH,
mainnetContracts.stETH,
'owner' // The string 'owner' can be used to replace a specific address with the deployer of the strategy
],
AAStaking: false, // if rewards are distributed in IdleCDO to AA holders
BBStaking: false, // if rewards are distributed in IdleCDO to BB holders
stkAAVEActive: false, // if IdleCDO needs to manage stkAAVE
limit: '1000000', // deposit limit for this IdleCDO
AARatio: '10000' // Interest rate split for AA holders. `100000` means 100% to AA
},
Start with
anvil -f https://eth-mainnet.alchemyapi.io/v2/$ALCHEMY_API_KEY --fork-block-number XXXXX
Then run the deployment with hardhat script to deploy everything on anvil network
npx hardhat deploy-with-factory-params --cdoname cpwinusdc --network local
then run the forge test against anvil network (using the deployed IdleCDO address)
forge test --fork-url http://127.0.0.1:8545/ --match-contract=MyTest -vvv
Note this repo was built using hardhat so most tests and scripts are in js. Foundry was also recently integrated and we encourage all new contributions and features to be tested using the foundry toolkit.
We welcome new contributors and code contributions with open arms! Please be sure to follow our contribution guidelines when proposing any new code. Idle Finance is a decentralized protocol managed by a decentralized governance, any new code contributions are more likely to be accepted into future deployments and proposals if they have been openly discussed within the community first in our forum https://gov.idle.finance/