Native Credit Delegation (CD) is a new feature in Aave v2. It allows a depositor to deposit funds in the protocol to earn interest, and delegate borrowing power (i.e. their credit) to other users. The enforcement of the loan and its terms are agreed upon between the depositor and borrowers, which can be either off-chain via legal agreements or on-chain via smart contracts.
This enables:
The depositor (delegator) to earn extra yield on top of the yield they already earn from the protocol,
The borrowers (delegatees) to access an uncollateralized loan.
Follow the below steps to create your first Credit Delegation.
TL;DR: A starter example contract can be found on Kovan etherscan and Github code examples repo, with a twitter discussion here.
In the following guide, we refer to borrower
and delegatee
. However credit delegation allows the delegation to multiple users, so it can also be read as borrowers
and delegatees
.
The approveDelegation()
method must be called by the depositor (delegator), approving the borrower (delegatee) a certain amount.
This is done for each debt token that needs to be delegated.
The depositor (delegator) does not need to already have deposited funds in the protocol to approveDelegation()
. However, before the borrower (delegatee) executes borrow()
, there must be sufficient collateral assigned to the depositor (delegator) in the protocol.
// Import relevant interfacesimport './IAaveProtocolDataProvider.sol';import './IDebtToken.sol';​// ... beginning of your contract. Constructors etc...​// Within a relevant function in your contract:​// Get the Protocol Data ProviderIAaveProtocolDataProvider provider = IAaveProtocolDataProvider(address(INSERT_DATA_PROVIDER_ADDRESS));// Get the relevant debt token address(, address stableDebtTokenAddress, address variableDebtTokenAddress) = provider.getReserveTokensAddresses(INSERT_ASSET_ADDRESS);​// Relevant details for credit delegationaddress borrower = address(INSERT_BORROWER_ADDRESS);uint256 amountInWei = INSERT_DELEGATED_AMOUNT;// For stable debt tokensIDebtToken(stableDebtTokenAddress).approveDelegation(borrower, amountInWei);// For variable debt tokensIDebtToken(variableDebtTokenAddress).approveDelegation(borrower, amountInWei);​
// Import relevant ABIsimport IAaveProtocolDataProviderABI from './IAaveProtocolDataProviderAbi.json'import IDebtTokenABI from './IDebtToken.json'​// ... beginning of your code​// Within a relevant function in your code:​// Get the Aave Protocol Data Providerconst provider = new web3.eth.Contract(IAaveProtocolDataProviderABI, INSERT_DATA_PROVIDER_ADDRESS)​// Get the relevant debt token addressconst tokenDetails = await provider.methods.getReserveTokensAddresses(INSERT_ASSET_ADDRESS).call().catch((e) => {throw Error(`Error getting token details: ${e.message}`)})// Relevant details for credit delegationconst borrower = INSERT_BORROWER_ADDRESSconst amountInWei = INSERT_DELEGATED_AMOUNT// For stable debt tokensconst stableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.stableDebtTokenAddress)await stableDebtContract.methods.approveDelegation(borrower, amountInWei).send().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})// For variable debt tokensconst variableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.variableDebtTokenAddress)await variableDebtContract.methods.approveDelegation(borrower, amountInWei).send().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})​
The borrower (delegatee) calls the borrow()
method on the LendingPool
, using the depositor's (delegator's) address in final parameter onBehalfOf
.
// Import relevant interfacesimport './IAddressesProvider.sol';import './ILendingPool.sol';​// ... beginning of your contract. Constructors etc...​// Within a relevant function in your contract:​// Get the latest LendingPool contract for the relevant marketIAddressesProvider provider = IAddressesProvider(address(INSERT_ADDRESSES_PROVIDER_ADDRESS));ILendingPool lendingPool = ILendingPool(provider.getLendingPool());// Borrow the relevant amountaddress assetToBorrow = address(INSERT_ASSET_ADDRESS); // E.g. the address for Daiuint256 amountToBorrowInWei = INSERT_AMOUNT; // must be equal to or less than the amount delegated to the borroweruint256 interestRateMode = INSERT_INTEREST_RATE_MODE; // must be of the same type as the debt token that is delegated. I.e. stable = 1, variable = 2.uint16 referralCode = INSERT_REFERRAL_CODE;address delegatorAddress = INSERT_DELEGATOR_ADDRESS;lendingPool.borrow(assetToBorrow, amountToBorrowInWei, interestRateMode, referralCode, delegatorAddress);
// Import relevant ABIsimport IAddressProviderABI from './IAddressesProviderAbi.json'import ILendingPoolABI from './ILendingPool.json'​// ... beginning of your code​// Within a relevant function in your code:​// Get the latest LendingPool contract for the relevant marketconst provider = new web3.eth.Contract(IAddressProviderABI, INSERT_ADDRESSES_PROVIDER_ADDRESS)const lendingPoolAddress = await provider.methods.getLendingPool().call().catch((e) => {throw Error(`Error getting lendingPool address: ${e.message}`)})const lendingPoolContract = new web3.eth.Contract(ILendingPoolABI, lendingPoolAddress)// Borrow the relevant amountconst assetToBorrow = INSERT_ASSET_ADDRESS; // E.g. the address for Daiconst amountToBorrowInWei = INSERT_AMOUNT; // must be equal to or less than the amount delegated to the borrowerconst interestRateMode = INSERT_INTERST_RATE_MODE; // must be of the same type as the debt token that is delegated. I.e. stable = 1, variable = 2.const referralCode = INSERT_REFERRAL_CODE;const delegatorAddress = INSERT_DELEGATOR_ADDRESS;await lendingPoolContract.methods.borrow(assetToBorrow,amountToBorrowInWei,interestRateMode,referralCode,delegatorAddress).send().catch((e) => {throw Error(`Error borrowing: ${e.message}`)})​
The borrower (delegatee) can also call repay()
at anytime to repay their uncollateralized loan, passing in the depositor's (delegator's) address as the final parameter onBehalfOf
.
// Import relevant interfacesimport './IAddressesProvider.sol';import './ILendingPool.sol';​// ... beginning of your contract. Constructors etc...​// Within a relevant function in your contract:​// Get the latest LendingPool contract for the relevant marketIAddressesProvider provider = IAddressesProvider(address(INSERT_ADDRESSES_PROVIDER_ADDRESS));ILendingPool lendingPool = ILendingPool(provider.getLendingPool());// Repay the relevant amountaddress assetToRepay = address(INSERT_ASSET_ADDRESS); // E.g. the address for Daiuint256 amountToRepayInWei = INSERT_AMOUNT; // must be equal to or less than the amount delegated to the borrower=uint256 interestRateMode = INSERT_INTEREST_RATE_MODE; // must be of the same type as the debt token that is delegated. I.e. stable = 1, variable = 2.address delegatorAddress = INSERT_DELEGATOR_ADDRESS;lendingPool.repay(assetToRepay, amountToRepayInWei, interestRateMode, delegatorAddress);
// Import relevant ABIsimport IAddressProviderABI from './IAddressesProviderAbi.json'import ILendingPoolABI from './ILendingPool.json'​// ... beginning of your code​// Within a relevant function in your code:​// Get the latest LendingPool contract for the relevant marketconst provider = new web3.eth.Contract(IAddressProviderABI, INSERT_ADDRESSES_PROVIDER_ADDRESS)const lendingPoolAddress = await provider.methods.getLendingPool().call().catch((e) => {throw Error(`Error getting lendingPool address: ${e.message}`)})const lendingPoolContract = new web3.eth.Contract(ILendingPoolABI, lendingPoolAddress)// Borrow the relevant amountconst assetToRepay = INSERT_ASSET_ADDRESS; // E.g. the address for Daiconst amountToRepayInWei = INSERT_AMOUNT; // must be equal to or less than the amount delegated to the borrowerconst delegatorAddress = INSERT_DELEGATOR_ADDRESS;await lendingPoolContract.methods.repay(assetToRepay,amountToRepayInWei,delegatorAddress).send().catch((e) => {throw Error(`Error repaying: ${e.message}`)})​
To increase a borrower's available credit, the approveDelegation()
method should be called again, setting the total amount that the borrower (delegatee) should now have access to, including any outstanding borrow amounts they have already performed.
This is done for each debt token that requires an increase.
// Import relevant interfacesimport './IAaveProtocolDataProvider.sol';import './IDebtToken.sol';​// ... beginning of your contract. Constructors etc...​// Within a relevant function in your contract:​// Get the Protocol Data ProviderIAaveProtocolDataProvider provider = IAaveProtocolDataProvider(address(INSERT_DATA_PROVIDER_ADDRESS));// Get the relevant debt token address(, address stableDebtTokenAddress, address variableDebtTokenAddress) = provider.getReserveTokensAddresses(INSERT_ASSET_ADDRESS);​// Relevant details for credit delegationaddress borrower = address(INSERT_BORROWER_ADDRESS);uint256 amountInWei = INSERT_DELEGATED_AMOUNT; // This is the total amount to be delegated (not just the increase)// For stable debt tokensIDebtToken(stableDebtTokenAddress).approveDelegation(borrower, amountInWei);// For variable debt tokensIDebtToken(variableDebtTokenAddress).approveDelegation(borrower, amountInWei);​
// Import relevant ABIsimport IAaveProtocolDataProviderABI from './IAaveProtocolDataProviderAbi.json'import IDebtTokenABI from './IDebtToken.json'​// ... beginning of your code​// Within a relevant function in your code:​// Get the Aave Protocol Data Providerconst provider = new web3.eth.Contract(IAaveProtocolDataProviderABI, INSERT_DATA_PROVIDER_ADDRESS)​// Get the relevant debt token addressconst tokenDetails = await provider.methods.getReserveTokensAddresses(INSERT_ASSET_ADDRESS).call().catch((e) => {throw Error(`Error getting token details: ${e.message}`)})// Relevant details for credit delegationconst borrower = INSERT_BORROWER_ADDRESSconst amountInWei = INSERT_DELEGATED_AMOUNT // This is the total amount to be delegated (not just the increase)// For stable debt tokensconst stableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.stableDebtTokenAddress)await stableDebtContract.methods.approveDelegation(borrower, amountInWei).send().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})// For variable debt tokensconst variableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.variableDebtTokenAddress)await variableDebtContract.methods.approveDelegation(borrower, amountInWei).send().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})​
To check the current allowance of a user, simply call borrowAllowance()
passing in the depositor (delegator) and borrower (delegatee) addresses.
This is done for each debt token that is delegated.
// Import relevant interfacesimport './IAaveProtocolDataProvider.sol';import './IDebtToken.sol';​// ... beginning of your contract. Constructors etc...​// Within a relevant function in your contract:​// Get the Protocol Data ProviderIAaveProtocolDataProvider provider = IAaveProtocolDataProvider(address(INSERT_DATA_PROVIDER_ADDRESS));// Get the relevant debt token address(, address stableDebtTokenAddress, address variableDebtTokenAddress) = provider.getReserveTokensAddresses(INSERT_ASSET_ADDRESS);​// Relevant details for credit delegationaddress delegator = address(INSERT_DEPOSITOR_ADDRESS)address delegatee = address(INSERT_BORROWER_ADDRESS);// For stable debt tokensuint256 stableAllowance = IDebtToken(stableDebtTokenAddress).borrowAllowance(delegator, delegatee);// For variable debt tokensuint256 variableAllowance = IDebtToken(variableDebtTokenAddress).borrowAllowance(delegator, delegatee);​
// Import relevant ABIsimport IAaveProtocolDataProviderABI from './IAaveProtocolDataProviderAbi.json'import IDebtTokenABI from './IDebtToken.json'​// ... beginning of your code​// Within a relevant function in your code:​// Get the Aave Protocol Data Providerconst provider = new web3.eth.Contract(IAaveProtocolDataProviderABI, INSERT_DATA_PROVIDER_ADDRESS)​// Get the relevant debt token addressconst tokenDetails = await provider.methods.getReserveTokensAddresses(INSERT_ASSET_ADDRESS).call().catch((e) => {throw Error(`Error getting token details: ${e.message}`)})// Relevant details for credit delegationconst delegator = INSERT_DEPOSITOR_ADDRESSconst delegatee = INSERT_BORROWER_ADDRESS// For stable debt tokensconst stableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.stableDebtTokenAddress)const stableAllowance = await stableDebtContract.methods.borrowAllowance(delegator, delegatee).call().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})// For variable debt tokensconst variableDebtContract = new web3.eth.Contract(IDebtTokenABI, tokenDetails.variableDebtTokenAddress)const variableAllowance = await variableDebtContract.methods.borrowAllowance(delegator, delegatee).call().catch((e) => {throw Error(`Error approving delegation: ${e.message}`)})​
​