This documentation outlines the functionality of the AaveDIVAWrapper contract.
- Overview
- Addressbook
- Terminology
- Contract overview
- Owner privileges
- Upgradeability
- Main user flows
- Invariants
- Function overview
- Miscellaneous
- Risk disclaimer
- Resources
AaveDIVAWrapper is a smart contract that acts as a connector between DIVA Protocol and Aave V3, allowing assets deposited into DIVA Protocol pools to generate yield by supplying them on Aave V3. The generated yield is claimable by the owner of the AaveDIVAWrapper contract.
The following diagram illustrates the high-level flow of funds. A technically more detailed flow is provided in the Main user flows section.
- User deposits funds (e.g., USDC) into AaveDIVAWrapper.
- AaveDIVAWrapper supplies these funds to Aave V3 for yield generation.
- AaveDIVAWrapper creates a new pool or adds liquidity to an existing pool in DIVA Protocol using a wrapped token (wToken) as collateral.
- The yield generated by Aave V3 is claimable by the owner.
This contract was originally designed for DIVA Donate on Arbitrum, a parametric conditional donations platform, which uses the yield to purchase insurance policies to increase donation payouts beyond the users' initial contributions. However, it can be utilized for any other use case enabled by DIVA Protocol (e.g., prediction markets, structured products, etc.). Users building on top of DIVA Protocol can deploy their own AaveDIVAWrapper instance and designate themselves as the yield recipient to receive a sustainable revenue stream.
To demonstrate the functionality of the AaveDIVAWrapper contract, let's compare two scenarios for Alice's contribution to a DIVA Donate campaign: one using direct DIVA Protocol interaction, and another utilizing the AaveDIVAWrapper.
- Alice contributes 100 USDC via DIVA Protocol through the DIVA Donate platform.
- When the outcome is reported, 100 USDC either go to the beneficiary (if drought conditions are met) or back to Alice.
- The 100 USDC sits idle in the pool during the campaign's lifetime; no yield is generated.
- Alice contributes 100 USDC via the AaveDIVAWrapper contract through the DIVA Donate platform.
- AaveDIVAWrapper supplies the 100 USDC on Aave which generates a yield of say 5 USDC during the campaign's lifetime.
- The owner of AaveDIVAWrapper can use this generated yield in several ways:
- Cover operational costs of running the platform.
- Distribute directly to beneficiaries when donation conditions are met.
- Purchase insurance policies to amplify potential payouts (e.g., using 5 USDC to buy a policy worth 20 USDC).
- A combination of the above.
- If a donation is triggered, the deposited 100 USDC is paid out to the farmer, along with any additional benefits from the yield usage (e.g., insurance payout or direct yield distribution), thereby increasing the impact of the donation. If no donation is triggered, the contributing user can redeem their 100 USDC from AaveDIVAWrapper (ignoring DIVA fees for simplicity).
- Supported tokens: The AaveDIVAWrapper accepts any token as collateral that is supported by Aave V3 (e.g., USDC, USDT, etc.) and that was registered in AaveDIVAWrapper by the owner.
- Fee-on-transfer tokens: As Aave V3 does not support fee-on-transfer tokens (see here), the AaveDIVAWrapper contract does not support them either.
- EIP-712: As opposed to DIVA Protocol, AaveDIVAWrapper does not support EIP-712 features in the current version. This is a minor limitation though since users can create markets via AaveDIVAWrapper, add liquidity to mint position tokens, and trade these positions on DEXs like 0x protocol that support EIP-712. EIP-712 features are planned for a future release.
- Aave V3: The AaveDIVAWrapper contract is built on Aave V3, which is an upgradeable protocol. For simplicity, all references to "Aave" or "Aave V3" in this documentation refer specifically to Aave V3.2.
- Outcome reporting: The oracle reporting process remains unchanged from DIVA Protocol's standard process. Data providers / oracles interact directly with DIVA Protocol and not via the AaveDIVAWrapper contract.
The following table provides an overview of the relevant protocol addresses for each available network and some example collateral tokens that can be used during the initialization of AaveDIVAWrapper.
Contract name | Address |
---|---|
AaveDIVAWrapper | to be added after deployment |
DIVA Protocol | 0x2C9c47E7d254e493f02acfB410864b9a86c28e1D |
Aave V3 (Pool contract) | 0x794a61358D6845594F94dc1DB02A252b5b4814aD |
Example collateral tokens | |
USDC (native) | 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 |
USDT | 0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9 |
The collateral token is the underlying asset (e.g., USDC, USDT) that users deposit into AaveDIVAWrapper. These tokens must be supported by Aave V3 and registered by the owner in AaveDIVAWrapper before they can be used.
The position token is the token representing the long or short position in a DIVA Protocol pool, minted by DIVA Protocol when users add liquidity to a pool.
ATokens are interest-bearing tokens that represent deposits in Aave markets. They have two key characteristics:
- They are rebaseable tokens, meaning their balances automatically increase over time as interest accrues.
- They maintain a 1:1 peg to the underlying asset (e.g., 1 aUSDC = 1 USDC).
When AaveDIVAWrapper supplies assets to an Aave market, it receives aTokens in return. The yield earned on the supplied assets is automatically reflected through an increase in the aToken balance in AaveDIVAWrapper's wallet. For more details, see the Aave documentation.
DIVA Protocol requires pool collateralization via non-rebasable ERC20 tokens to ensure stable pool accounting. Since Aave's aTokens are rebasable, they cannot be used directly as collateral in DIVA Protocol. To solve this, the AaveDIVAWrapper contract creates wrapped versions of collateral tokens (e.g., wUSDC for USDC), so-called wTokens, when the owner registers a collateral token via the registerCollateralToken
function that serve as proxy collateral in DIVA Protocol. These wrapped tokens are non-rebasable and redeemable 1:1 for the underlying collateral token, making them suitable for use as collateral in DIVA Protocol.
wTokens represent AaveDIVAWrapper's liability of the underlying asset (e.g., USDC) towards long and short token holders, with the total wToken supply reflecting the contract's total liability. Only the AaveDIVAWrapper contract has the authority to mint and burn wTokens.
While short and long tokens are collateralized with wTokens, they can be priced in the underlying asset (e.g., USDC) on DEXs like 0x protocol due to 1:1 redemption guarantee for the underlying asset. User's that redeem short or long tokens directly from DIVA Protocol for wTokens can always convert them into the underlying asset using AaveDIVAWrapper's redeemWToken
function.
The wToken address associated with a collateral token such as USDC or USDT can be retrieved via the getWToken
function.
When an asset like USDC is supplied to Aave, yield accrues as an increase in the AaveDIVAWrapper contract's aUSDC balance. The aUSDC amount in excess of the total wUSDC supply is the generated yield, claimable by the AaveDIVAWrapper contract's owner via the claimYield
function.
The main contracts are:
- IAaveDIVAWrapper: Interface for the AaveDIVAWrapper contract.
- AaveDIVAWrapperCore: An abstract contract that inherits from
IAaveDIVAWrapper
and implements the core functions of the AaveDIVAWrapper contract as internal functions. - AaveDIVAWrapper: The main contract that inherits from
AaveDIVAWrapperCore
and implements the core functionality of the AaveDIVAWrapper contract (including batch versions of the core functions) as external functions. That is the contract that users interact with. - WToken: The contract that represents a wrapped version of the collateral token. Deployed when the owner registers a collateral token via the
registerCollateralToken
function.
For contract addresses across different networks, refer to the respective address pages of DIVA Protocol and Aave V3. The documentation and codebases for both DIVA Protocol and Aave V3 can be found in the Resources section.
To deploy the AaveDIVAWrapper
contract, the following parameters must be provided:
diva_
: Address of the DIVA Protocol contract.aaveV3_
: Address of the Aave V3 contract.owner_
: Address of the owner of the contract, eligible to claim yield and register collateral tokens.
- Validate that none of the provided addresses are zero.
- Set the DIVA Protocol address (
_diva
) to the provideddiva_
address. - Set the Aave V3 Pool address (
_aaveV3Pool
) to the providedaaveV3Pool_
address. - Initialize the
Ownable
contract with the providedowner_
address.
Error | Condition | Contract/Library |
---|---|---|
ZeroAddress |
When the DIVA Protocol or Aave V3 Pool contract address is zero. | AaveDIVAWrapper |
OwnableInvalidOwner |
When the owner_ address is zero. |
Ownable (OpenZeppelin) |
Event | Description | Contract/Library |
---|---|---|
OwnershipTransferred |
Emitted when ownership is set to the initial owner. | Ownable2Step (OpenZeppelin) |
- Register collateral tokens (token must be supported by Aave V3)
- Claim yield
- Initiate process to update owner in a 2-step process
- AaveDIVAWrapper is immutable and cannot be upgraded.
- DIVA Protocol is immutable and cannot be upgraded.
- Aave V3 is upgradeable and has been upgraded already multiple times in the past. The development of the AaveDIVAWrapper contract is based on Aave V3.2. Due to AaveDIVAWrapper's reliance on only core functions (
supply()
,withdraw()
) and thegetReserveData()
getter function, breaking changes to their interfaces are deemed unlikely. You can view the changelogs for new version releases here.
The following sections provide an overview of the main user flows of the AaveDIVAWrapper contract in more technical detail.
The pool creation / liquidity addition flow is illustrated below:
- User (e.g. donor) deposits 100 USDC (the collateral token) via AaveDIVAWrapper's
createContingentPool
oraddLiquidity
function. - AaveDIVAWrapper supplies the 100 USDC to Aave (2a) and receives 100 rebasing aUSDC tokens (the aToken) (2b).
- AaveDIVAWrapper mints 100 wUSDC, a wrapped version of the collateral token, and uses it as proxy collateral when creating / adding liquidity to the DIVA Protocol pool.
- DIVA Protocol sends 100 long and 100 short tokens to the specified recipients (e.g., donor and farmer in the case of DIVA Donate).
The position token redemption flow is illustrated below. Note that for clarity, the diagram shows a simplified sequence - the actual implementation handles these steps in a slightly different order for security reasons.
- User (e.g. farmer) submits 100 short tokens for redemption to AaveDIVAWrapper via
redeemPositionToken
. - AaveDIVAWrapper redeems 100 aUSDC from Aave (2a) and receives 100 USDC (2b). aUSDC tokens are burnt during this process.
- AaveDIVAWrapper redeems the short tokens (3a) and receives 100 wUSDC from DIVA Protocol (3b). Short tokens are burnt during this process.
- AaveDIVAWrapper burns 100 wTokens and transfers 100 USDC to the user.
The same redemption process applies when redeeming long tokens or when redeeming both long and short tokens simultaneously via the removeLiquidity
function.
The yield claim flow is as follows:
- Owner calls the
claimYield
function to claim accrued yield. - AaveDIVAWrapper calculates the accrued yield by taking the excess of the aToken balance (e.g., 105) over the wToken supply (e.g., 100).
- AaveDIVAWrapper redeems 5 aUSDC from Aave for 5 USDC and transfers them to the owner.
At any point in time, the following invariants have to hold true:
aToken balance of AaveDIVAWrapper >= wToken supply
short token supply = long token supply = wToken supply
Function Name | Description |
---|---|
Core functions | |
createContingentPool | Creates a new contingent pool, adds liquidity and sends long and short tokens to specified recipients. |
addLiquidity | Adds collateral to an existing pool, mints new long and short position tokens and sends them to specified recipients. |
removeLiquidity | Removes collateral from an existing pool, burns long and short position tokens and sends the corresponding collateral amount to the specified recipient. |
redeemPositionToken | Redeems position tokens (short or long tokens) for the original collateral token (e.g., USDC) and sends it to the specified recipient. |
redeemWToken | Allows users to convert their wTokens for the underlying collateral asset. |
Owner controlled functions | |
registerCollateralToken | Registers a new collateral token that can be used in the protocol. |
claimYield | Allows the owner of the contract to claim the accrued yield. |
Batch functions | |
batchCreateContingentPool | Batch version of createContingentPool function. |
batchAddLiquidity | Batch version of addLiquidity function. |
batchRemoveLiquidity | Batch version of removeLiquidity function. |
batchRedeemPositionToken | Batch version of redeemPositionToken function. |
batchRedeemWToken | Batch version of redeemWToken function. |
batchRegisterCollateralToken | Batch version of registerCollateralToken function. |
batchClaimYield | Batch version of claimYield function. |
Non-core functions | |
approveCollateralTokenForAave | Function to reset the allowance of the collateral token for the Aave V3 contract to unlimited in an unlikely scenario that it runs out. |
View functions | |
getAccruedYield | Retrieves the accrued yield that is claimable by the AaveDIVAWrapper owner. |
getContractDetails | Returns the addresses of DIVA Protocol, Aave V3 Pool contract and owner. |
getWToken | Returns the wToken address for a given collateral token. |
getCollateralToken | Returns the collateral token address for a given wToken. |
Creates a new contingent pool in DIVA Protocol using the provided parameters. Long tokens are sent to PoolParams.longRecipient
and short tokens to PoolParams.shortRecipient
. The caller must approve AaveDIVAWrapper to transfer the collateral token before calling this function.
Returns the Id of the newly created pool.
function createContingentPool(PoolParams calldata _poolParams) external returns (bytes32);
The PoolParams
struct is defined as follows:
Parameter | Type | Description |
---|---|---|
referenceAsset |
string | The metric or event whose outcome will determine the payout for long and short tokens. |
expiryTime |
uint96 | Expiration time of the pool expressed as a unix timestamp in seconds (UTC). |
floor |
uint256 | Value of the reference asset at or below which the long token pays out 0 and the short token 1 (max payout), gross of fees. Input expects an integer with 18 decimals. |
inflection |
uint256 | Value of the reference asset at which the long token pays out gradient and the short token 1-gradient , gross of fees. Input expects an integer with 18 decimals. |
cap |
uint256 | Value of the reference asset at or above which the long token pays out 1 (max payout) and the short token 0, gross of fees. Input expects an integer with 18 decimals. |
gradient |
uint256 | A value between 0 and 1 which specifies the payout per long token if the outcome is equal to inflection . Input expects an integer with collateral token decimals. |
collateralAmount |
uint256 | Amount to be deposited into AaveDIVAWrapper, which is wrapped 1:1 into the wToken and deposited as collateral into the pool. Input expects an integer with collateral token decimals. |
collateralToken |
address | Address of the ERC20 collateral token (e.g., USDT). |
dataProvider |
address | Ethereum account (EOA or smart contract) that is supposed to report the final reference asset value following pool expiration. |
capacity |
uint256 | Maximum collateral amount that a contingent pool can accept. Choose a large number (e.g., 2**256 - 1 ) for unlimited size. Input expects an integer with collateral token decimals. |
longRecipient |
address | Address that shall receive the long token. Any burn address except for the zero address is a valid recipient to enable conditional burn use cases. |
shortRecipient |
address | Address that shall receive the short token. Any burn address except for the zero address is a valid recipient to enable conditional burn use cases. |
permissionedERC721Token |
address | Address of the ERC721 token that transfers are restricted to. Use zero address to render the long and short tokens permissionless. |
- Verify that
PoolParams.collateralToken
is registered in the AaveDIVAWrapper contract and has an associated wToken. - Transfer collateral token from caller to the AaveDIVAWrapper contract.
- Supply the collateral token to Aave V3 and receive aTokens into the AaveDIVAWrapper contract.
- Mint an equivalent amount of wTokens to the AaveDIVAWrapper contract.
- Create a new contingent pool on DIVA Protocol using the provided parameters and the minted wTokens as proxy collateral. Refer to the DIVA protocol documentation for more details.
- Send the resulting long and short tokens to the specified recipients.
- Emit a
PoolIssued
event. - Return the Id of the newly created pool.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenNotRegistered |
When PoolParams.collateralToken is not registered in AaveDIVAWrapper |
AaveDIVAWrapper |
ERC20InsufficientAllowance (wording depending on collateral token implementation) |
When caller has insufficient allowance. | ERC20 (collateralToken) |
ERC20InsufficientBalance (wording depending on collateral token implementation) |
When caller has insufficient balance. | ERC20 (collateralToken) |
Error code 26 | When PoolParams.collateralAmount is zero. |
Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 28 | When Aave V3 reserve is frozen. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
Error code 51 | When reserve's supply cap is exceeded. | Aave V3 |
InvalidInputParamsCreateContingentPool |
When pool parameters are invalid (see details below). | DIVA Protocol |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin). |
Note: Additional ERC20-specific revert conditions may apply (e.g., token may revert paused or when the
to
orfrom
address is blacklisted).
expiryTime
is smaller than or equal toblock.timestamp
referenceAsset
is an empty string.floor
is greater thaninflection
.cap
is smaller thaninflection
.cap
is greater than 1e59.dataProvider
is equal to the zero address.gradient
is greater than 1 base unit in collateral token terms.collateralAmount
exceedscapacity
.collateralToken
has more than 18 or less than 6 decimals.- Either
longRecipient
orshortRecipient
are equal to the zero address. Reverts withERC20: mint to the zero address
inside the long/short ERC20 token contract.
Event | Description | Contract/Library |
---|---|---|
PoolIssued |
Emitted when a new pool is created. | AaveDIVAWrapper |
Transfer |
Emitted during token transfers (safeTransferFrom , mint functions). |
ERC20 (collateralToken, wToken) |
Approval |
Emitted during token approvals (depends on token implementation; USDT on Ethereum does not emit an Approval event, for instance). |
ERC20 (collateralToken) |
Supply among others (Example) |
Emitted when supplying to Aave V3. | Aave V3 |
PoolIssued among others (Example) |
Emitted during pool creation on DIVA Protocol. | DIVA Protocol |
Adds _collateralAmount
of liquidity to an existing DIVA Protocol pool identified by the provided _poolId
. Long tokens are sent to _longRecipient
and short tokens to _shortRecipient
. The caller must approve AaveDIVAWrapper to transfer _collateralAmount
of the collateral token before calling this function.
function addLiquidity(
bytes32 _poolId, // The Id of the DIVA Protocol pool to add liquidity to
uint256 _collateralAmount, // The amount of collateral token to add as liquidity
address _longRecipient, // The recipient of the long tokens
address _shortRecipient // The recipient of the short tokens
) external;
- Verify that the collateral token used in the DIVA Protocol pool associated with
_poolId
corresponds to a registered collateral token in the AaveDIVAWrapper contract. - Transfer the collateral token from caller to the AaveDIVAWrapper contract.
- Supply the collateral token to Aave V3 and receive aTokens.
- Mint an equivalent amount of wTokens to the AaveDIVAWrapper contract.
- Add
_collateralAmount
of liquidity to the DIVA Protocol pool associated with the provided_poolId
using the minted wTokens. - Send the resulting long and short tokens to the specified recipients.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenNotRegistered |
When the pool's collateral token is not associated with a registered collateral token in AaveDIVAWrapper. | AaveDIVAWrapper |
ERC20InsufficientAllowance (wording depending on collateral token implementation) |
When caller has insufficient allowance. | ERC20 (collateralToken) |
ERC20InsufficientBalance (wording depending on collateral token implementation) |
When caller has insufficient balance. | ERC20 (collateralToken) |
Error code 26 | When _collateralAmount is zero. |
Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 28 | When Aave V3 reserve is frozen. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
Error code 51 | When reserve's supply cap is exceeded. | Aave V3 |
PoolExpired |
When the pool is already expired. | DIVA Protocol |
PoolCapacityExceeded |
When the pool capacity is exceeded. | DIVA Protocol |
ERC20: mint to the zero address |
When either _longRecipient or _shortRecipient are equal to the zero address. |
ERC20 (long/short tokens) |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin). |
Note: Additional ERC20-specific revert conditions may apply (e.g., when the token is paused or the
to
orfrom
address is blacklisted).
Event | Description | Contract/Library |
---|---|---|
Transfer |
Emitted during token transfers (safeTransferFrom , mint functions). |
ERC20 (collateralToken, wToken) |
Approval |
Emitted during token approvals (depends on token implementation; USDT on Ethereum does not emit an Approval event, for instance). |
ERC20 (collateralToken) |
Supply among others (Example) |
Emitted when supplying to Aave V3. | Aave V3 |
LiquidityAdded among others (Example) |
Emitted during liquidity addition to DIVA Protocol. | DIVA Protocol |
Removes liquidity from the pool associated with _poolId
by burning an equal amount (_positionTokenAmount
) of valid long and short tokens, and then transferring the corresponding collateral tokens (e.g., USDC) to the specified _recipient
. The caller must approve AaveDIVAWrapper to transfer both long and short tokens before calling this function.
Returns the amount of collateral tokens transferred to _recipient
, net of DIVA fees.
function removeLiquidity(
bytes32 _poolId, // The pool Id to remove liquidity from
uint256 _positionTokenAmount, // Amount of liquidity to remove (type(uint256).max = min short/long balance)
address _recipient // The address of the recipient to receive the collateral tokens
) external returns (uint256);
- Verify that the collateral token used in the DIVA Protocol pool associated with
_poolId
corresponds to a registered collateral token in the AaveDIVAWrapper contract. - Override
_positionTokenAmount
with the user's minimum short/long token balance if_positionTokenAmount
equalstype(uint256).max
. - Transfer the specified
_positionTokenAmount
of both short and long tokens from the caller to the AaveDIVAWrapper contract. - Remove liquidity from DIVA Protocol using the transferred short and long tokens, and get the wToken amount received.
- Verify that
_recipient
is not the zero address. - Burn the wTokens (AaveDIVAWrapper contract has the authority to do so as the owner).
- Withdraw the corresponding collateral tokens from Aave.
- Transfer the withdrawn collateral tokens to the specified
_recipient
. - Return the amount transferred.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenNotRegistered |
When the pool's collateral token is not associated with a registered collateral token in AaveDIVAWrapper. | AaveDIVAWrapper |
ERC20: insufficient allowance |
When caller has insufficient short or long token allowance. | ERC20 (short/long token) |
ERC20: transfer amount exceeds balance |
When caller has insufficient short or long token balance. | ERC20 (short/long token) |
ZeroAddress |
When _recipient is the zero address. |
AaveDIVAWrapper |
ReturnCollateralPaused |
When the DIVA Protocol is paused. | DIVA Protocol |
FinalValueAlreadyConfirmed |
When the final reference value has already been reported and confirmed. | DIVA Protocol |
ZeroProtocolFee or ZeroSettlementFee |
When _positionTokenAmount is small and renders the DIVA fee zero (if DIVA fee pct != 0). |
DIVA Protocol |
Error code 26 | When collateral amount to withdraw is zero. | Aave V3 |
Error code 93 | When _recipient is the same as the aToken address. |
Aave V3 |
Error code 32 | When aToken amount to redeem exceeds AaveDIVAWrapper contract's balance (should never happen). | Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin). |
Note: Will not revert if the Aave reserve is frozen (see here).
Event | Description | Contract/Library |
---|---|---|
WTokenRedeemed |
Emitted when wTokens are redeemed for collateral tokens. | AaveDIVAWrapper |
Transfer |
Emitted during token transfers. | ERC20 (short/long tokens) |
Approval |
Emitted during token approvals. | ERC20 (short/long tokens) |
LiquidityRemoved among others (Example) |
Emitted during liquidity removal in DIVA Protocol. | DIVA Protocol |
Withdraw among others (Example) |
Emitted when withdrawing from Aave V3. | Aave V3 |
- DIVA fees: The DIVA fee charged on the removal of liquidity is denominated in wToken (the pool's collateral token) and is withheld within DIVA Protocol, where it can be claimed by the respective owner. The wToken can then be converted into the underlying asset (e.g., USDC) via AaveDIVAWrapper's
redeemWToken
function.
Redeems _positionTokenAmount
of _positionToken
(short or long token) for the collateral token (e.g., USDC) and transfers it to the specified _recipient
. The caller must approve AaveDIVAWrapper to transfer the position tokens before calling this function.
Returns the amount of collateral tokens transferred to _recipient
, net of DIVA fees.
function redeemPositionToken(
address _positionToken, // The address of the position token to redeem
uint256 _positionTokenAmount, // Amount to redeem (type(uint256).max = caller's balance)
address _recipient // The recipient of the returned collateral tokens
) external returns (uint256);
- Verify that the pool's collateral token is associated with a registered wToken in the AaveDIVAWrapper contract.
- Override
_positionTokenAmount
with the user's position token balance if_positionTokenAmount
equalstype(uint256).max
. - Transfer the specified amount of position tokens from the caller to the AaveDIVAWrapper contract.
- Redeem the position token on DIVA Protocol and get the wToken amount received.
- Verify that
_recipient
is not the zero address. - Burn the wTokens (AaveDIVAWrapper contract has the authority to do so as the owner).
- Withdraw the corresponding collateral tokens from Aave.
- Transfer the withdrawn collateral tokens to the specified recipient.
- Return the amount transferred.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenNotRegistered |
When the pool's collateral token is not associated with a registered collateral token in AaveDIVAWrapper. | AaveDIVAWrapper |
ERC20: insufficient allowance |
When caller has insufficient position token allowance. | ERC20 (positionToken) |
ERC20: transfer amount exceeds balance |
When caller has insufficient position token balance. | ERC20 (positionToken) |
ZeroAddress |
When _recipient is the zero address. |
AaveDIVAWrapper |
ReturnCollateralPaused |
When the DIVA Protocol is paused. | DIVA Protocol |
FinalReferenceValueNotSet |
When no final reference value has been reported yet. | DIVA Protocol |
ChallengePeriodNotExpired |
When a final reference value has been reported, but the challenge period didn't expire yet. | DIVA Protocol |
ReviewPeriodNotExpired |
When a final reference value has been reported, but was challenged and the subsequent review period didn't expire yet. | DIVA Protocol |
Error code 26 | When collateral amount to withdraw is zero. | Aave V3 |
Error code 93 | When _recipient is the same as the aToken address. |
Aave V3 |
Error code 32 | When aToken amount to redeem exceeds AaveDIVAWrapper contract's balance (should never happen). | Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin). |
Note: Will not revert if the Aave reserve is frozen (see here).
Event | Description | Contract/Library |
---|---|---|
WTokenRedeemed |
Emitted when wTokens are redeemed for collateral tokens. | AaveDIVAWrapper |
Transfer |
Emitted during token transfers. | ERC20 (positionToken) |
Approval |
Emitted during token approvals. | ERC20 (positionToken) |
PositionTokenRedeemed among others (Example) |
Emitted during position token redemption. | DIVA Protocol |
Withdraw among others (Example) |
Emitted when withdrawing from Aave V3. | Aave V3 |
- DIVA fees: The DIVA fee charged on redemptionis denominated in wToken and is withheld within DIVA Protocol, where it can be claimed by the respective DIVA Protocol owner. The wToken can be converted via AaveDIVAWrapper's
redeemWToken
function into the underlying asset (e.g., USDC).
Converts the provided _wTokenAmount
of _wToken
into the underlying collateral token and transfers it to the specified _recipient
. Users that received wTokens, e.g., by redeeming their position tokens directly from DIVA Protocol or other direct interactions, can use this function to convert them into collateral tokens (e.g., USDC). No prior approval from the caller is required for this operation as the AaveDIVAWrapper contract has the authority to burn wTokens directly from the caller's balance.
Returns the amount of collateral tokens withdrawn from Aave and transferred to _recipient
.
function redeemWToken(
address _wToken, // The address of the wToken to convert
uint256 _wTokenAmount, // Amount to convert (type(uint256).max = caller's balance)
address _recipient // The address of the recipient to receive the collateral tokens
) external returns (uint256);
- Use the user's balance if
_wTokenAmount
equalstype(uint256).max
. - Burn the specified amount of wTokens from the caller's balance.
- Withdraw the corresponding amount of collateral tokens from Aave.
- Transfer the withdrawn collateral tokens to the specified
_recipient
. - Return the amount transferred.
Error | Condition | Contract/Library |
---|---|---|
ERC20InsufficientBalance |
When caller does not own the specified amount of wTokens. | ERC20 (wToken) |
ZeroAddress |
When _recipient is the zero address. |
AaveDIVAWrapper |
Error code 26 | When _wTokenAmount is zero. |
Aave V3 |
Error code 32 | When aToken amount to redeem exceeds AaveDIVAWrapper contract's balance (should never happen). | Aave V3 |
Error code 93 | When _recipient is the same as the aToken address. |
Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin). |
Note: Will not revert if the Aave reserve is frozen (see here).
Event | Description | Contract/Library |
---|---|---|
WTokenRedeemed |
Emitted when wTokens are redeemed for collateral tokens. | AaveDIVAWrapper |
Transfer |
Emitted during wToken burn operation. | ERC20 (wToken) |
Withdraw among others (Example) |
Emitted when withdrawing from Aave V3. | Aave V3 |
Registers a new _collateralToken
and returns the address of the corresponding wToken. Only callable by the owner.
Returns the address of the newly created wToken.
function registerCollateralToken(address _collateralToken) external returns (address);
- Verify that the provided
_collateralToken
is not yet registered. - Confirm that the provided
_collateralToken
is supported by Aave V3. - Deploy a new wToken contract to represent the wrapped version of the provided
_collateralToken
:- Set the symbol as "w" +
_collateralToken
symbol (e.g., wUSDT). - Set decimals to match the
_collateralToken
. - Set the AaveDIVAWrapper contract as the owner of the wToken.
- Set the symbol as "w" +
- Map the
_collateralToken
address to the newly created wToken address, and vice versa for reverse lookups. - Approve unlimited wToken transfers to DIVA Protocol.
- Approve unlimited
_collateralToken
transfers to Aave V3. - Emit a
CollateralTokenRegistered
event. - Return the address of the newly created wToken.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenAlreadyRegistered |
When _collateralToken is already registered. |
AaveDIVAWrapper |
UnsupportedCollateralToken |
When _collateralToken is not supported by Aave V3. |
AaveDIVAWrapper |
OwnableUnauthorizedAccount |
When function is called by an address that is not the owner. | Ownable2Step (OpenZeppelin). |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected | ReentrancyGuard (OpenZeppelin). |
Event | Description | Contract/Library |
---|---|---|
CollateralTokenRegistered |
Emitted when a new collateral token is registered. | AaveDIVAWrapper |
Approval |
Emitted when approving token transfers. | ERC20 (wToken) |
- Token decimals: wToken, aToken and collateral token have the same number of decimals.
- wToken ownership: The AaveDIVAWrapper contract is set as the owner of the wToken and has exclusive rights to mint and burn them.
- Unlimited approvals: The unlimited approvals are deemed safe as the
AaveDIVAWrapper
is a pass-through entity that does not hold excess wTokens or collateral tokens. Should a vulnerability be discovered in DIVA Protocol or Aave, users can simply stop interacting with theAaveDIVAWrapper
contract. - Allowance behavior: Granting an infinite allowance for wToken does not reduce the allowance on
transferFrom
as it uses a newer OpenZeppelin ERC20 implementation. However, this behavior may differ for collateral tokens like USDC, DAI, or WETH used in Aave. These tokens decrement the allowance with each use oftransferFrom
, even if an unlimited allowance is set. Consequently, though very unlikely, AaveDIVAWrapper could eventually exhaust its allowance. TheapproveCollateralTokenForAave
function has been implemented to manually reset the allowance for Aave to unlimited.
Transfers the yield accrued in the provided _collateralToken
to the specified _recipient
. Only callable by the owner of the contract. Partial yield claims are not supported.
Returns the amount of collateral token sent to _recipient
.
function claimYield(
address _collateralToken, // The address of the collateral token to claim yield for
address _recipient // The address of the recipient to whom the accrued yield will be transferred
) external returns (uint256);
- Verify that the caller is the contract owner (enforced by
onlyOwner
modifier). - Verify that the provided
_collateralToken
is registered. - Verify that the provided
_recipient
is not the zero address. - Calculate the accrued yield for the provided
_collateralToken
(AaveDIVAWrapper contract's aToken balance - wToken supply). - Withdraw the accrued yield from Aave V3.
- Transfer the withdrawn collateral token amount to the specified recipient.
- Emit a
YieldClaimed
event. - Return the amount claimed.
Error | Condition | Contract/Library |
---|---|---|
OwnableUnauthorizedAccount |
When the caller is not the owner of the contract. | Ownable2Step (OpenZeppelin) |
CollateralTokenNotRegistered |
When _collateralToken is not registered. |
AaveDIVAWrapper |
ZeroAddress |
When _recipient is the zero address. |
AaveDIVAWrapper |
Error code 26 | When the accrued yield is zero. | Aave V3 |
Error code 32 | When the calculated accrued yield exceeds AaveDIVAWrapper contract's aToken balance (should never happen). | Aave V3 |
Error code 27 | When Aave V3 reserve is inactive. | Aave V3 |
Error code 29 | When Aave V3 reserve is paused. | Aave V3 |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin) |
Note: Will not revert if the reserve is frozen (see here).
Event | Description | Contract/Library |
---|---|---|
YieldClaimed |
Emitted when yield is claimed by the owner. | AaveDIVAWrapper |
Withdraw among others (Example) |
Emitted when withdrawing from Aave V3. | Aave V3 |
- Yield calculation: The accrued yield is calculated as the difference between the AaveDIVAWrapper contract's aToken balance and the total supply of the associated wToken. If the aToken balance is smaller than the wToken supply (e.g., due to rounding), the function will revert with error code 26 from Aave V3. In this case, the owner should wait for more yield to accrue.
Resets the allowance of the provided _collateralToken
for the Aave V3 contract to unlimited, should it ever be depleted. Can be triggered by anyone. Using OpenZeppelin's safeIncreaseAllowance
to accommodate tokens like USDT on Ethereum that require the approval to be set to zero before setting it to a non-zero value.
function approveCollateralTokenForAave(address _collateralToken) external;
- Verify that the provided
_collateralToken
is registered in AaveDIVAWrapper contract. - Retrieve the current allowance of AaveDIVAWrapper contract for the
_collateralToken
on Aave V3. - Calculate the difference between the maximum possible allowance and the current allowance.
- Increase the allowance by this difference.
Error | Condition | Contract/Library |
---|---|---|
CollateralTokenNotRegistered |
When _collateralToken is not registered. |
AaveDIVAWrapper |
ReentrancyGuardReentrantCall |
When a reentrant call to the function is detected. | ReentrancyGuard (OpenZeppelin) |
Note: Additional token-specific revert conditions may apply depending on the token being approved.
Event | Description | Contract/Library |
---|---|---|
Approval |
Emitted when approving token transfers. | ERC20 (collateralToken) |
Batch version of createContingentPool
function.
function batchCreateContingentPool(
PoolParams[] calldata _poolParams
) external returns (bytes32[] memory);
See createContingentPool for the PoolParams
structure.
Batch version of addLiquidity
function.
function batchAddLiquidity(
AddLiquidityArgs[] calldata _addLiquidityArgs
) external;
where AddLiquidityArgs
is defined as follows:
struct AddLiquidityArgs {
bytes32 poolId;
uint256 collateralAmount;
address longRecipient;
address shortRecipient;
}
Batch version of removeLiquidity
function.
function batchRemoveLiquidity(
RemoveLiquidityArgs[] calldata _removeLiquidityArgs
) external returns (uint256[] memory);
where RemoveLiquidityArgs
is defined as follows:
struct RemoveLiquidityArgs {
bytes32 poolId;
uint256 positionTokenAmount;
address recipient;
}
Batch version of redeemPositionToken
function.
function batchRedeemPositionToken(
RedeemPositionTokenArgs[] calldata _redeemPositionTokenArgs
) external returns (uint256[] memory);
where RedeemPositionTokenArgs
is defined as follows:
struct RedeemPositionTokenArgs {
address positionToken;
uint256 positionTokenAmount;
address recipient;
}
Batch version of redeemWToken
function.
function batchRedeemWToken(
RedeemWTokenArgs[] calldata _redeemWTokenArgs
) external returns (uint256[] memory);
where RedeemWTokenArgs
is defined as follows:
struct RedeemWTokenArgs {
address wToken;
uint256 wTokenAmount;
address recipient;
}
Batch version of claimYield
function.
function batchClaimYield(
ClaimYieldArgs[] calldata _claimYieldArgs
) external returns (uint256[] memory);
where ClaimYieldArgs
is defined as follows:
struct ClaimYieldArgs {
address collateralToken;
address recipient;
}
Batch version of approveCollateralTokenForAave
function.
function batchApproveCollateralTokenForAave(
address[] calldata _collateralTokens
) external;
Returns the total yield accrued in AaveDIVAWrapper contract in the provided _collateralToken
and claimable by the owner. Returns zero if _collateralToken
is not registered or if the aToken balance is smaller than the wToken supply (e.g., due to rounding).
function getAccruedYield(address _collateralToken) external view returns (uint256);
Returns the DIVA Protocol and Aave V3 addresses the AaveDIVAWrapper contract is linked to as well as the owner of the contract.
function getContractDetails() external view returns (address, address, address);
Returns the address of the wToken associated with the provided _collateralToken
. Returns address(0)
if the provided _collateralToken
is not registered.
function getWToken(address _collateralToken) external view returns (address);
Returns the address of Aave V3's aToken associated with the provided _collateralToken
. Returns address(0)
if the provided _collateralToken
is not supported by Aave V3.
function getAToken(address _collateralToken) external view returns (address);
Returns the address of the collateral token associated with the provided _wToken
. Returns address(0)
if the provided _wToken
is not registered.
function getCollateralToken(address _wToken) external view returns (address);
- This contract does not implement
receive
orfallback
functions and, therefore, cannot accept Ether directly through plain transactions or manage calls to non-existent functions. - This contract does not support deposits in Ether. To support Ether deposits, an adapter contract like this one can be placed in front.
The use of any DeFi protocol comes with certain risks. Be responsible when interacting with the AaveDIVAWrapper contract and don't put in more funds than you are willing to lose. By interacting with AaveDIVAWrapper you acknowledge the following risks:
- Smart contract risk: Despite following best practices in Solidity coding and conducting a smart contract audit, bugs cannot be fully excluded. Only deposit amounts that you can afford to lose.
- Integration risk: The AaveDIVAWrapper contract integrates with Aave V3 and DIVA Protocol. Vulnerabilities or issues in either protocol (e.g., bad debt in Aave) may affect the functionality of AaveDIVAWrapper.
- Upgradeability of Aave V3: Aave V3's upgradeable nature may introduce breaking changes in future versions which could impact the functionality of the AaveDIVAWrapper contract. However, this risk is deemed low as the AaveDIVAWrapper contract only uses a limited number of Aave's core functions which are unlikely to see breaking changes (see Upgradeability section).