HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: high
Invalid

The registerCollateralToken Transaction Fails in runtime Due to Incorrect Return Type in getReserveData – Critical DoS, Rendering the Entire Protocol Unusable due to storage collision.

Summary

The IAave interface provides a function called getReserveData, which is designed to retrieve comprehensive reserve data for a given asset. This function returns critical information regarding the reserve's state and configuration. It requires an address parameter, representing the underlying asset of the reserve.

However, when executing a static call (staticCall) to this function, the transaction can get failed due to a mismatch in the expected return type defined in the interface function signature. This discrepancy leads to an invalid response, preventing successful data retrieval.

In simpler words: IAave Interface's getReserveData Call Fails Due to Return Type Mismatch – infects AaveDIVAWrapperCore and leads to a DoS.

The AaveDIVAWrapperCore contract utilizes the IAave interface, specifically calling IAave::getReserveData within the _registerCollateralToken function. This function is only accessible by the owner of AaveDIVAWrapper, as AaveDIVAWrapper::registerCollateralToken is restricted by the onlyOwner modifier and internally calls AaveDIVAWrapperCore::_registerCollateralToken.

Since, it is now established that IAave::getReserveData can get failed due to an incorrect struct return type, it is evident that the AaveDIVAWrapper::registerCollateralToken transaction will consistently revert, causing an internal execution halt due to invalid data retrieval.

Vulnerability Details

The function IAave::getReserveData is expected to return a struct named ReserveDataLegacy, which contains key reserve-related details associated with the input asset (token). This struct typically includes:

  • The aToken address (Aave's interest-bearing token)

  • The liquidity index

  • The reserve ID

  • The last update timestamp

  • Various borrow rates

  • Additional reserve-specific metadata

However, despite the interface defining ReserveDataLegacy as the return type, the actual implementation of Aave::getReserveData returns a different struct, named ReserveData. This version may contain different fields—potentially in a compact or expanded form—causing a type mismatch.

As a result, any contract or external caller relying on IAave::getReserveData can get failed to retrieve the expected data, leading to transaction failures and potential disruptions in protocols dependent on this function.

IAave::getReserveData: Reference link

function getReserveData(address asset) external view returns (ReserveDataLegacy memory);

Aave::getReserveData: Reference link

function getReserveData(address asset) external view virtual override returns (DataTypes.ReserveData memory)

Observe the differences in both function signatures. Additionally, the Aave implementation includes virtual and override modifiers, which may cause confusion for developers and auditors.

The primary distinction between the two functions lies in their return types.

IAave::getReserveData: return type is:

ReserveDataLegacy memory

Aave::getReserveData: return type is:

DataTypes.ReserveData memory

Please exclude DataTypes for clarity.

Specifically let's see the main differnece between both struct types.

Aave::ReserveDataLegacy: struct Reference link

struct ReserveDataLegacy {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//aToken address
@> address aTokenAddress;
//stableDebtToken address
address stableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
}

total 15 members in the ReserveDataLegacy.

Aave::ReserveData: struct Reference link

struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
uint40 liquidationGracePeriodUntil;
//aToken address
@> address aTokenAddress;
//stableDebtToken address
address stableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
//the amount of underlying accounted for by the protocol
uint128 virtualUnderlyingBalance;
}

There are a total of 17 members in the ReserveData struct, meaning it contains two additional members compared to the ReserveDataLegacy struct.

However, regardless of this difference, the function call can still fail in runtime even if both structs contain the specific members required by our protocol. Why?

Let's explore why transaction will fail in runtime...

AaveDIVAWrapperCore::_registerCollateralToken Reference Link

function _registerCollateralToken(address _collateralToken) internal returns (address) {
// Verify that the collateral token is not yet registered.
if (_collateralTokenToWToken[_collateralToken] != address(0)) {
revert CollateralTokenAlreadyRegistered();
}
// Retrieve the aToken address associated with the provided collateral token from Aave V3. Reverts if
// the collateral token is not supported by Aave V3.
// Note: aTokens have the same number of decimals as the collateral token: https://discord.com/channels/602826299974877205/636902500041228309/1249607036417867810
@> address _aToken = _getAToken(_collateralToken);
------------------------------^
if (_aToken == address(0)) {
revert UnsupportedCollateralToken();
}
IERC20Metadata _collateralTokenContract = IERC20Metadata(_collateralToken);
...
return _wToken;
}

The AaveDIVAWrapperCore::_registerCollateralToken calls _getAToken function...

AaveDIVAWrapperCore::_getAToken: Reference link

function _getAToken(address _collateralToken) internal view returns (address) {
return IAave(_aaveV3Pool).getReserveData(_collateralToken).aTokenAddress;
}

The AaveDIVAWrapperCore::_getAToken function calls IAave::getReserveData to retrieve the aTokenAddress and then returns it to its caller, AaveDIVAWrapperCore::_registerCollateralToken. We also have a getter of aToken in AaveDIVAWrapper contract.

AaveDIVAWrapper::getAToken: Reference link

function getAToken(address _collateralToken) external view override returns (address) {
return _getAToken(_collateralToken);
}

If there is a storage collision happend then it can be confirmed using this gettter.

However, since it is established that the IAave::getReserveData call can get failed at runtime due to an invalid struct return type, this results in a Denial of Service (DoS) for the protocol. As a consequence, any attempt to register a collateral token can consistently revert, rendering the entire protocol completely unusable.

This fundamental failure prevents the registration of new collateral tokens, blocking essential functionalities and halting protocol operations indefinitely.

Alternatively, the contract may allow the registration of collateral tokens that do not have their corresponding aTokens (Aave tokens). This could result in funds becoming permanently locked, as users would be unable to retrieve or interact with their assets.

Why is this happening?

This issue arises due to a storage slot clash. In the ReserveDataLegacy struct, the aTokenAddress is stored at slot 9, index 8, whereas in ReserveData, it is stored at slot 10, index 9.

Since the protocol expects to retrieve the aTokenAddress from slot 9, index 8 (as per ReserveDataLegacy), but the Aave contract actually retrieves data from ReserveData (or its cache version), the incorrect storage slot is accessed, leading to invalid data retrieval. This mismatch occurs entirely at the storage level, causing unpredictable behavior in the protocol.

We have already reviewed the ReserveDataLegacy and ReserveData structs. Now, let's examine the ReserveCache struct, as it is used to retrieve reserve data.

AaveV3::ReserveCache: Reference link

struct ReserveCache {
uint256 currScaledVariableDebt;
uint256 nextScaledVariableDebt;
uint256 currPrincipalStableDebt;
uint256 currAvgStableBorrowRate;
uint256 currTotalStableDebt;
uint256 nextAvgStableBorrowRate;
uint256 nextTotalStableDebt;
uint256 currLiquidityIndex;
uint256 nextLiquidityIndex;
uint256 currVariableBorrowIndex;
uint256 nextVariableBorrowIndex;
uint256 currLiquidityRate;
uint256 currVariableBorrowRate;
uint256 reserveFactor;
ReserveConfigurationMap reserveConfiguration;
@> address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
uint40 reserveLastUpdateTimestamp;
uint40 stableDebtLastUpdateTimestamp;
}

In AaveV3::ReserveCache, the aTokenAddress is stored at slot 16, index 15. However, when attempting to retrieve reserve data, slot 9, index 8 is accessed instead.

Now, what resides at slot 9, index 8? It’s the nextLiquidityIndex. This value can be zero, or if the collateralToken is unregistered, it may contain a non-zero value. In such a scenario, the protocol could mistakenly interpret this value as a valid aTokenAddress, leading to incorrect collateral registration.

As a result, an invalid, non-existent aTokenAddress could be assigned to an unregistered collateralToken. This critical flaw could cause user funds to become permanently locked within the protocol, as the incorrect aTokenAddress would prevent proper withdrawals or interactions with Aave. Since the protocol is unable to correct the erroneous registration due to interface bug, the funds could remain inaccessible indefinitely.

Proof of Concept

To demonstrate this vulnerability, a Proof of Concept (PoC) is provided below.

Note: The PoC is written using the Foundry tool.

  1. Step 1: Make a foundry project and put all the contracts in the src directory.

  2. Step 2: Create a test folder and mocks folder in the test and src directories respectively (or we already have a mocks folder in src).

  3. Step 3: Create all necessary mocks

  4. step 4: Create a test file with any name in the test directory.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;
import {Test, console} from "forge-std/Test.sol";
import {AaveMock} from "../src/mocks/AaveMock.m.sol";
import {AaveMockProper} from "../src/mocks/AaveMockProper.m.sol";
import {ATokenMock} from "../src/mocks/ATokenMock.m.sol";
import {DivaMock} from "../src/mocks/DivaMock.m.sol";
import {MockERC20} from "../src/mocks/MockERC20.sol";
import {MockLongToken} from "../src/mocks/MockLongToken.m.sol";
import {MockShortToken} from "../src/mocks/MockShortToken.m.sol";
import {MockUSDT} from "../src/mocks/MockUSDTEthereum.sol";
import {AaveDIVAWrapper} from "../src/AaveDIVAWrapper.sol";
import {WToken} from "../src/WToken.sol";
import {IAaveDIVAWrapper} from "../src/interfaces/IAaveDIVAWrapper.sol";
import {IAave} from "../src/interfaces/IAave.sol";
import {IAaveProper} from "../src/mocks/IAaveProper.i.sol";
contract AaveDivaWrapperTest is Test {
AaveDIVAWrapper aaveDivaWrapper;
DivaMock divaMock;
AaveMock aaveMock;
MockUSDT usdtMock;
address AAVE_DIVA_WRAPPER_OWNER = makeAddr("AAVE_DIVA_WRAPPER_OWNER");
address ALICE = makeAddr("ALICE");
address BOB = makeAddr("BOB");
address CHARLIE = makeAddr("CHARLIE");
address INTRUDER = makeAddr("INTRUDER");
address CHAINLINK_DATA_PROVIDER = makeAddr("CHAINLINK_DATA_PROVIDER");
address ERC721_PERMISSIONED_TOKEN = makeAddr("ERC721_PERMISSIONED_TOKEN");
// setUp function isn't that much necessary here
function setUp() public {
aaveMock = new AaveMock();
divaMock = new DivaMock();
usdtMock = new MockUSDT();
aaveMock.setAaveAllowedTokens(address(usdtMock));
vm.startPrank(AAVE_DIVA_WRAPPER_OWNER);
// AaveDIVAWrapper constructor
// constructor(address _aaveV3Pool, address _diva, address _owner)
aaveDivaWrapper = new AaveDIVAWrapper(address(aaveMock), address(divaMock), AAVE_DIVA_WRAPPER_OWNER);
vm.stopPrank();
}
}
  1. Step 5: Now, Put the following Test PoC in the test file adjacent to the setUp function.

    • Step 5: First Scenario: DoS Due to Retrieving a Zero Value from the Wrong Slot

  • ReserveData setting in the mock for this scenario, similarly we can assume for ReserveCache in the aave

reserveData[_collateralToken] = ReserveData({
configuration: ReserveConfigurationMap({data: 0}),
liquidityIndex: 0,
currentLiquidityRate: 2,
variableBorrowIndex: 0,
currentVariableBorrowRate: 0,
currentStableBorrowRate: 0,
lastUpdateTimestamp: 0,
id: uint16(uint256(bytes32(abi.encodePacked(msg.sender, block.timestamp, _collateralToken)))),
@> liquidationGracePeriodUntil: uint40(0),
@> aTokenAddress: address(aToken),
stableDebtTokenAddress: address(0),
variableDebtTokenAddress: address(0),
interestRateStrategyAddress: address(0),
accruedToTreasury: 0,
unbacked: 0,
isolationModeTotalDebt: 0,
virtualUnderlyingBalance: 242342342
});
function testRegisterCollateralTokenFailsAtRuntime() public {
// It's a correct one aave mock with correct ReserveData struct type
AaveMockProper aaveMockProper = new AaveMockProper();
// self defined function to mock aave
// just a mechanism to set tokens in allowed list
aaveMockProper.setAaveAllowedTokens(address(usdtMock));
vm.startPrank(AAVE_DIVA_WRAPPER_OWNER);
AaveDIVAWrapper avDvWrapper =
new AaveDIVAWrapper(address(aaveMockProper), address(divaMock), AAVE_DIVA_WRAPPER_OWNER);
vm.stopPrank();
vm.startPrank(AAVE_DIVA_WRAPPER_OWNER);
// however, the aaveDivaWrapper is using buggy IAave interface
// this will happen because different value picked because of storage clash
vm.expectRevert(bytes4(keccak256(abi.encodePacked("UnsupportedCollateralToken()"))));
avDvWrapper.registerCollateralToken(address(usdtMock));
// For another scenario: address wUSDTToken = avDvWrapper.registerCollateralToken(address(usdtMock));
vm.stopPrank();
// // For another scenario: both should be same but it's not true actually
// console.log("wToken : ", wToken); // wToken will be different because of storage collision
// console.log("wUSDTToken: ", wUSDTToken); // wUSDTToken was the actual token created on registration.
// assertNotEq(wToken, wUSDTToken);
}
  • Step 5: Second Scenario (Funds Locks)

    • This second scenario is also maybe possible (not sure about aaveV3 protocol)

    • owner registers an invalid collateral token

    • user creates a pool

    • user adds liquidity

    • remove liquidity reverts due to nonexistent token

  1. Step 6: Now, to run the test, run the following commands in the terminal in sequence:

forge test --mt testRegisterCollateralTokenFailsAtRuntime -vvvv
  1. Step 7: See the output of the test in the terminal, the output should be similar to the below one:

[⠊] Compiling...
No files changed, compilation skipped
Ran 1 test for test/AaveDivaWrapperTest.t.sol:AaveDivaWrapperTest
[PASS] testRegisterCollateralTokenFailsAtRuntime() (gas: 6725154)
Logs:
_aToken in AaveDIVAWrapperCore: 0x0000000000000000000000000000000000000001
wToken : 0x0000000000000000000000000000000000000001
wUSDTToken: 0xcC7708116F3875ad2CEe93e8A073C613A61d002B
Traces:
[6725154] AaveDivaWrapperTest::testRegisterCollateralTokenFailsAtRuntime()
├─ [266] MockUSDT::decimals() [staticcall]
│ └─ ← [Return] 6
├─ [266] MockUSDT::decimals() [staticcall]
│ └─ ← [Return] 6
├─ [1958669] → new AaveMockProper@0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9
│ └─ ← [Return] 9783 bytes of code
├─ [643367] AaveMockProper::setAaveAllowedTokens(MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a])
│ ├─ [3216] MockUSDT::symbol() [staticcall]
│ │ └─ ← [Return] "USDT"
│ ├─ [266] MockUSDT::decimals() [staticcall]
│ │ └─ ← [Return] 6
│ ├─ [519050] → new ATokenMock@0x5B0091f49210e7B2A57B03dfE1AB9D08289d9294
│ │ └─ ← [Return] 2253 bytes of code
│ └─ ← [Stop]
├─ [0] VM::startPrank(AAVE_DIVA_WRAPPER_OWNER: [0xE3956835e40e4731A03596C87534501ac1656f1E])
│ └─ ← [Return]
├─ [3359845] → new AaveDIVAWrapper@0x1e3726162d35b1830e94df5d6ad4af4c28643099
│ ├─ emit OwnershipTransferred(previousOwner: 0x0000000000000000000000000000000000000000, newOwner: AAVE_DIVA_WRAPPER_OWNER: [0xE3956835e40e4731A03596C87534501ac1656f1E])
│ └─ ← [Return] 16536 bytes of code
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::startPrank(AAVE_DIVA_WRAPPER_OWNER: [0xE3956835e40e4731A03596C87534501ac1656f1E])
│ └─ ← [Return]
├─ [661883] AaveDIVAWrapper::registerCollateralToken(MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a])
│ ├─ [3513] AaveMockProper::getReserveData(MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]) [staticcall]
│ │ └─ ← [Return] ReserveDataLegacy({ configuration: ReserveConfigurationMap({ data: 0 }), liquidityIndex: 0, currentLiquidityRate: 2, variableBorrowIndex: 0, currentVariableBorrowRate: 0, currentStableBorrowRate: 0, lastUpdateTimestamp: 0, id: 0, aTokenAddress: 0x0000000000000000000000000000000000000001, stableDebtTokenAddress: 0x0000000000000000000000000000000000000000, variableDebtTokenAddress: 0x0000000000000000000000000000000000000000, interestRateStrategyAddress: 0x0000000000000000000000000000000000000000, accruedToTreasury: 0, unbacked: 0, isolationModeTotalDebt: 0 })
│ ├─ [0] console::log("_aToken in AaveDIVAWrapperCore: ", ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ │ └─ ← [Stop]
│ ├─ [1216] MockUSDT::symbol() [staticcall]
│ │ └─ ← [Return] "USDT"
│ ├─ [266] MockUSDT::decimals() [staticcall]
│ │ └─ ← [Return] 6
│ ├─ [519050] → new WToken@0xcC7708116F3875ad2CEe93e8A073C613A61d002B
│ │ └─ ← [Return] 2253 bytes of code
│ ├─ [24739] WToken::approve(DivaMock: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ │ ├─ emit Approval(owner: AaveDIVAWrapper: [0x1e3726162d35b1830e94df5d6ad4af4c28643099], spender: DivaMock: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], value: 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ │ └─ ← [Return] true
│ ├─ [24821] MockUSDT::approve(AaveMockProper: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ │ ├─ emit Approval(owner: AaveDIVAWrapper: [0x1e3726162d35b1830e94df5d6ad4af4c28643099], spender: AaveMockProper: [0x5991A2dF15A8F6A256D3Ec51E99254Cd3fb576A9], value: 115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77])
│ │ └─ ← [Return] true
│ ├─ emit CollateralTokenRegistered(_collateralToken: MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a], _wToken: WToken: [0xcC7708116F3875ad2CEe93e8A073C613A61d002B])
│ └─ ← [Return] WToken: [0xcC7708116F3875ad2CEe93e8A073C613A61d002B]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [6132] AaveDIVAWrapper::getAToken(MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]) [staticcall]
│ ├─ [3513] AaveMockProper::getReserveData(MockUSDT: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a]) [staticcall]
│ │ └─ ← [Return] ReserveDataLegacy({ configuration: ReserveConfigurationMap({ data: 0 }), liquidityIndex: 0, currentLiquidityRate: 2, variableBorrowIndex: 0, currentVariableBorrowRate: 0, currentStableBorrowRate: 0, lastUpdateTimestamp: 0, id: 0, aTokenAddress: 0x0000000000000000000000000000000000000001, stableDebtTokenAddress: 0x0000000000000000000000000000000000000000, variableDebtTokenAddress: 0x0000000000000000000000000000000000000000, interestRateStrategyAddress: 0x0000000000000000000000000000000000000000, accruedToTreasury: 0, unbacked: 0, isolationModeTotalDebt: 0 })
│ └─ ← [Return] ECRecover: [0x0000000000000000000000000000000000000001]
├─ [0] console::log("wToken : ", ECRecover: [0x0000000000000000000000000000000000000001]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("wUSDTToken: ", WToken: [0xcC7708116F3875ad2CEe93e8A073C613A61d002B]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::assertNotEq(ECRecover: [0x0000000000000000000000000000000000000001], WToken: [0xcC7708116F3875ad2CEe93e8A073C613A61d002B]) [staticcall]
│ └─ ← [Return]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.85ms (591.10µs CPU time)

As demonstrated in the output, the test passes, confirming the presence of a Denial of Service (DoS) vulnerability in the protocol due to an invalid return type used in the IAave interface.

While I am not entirely certain about the exact behavior within the Aave V3 protocol, I am confident that a DoS scenario will occur from Aave’s end. This could happen due to token incompatibility, non-recoverable funds errors, or silent failures that ultimately trigger the AaveDIVAWrapper contract’s UnsupportedCollateralToken error, rendering the protocol unusable.

Impact

  • storage slot misalignment.

  • The symptom (incorrect data retrieval).

  • The impact (DoS + locked funds).

  • The irreversibility (permanent issue in non-upgradeable contracts).

Tools Used

  • Manual Review

  • Foundry

  • Foundry's console

  • Mutation Testing

  • Mocks

Recommendations

The Mitigation of this issue is simple, Please use ReserveData instead of ReserveDataLegacy struct type in the IAave Interface.

One Possible solution:

IAave:

interface IAave {
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60: asset is paused
//bit 61: borrowing in isolation mode is enabled
//bit 62: siloed borrowing enabled
//bit 63: flashloaning enabled
//bit 64-79: reserve factor
//bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap
//bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap
//bit 152-167 liquidation protocol fee
//bit 168-175 eMode category
//bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
//bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
//bit 252-255 unused
uint256 data;
}
- struct ReserveDataLegacy {
- //stores the reserve configuration
- ReserveConfigurationMap configuration;
- //the liquidity index. Expressed in ray
- uint128 liquidityIndex;
- //the current supply rate. Expressed in ray
- uint128 currentLiquidityRate;
- //variable borrow index. Expressed in ray
- uint128 variableBorrowIndex;
- //the current variable borrow rate. Expressed in ray
- uint128 currentVariableBorrowRate;
- //the current stable borrow rate. Expressed in ray
- uint128 currentStableBorrowRate;
- //timestamp of last update
- uint40 lastUpdateTimestamp;
- //the id of the reserve. Represents the position in the list of the active reserves
- uint16 id;
- //aToken address
- address aTokenAddress;
- //stableDebtToken address
- address stableDebtTokenAddress;
- //variableDebtToken address
- address variableDebtTokenAddress;
- //address of the interest rate strategy
- address interestRateStrategyAddress;
- //the current treasury balance, scaled
- uint128 accruedToTreasury;
- //the outstanding unbacked aTokens minted through the bridging feature
- uint128 unbacked;
- //the outstanding debt borrowed against this asset in isolation mode
- uint128 isolationModeTotalDebt;
- }
- struct ReserveData {
+ //stores the reserve configuration
+ ReserveConfigurationMap configuration;
+ //the liquidity index. Expressed in ray
+ uint128 liquidityIndex;
+ //the current supply rate. Expressed in ray
+ uint128 currentLiquidityRate;
+ //variable borrow index. Expressed in ray
+ uint128 variableBorrowIndex;
+ //the current variable borrow rate. Expressed in ray
+ uint128 currentVariableBorrowRate;
+ //the current stable borrow rate. Expressed in ray
+ uint128 currentStableBorrowRate;
+ //timestamp of last update
+ uint40 lastUpdateTimestamp;
+ //the id of the reserve. Represents the position in the list of the active reserves
+ uint16 id;
+ //timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
+ uint40 liquidationGracePeriodUntil;
+ //aToken address
+ address aTokenAddress;
+ //stableDebtToken address
+ address stableDebtTokenAddress;
+ //variableDebtToken address
+ address variableDebtTokenAddress;
+ //address of the interest rate strategy
+ address interestRateStrategyAddress;
+ //the current treasury balance, scaled
+ uint128 accruedToTreasury;
+ //the outstanding unbacked aTokens minted through the bridging feature
+ uint128 unbacked;
+ //the outstanding debt borrowed against this asset in isolation mode
+ uint128 isolationModeTotalDebt;
+ //the amount of underlying accounted for by the protocol
+ uint128 virtualUnderlyingBalance;
}
...
/**
* @notice Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state and configuration data of the reserve
*/
- function getReserveData(address asset) external view returns (ReserveDataLegacy memory);
+ function getReserveData(address asset) external view returns (ReserveData memory);
}
Updates

Lead Judging Commences

bube Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.