Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion snapshots/NativeTokenGateway.Operations.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"borrowNative": "228557",
"borrowNative": "227819",
"repayNative": "166460",
"supplyAsCollateralNative": "160122",
"supplyNative": "135753",
Expand Down
2 changes: 1 addition & 1 deletion snapshots/SignatureGateway.Operations.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"borrowWithSig": "213790",
"borrowWithSig": "213421",
"repayWithSig": "186732",
"setSelfAsUserPositionManagerWithSig": "75118",
"setUsingAsCollateralWithSig": "85387",
Expand Down
8 changes: 4 additions & 4 deletions snapshots/Spoke.Getters.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"getUserAccountData: supplies: 0, borrows: 0": "13014",
"getUserAccountData: supplies: 1, borrows: 0": "49426",
"getUserAccountData: supplies: 2, borrows: 0": "81102",
"getUserAccountData: supplies: 2, borrows: 1": "101454",
"getUserAccountData: supplies: 2, borrows: 2": "120714"
"getUserAccountData: supplies: 1, borrows: 0": "49057",
"getUserAccountData: supplies: 2, borrows: 0": "80364",
"getUserAccountData: supplies: 2, borrows: 1": "100347",
"getUserAccountData: supplies: 2, borrows: 2": "119238"
}
34 changes: 17 additions & 17 deletions snapshots/Spoke.Operations.ZeroRiskPremium.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"borrow: first": "190296",
"borrow: second action, same reserve": "170162",
"liquidationCall (receiveShares): full": "303081",
"liquidationCall (receiveShares): partial": "302499",
"liquidationCall (reportDeficit): full": "367565",
"liquidationCall: full": "320706",
"liquidationCall: partial": "320124",
"borrow: first": "189558",
"borrow: second action, same reserve": "169424",
"liquidationCall (receiveShares): full": "300867",
"liquidationCall (receiveShares): partial": "300285",
"liquidationCall (reportDeficit): full": "366089",
"liquidationCall: full": "318492",
"liquidationCall: partial": "317910",
"permitReserve + repay (multicall)": "164565",
"permitReserve + supply (multicall)": "146745",
"permitReserve + supply + enable collateral (multicall)": "161196",
Expand All @@ -17,18 +17,18 @@
"supply: 0 borrows, collateral disabled": "122835",
"supply: 0 borrows, collateral enabled": "105806",
"supply: second action, same reserve": "105735",
"updateUserDynamicConfig: 1 collateral": "74545",
"updateUserDynamicConfig: 2 collaterals": "89413",
"updateUserRiskPremium: 1 borrow": "95657",
"updateUserRiskPremium: 2 borrows": "105337",
"updateUserDynamicConfig: 1 collateral": "74176",
"updateUserDynamicConfig: 2 collaterals": "88675",
"updateUserRiskPremium: 1 borrow": "94919",
"updateUserRiskPremium: 2 borrows": "104599",
"usingAsCollateral: 0 borrows, enable": "59616",
"usingAsCollateral: 1 borrow, disable": "105701",
"usingAsCollateral: 1 borrow, disable": "104963",
"usingAsCollateral: 1 borrow, enable": "42504",
"usingAsCollateral: 2 borrows, disable": "127250",
"usingAsCollateral: 2 borrows, disable": "126143",
"usingAsCollateral: 2 borrows, enable": "42516",
"withdraw: 0 borrows, full": "127944",
"withdraw: 0 borrows, partial": "132840",
"withdraw: 1 borrow, partial": "159894",
"withdraw: 2 borrows, partial": "174452",
"withdraw: 0 borrows, full": "127575",
"withdraw: 0 borrows, partial": "132471",
"withdraw: 1 borrow, partial": "159156",
"withdraw: 2 borrows, partial": "173345",
"withdraw: non collateral": "105891"
}
34 changes: 17 additions & 17 deletions snapshots/Spoke.Operations.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"borrow: first": "259220",
"borrow: second action, same reserve": "202086",
"liquidationCall (receiveShares): full": "335114",
"liquidationCall (receiveShares): partial": "334532",
"liquidationCall (reportDeficit): full": "359765",
"liquidationCall: full": "352739",
"liquidationCall: partial": "352157",
"borrow: first": "258482",
"borrow: second action, same reserve": "201348",
"liquidationCall (receiveShares): full": "332900",
"liquidationCall (receiveShares): partial": "332318",
"liquidationCall (reportDeficit): full": "358289",
"liquidationCall: full": "350525",
"liquidationCall: partial": "349943",
"permitReserve + repay (multicall)": "162036",
"permitReserve + supply (multicall)": "146745",
"permitReserve + supply + enable collateral (multicall)": "161196",
Expand All @@ -17,18 +17,18 @@
"supply: 0 borrows, collateral disabled": "122835",
"supply: 0 borrows, collateral enabled": "105806",
"supply: second action, same reserve": "105735",
"updateUserDynamicConfig: 1 collateral": "74545",
"updateUserDynamicConfig: 2 collaterals": "89413",
"updateUserRiskPremium: 1 borrow": "149005",
"updateUserRiskPremium: 2 borrows": "199256",
"updateUserDynamicConfig: 1 collateral": "74176",
"updateUserDynamicConfig: 2 collaterals": "88675",
"updateUserRiskPremium: 1 borrow": "148267",
"updateUserRiskPremium: 2 borrows": "198518",
"usingAsCollateral: 0 borrows, enable": "59616",
"usingAsCollateral: 1 borrow, disable": "159046",
"usingAsCollateral: 1 borrow, disable": "158308",
"usingAsCollateral: 1 borrow, enable": "42504",
"usingAsCollateral: 2 borrows, disable": "229165",
"usingAsCollateral: 2 borrows, disable": "228058",
"usingAsCollateral: 2 borrows, enable": "42516",
"withdraw: 0 borrows, full": "127944",
"withdraw: 0 borrows, partial": "132840",
"withdraw: 1 borrow, partial": "210737",
"withdraw: 2 borrows, partial": "256902",
"withdraw: 0 borrows, full": "127575",
"withdraw: 0 borrows, partial": "132471",
"withdraw: 1 borrow, partial": "209999",
"withdraw: 2 borrows, partial": "255795",
"withdraw: non collateral": "105891"
}
20 changes: 20 additions & 0 deletions src/dependencies/chainlink/AggregatorInterface.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
// Imported from https://github.com/smartcontractkit/chainlink/blob/e8490e910274279a2c394ba37eb328943322ac6b/contracts/src/v0.8/shared/interfaces/AggregatorInterface.sol
pragma solidity ^0.8.0;

// solhint-disable-next-line interface-starts-with-i
interface AggregatorInterface {
function latestAnswer() external view returns (int256);

function latestTimestamp() external view returns (uint256);

function latestRound() external view returns (uint256);

function getAnswer(uint256 roundId) external view returns (int256);

function getTimestamp(uint256 roundId) external view returns (uint256);

event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);

event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
}
9 changes: 9 additions & 0 deletions src/dependencies/chainlink/AggregatorV2V3Interface.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
// Imported from https://github.com/smartcontractkit/chainlink/blob/e8490e910274279a2c394ba37eb328943322ac6b/contracts/src/v0.8/shared/interfaces/AggregatorV2V3Interface.sol
pragma solidity ^0.8.0;

import {AggregatorInterface} from "./AggregatorInterface.sol";
import {AggregatorV3Interface} from "./AggregatorV3Interface.sol";

// solhint-disable-next-line interface-starts-with-i
interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface {}
39 changes: 36 additions & 3 deletions src/misc/UnitPriceFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
// Copyright (c) 2025 Aave Labs
pragma solidity 0.8.28;

import {AggregatorV2V3Interface} from 'src/dependencies/chainlink/AggregatorV2V3Interface.sol';
import {AggregatorV3Interface} from 'src/dependencies/chainlink/AggregatorV3Interface.sol';
import {AggregatorInterface} from 'src/dependencies/chainlink/AggregatorInterface.sol';
Comment on lines +5 to +7
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The imports AggregatorV3Interface and AggregatorInterface are redundant since AggregatorV2V3Interface already extends both of these interfaces. Consider removing these imports to keep the code clean and reduce unnecessary dependencies.

Copilot uses AI. Check for mistakes.
import {SafeCast} from 'src/dependencies/openzeppelin/SafeCast.sol';

/// @title UnitPriceFeed contract
/// @author Aave Labs
/// @notice Price feed that returns the unit price (1), with decimals precision.
/// @dev This price feed can be set for reserves that use the base currency as collateral.
contract UnitPriceFeed is AggregatorV3Interface {
contract UnitPriceFeed is AggregatorV2V3Interface {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine just using V2

using SafeCast for uint256;

/// @inheritdoc AggregatorV3Interface
Expand Down Expand Up @@ -46,7 +48,7 @@ contract UnitPriceFeed is AggregatorV3Interface {
uint80 answeredInRound
)
{
if (_roundId <= uint80(block.timestamp)) {
if (_roundId <= block.timestamp.toUint80()) {
roundId = _roundId;
answer = UNITS;
startedAt = _roundId;
Expand All @@ -67,7 +69,7 @@ contract UnitPriceFeed is AggregatorV3Interface {
uint80 answeredInRound
)
{
roundId = uint80(block.timestamp);
roundId = block.timestamp.toUint80();
answer = UNITS;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

answer = latestAnswer();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i thought the point of this unit price feed was hard coding it to UNITS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that's what latestAnswer returns

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion is to avoid logic duplication, can be done either way

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm then we need to make latestAnswer public or create a _latestAnswer internal helper to return UNITS, also there's already some code duplication in getAnswer too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes make it public

startedAt = block.timestamp;
updatedAt = block.timestamp;
Expand All @@ -78,4 +80,35 @@ contract UnitPriceFeed is AggregatorV3Interface {
function decimals() external view returns (uint8) {
return DECIMALS;
}

/// @inheritdoc AggregatorInterface
function latestAnswer() external view returns (int256) {
return UNITS;
}

/// @inheritdoc AggregatorInterface
function latestTimestamp() external view returns (uint256) {
return block.timestamp;
}

/// @inheritdoc AggregatorInterface
function latestRound() external view returns (uint256) {
return block.timestamp;
}

/// @inheritdoc AggregatorInterface
function getAnswer(uint256 roundId) external view returns (int256) {
if (roundId <= block.timestamp) {
return UNITS;
}
return 0;
}

/// @inheritdoc AggregatorInterface
function getTimestamp(uint256 roundId) external view returns (uint256) {
if (roundId <= block.timestamp) {
return roundId;
}
return 0;
}
}
10 changes: 5 additions & 5 deletions src/spoke/AaveOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright (c) 2025 Aave Labs
pragma solidity 0.8.28;

import {AggregatorV3Interface} from 'src/dependencies/chainlink/AggregatorV3Interface.sol';
import {AggregatorV2V3Interface} from 'src/dependencies/chainlink/AggregatorV2V3Interface.sol';
import {ISpoke} from 'src/spoke/interfaces/ISpoke.sol';
import {IAaveOracle, IPriceOracle} from 'src/spoke/interfaces/IAaveOracle.sol';

Expand All @@ -23,7 +23,7 @@ contract AaveOracle is IAaveOracle {
/// @dev The address of the deployer.
address private immutable DEPLOYER;

mapping(uint256 reserveId => AggregatorV3Interface) internal _sources;
mapping(uint256 reserveId => AggregatorV2V3Interface) internal _sources;

/// @dev Constructor.
/// @dev `decimals` must match the spoke's decimals for compatibility.
Expand All @@ -48,7 +48,7 @@ contract AaveOracle is IAaveOracle {
/// @inheritdoc IAaveOracle
function setReserveSource(uint256 reserveId, address source) external {
require(msg.sender == SPOKE, OnlySpoke());
AggregatorV3Interface targetSource = AggregatorV3Interface(source);
AggregatorV2V3Interface targetSource = AggregatorV2V3Interface(source);
require(targetSource.decimals() == DECIMALS, InvalidSourceDecimals(reserveId));
_sources[reserveId] = targetSource;
_getSourcePrice(reserveId);
Expand Down Expand Up @@ -78,10 +78,10 @@ contract AaveOracle is IAaveOracle {

/// @dev Price of zero will revert with `InvalidPrice`.
function _getSourcePrice(uint256 reserveId) internal view returns (uint256) {
AggregatorV3Interface source = _sources[reserveId];
AggregatorV2V3Interface source = _sources[reserveId];
require(address(source) != address(0), InvalidSource(reserveId));

(, int256 price, , , ) = source.latestRoundData();
int256 price = source.latestAnswer();
require(price > 0, InvalidPrice(reserveId));

return uint256(price);
Expand Down
24 changes: 22 additions & 2 deletions tests/mocks/MockPriceFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Copyright (c) 2025 Aave Labs
pragma solidity ^0.8.0;

import {AggregatorV3Interface} from 'src/dependencies/chainlink/AggregatorV3Interface.sol';
import {AggregatorV2V3Interface} from 'src/dependencies/chainlink/AggregatorV2V3Interface.sol';

contract MockPriceFeed is AggregatorV3Interface {
contract MockPriceFeed is AggregatorV2V3Interface {
uint8 public immutable override decimals;
string public override description;

Expand Down Expand Up @@ -47,4 +47,24 @@ contract MockPriceFeed is AggregatorV3Interface {
updatedAt = block.timestamp;
answeredInRound = roundId;
}

function latestAnswer() external view override returns (int256) {
return _price;
}

function latestTimestamp() external view override returns (uint256) {
return block.timestamp;
}

function latestRound() external view override returns (uint256) {
return block.timestamp;
}

function getAnswer(uint256) external view override returns (int256) {
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getAnswer function ignores the roundId parameter and always returns the current price. According to the Chainlink AggregatorInterface specification, getAnswer should return historical answers based on the roundId. This implementation is inconsistent with UnitPriceFeed.getAnswer which does check the roundId parameter. Consider either documenting this deviation from the standard interface behavior or implementing historical round tracking if accurate behavior is required.

Suggested change
function getAnswer(uint256) external view override returns (int256) {
/// @notice Returns the current mocked price.
/// @dev This mock does not support historical rounds; `roundId` is ignored.
function getAnswer(uint256 /* roundId */) external view override returns (int256) {

Copilot uses AI. Check for mistakes.
return _price;
}

function getTimestamp(uint256) external view override returns (uint256) {
return block.timestamp;
Comment on lines +67 to +68
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getTimestamp function ignores the roundId parameter and always returns the current block.timestamp. According to the Chainlink AggregatorInterface specification, getTimestamp should return the timestamp of a specific round. This implementation is inconsistent with UnitPriceFeed.getTimestamp which does check the roundId parameter. Consider either documenting this deviation from the standard interface behavior or implementing historical round tracking if accurate behavior is required.

Suggested change
function getTimestamp(uint256) external view override returns (uint256) {
return block.timestamp;
function getTimestamp(uint256 roundId) external view override returns (uint256) {
return roundId;

Copilot uses AI. Check for mistakes.
}
}
Loading
Loading