Skip to content

Commit 22ca867

Browse files
feat: adjusted aggregator contract for price adjustments based on signed percentage
1 parent d533abc commit 22ca867

10 files changed

+434
-303
lines changed

contracts/feeds/CustomAggregatorV3CompatibleFeedDiscounted.sol renamed to contracts/feeds/CustomAggregatorV3CompatibleFeedAdjusted.sol

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,44 @@ pragma solidity 0.8.9;
44
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
55

66
/**
7-
* @title CustomAggregatorV3CompatibleFeedDiscounted
8-
* @notice AggregatorV3 compatible proxy-feed that discounts the price
9-
* of an underlying chainlink compatible feed by a given percentage
7+
* @title CustomAggregatorV3CompatibleFeedAdjusted
8+
* @notice AggregatorV3 compatible proxy-feed that adjusts the price
9+
* of an underlying chainlink compatible feed by a given signed percentage.
10+
* Positive adjustmentPercentage lowers the reported price.
11+
* Negative adjustmentPercentage raises the reported price.
1012
* @author RedDuck Software
1113
*/
12-
contract CustomAggregatorV3CompatibleFeedDiscounted is AggregatorV3Interface {
14+
contract CustomAggregatorV3CompatibleFeedAdjusted is AggregatorV3Interface {
1315
/**
1416
* @notice the underlying chainlink compatible feed
1517
*/
1618
AggregatorV3Interface public immutable underlyingFeed;
1719

1820
/**
19-
* @notice the discount percentage. Expressed in 10 ** decimals() precision
20-
* Example: 10 ** decimals() = 1%
21+
* @notice the adjustment percentage (signed).
22+
* Expressed in 10 ** decimals() precision.
23+
* Example: 10 ** decimals() = 1%, -(10 ** decimals()) = -1%
24+
* Positive values lower the reported price.
25+
* Negative values raise the reported price.
2126
*/
22-
uint256 public immutable discountPercentage;
27+
int256 public immutable adjustmentPercentage;
2328

2429
/**
2530
* @notice constructor
2631
* @param _underlyingFeed the underlying chainlink compatible feed
27-
* @param _discountPercentage the discount percentage. Expressed in 10 ** decimals() precision
32+
* @param _adjustmentPercentage signed adjustment percentage in 10 ** decimals() precision
2833
*/
29-
constructor(address _underlyingFeed, uint256 _discountPercentage) {
30-
require(_underlyingFeed != address(0), "CAD: !underlying feed");
34+
constructor(address _underlyingFeed, int256 _adjustmentPercentage) {
35+
require(_underlyingFeed != address(0), "CAA: !underlying feed");
3136
underlyingFeed = AggregatorV3Interface(_underlyingFeed);
3237

38+
int256 maxPct = int256(100 * (10**decimals()));
3339
require(
34-
_discountPercentage <= 100 * (10**decimals()),
35-
"CAD: !discount percentage"
40+
_adjustmentPercentage >= -maxPct && _adjustmentPercentage <= maxPct,
41+
"CAA: invalid adjustment"
3642
);
3743

38-
discountPercentage = _discountPercentage;
44+
adjustmentPercentage = _adjustmentPercentage;
3945
}
4046

4147
/**
@@ -60,7 +66,7 @@ contract CustomAggregatorV3CompatibleFeedDiscounted is AggregatorV3Interface {
6066
answeredInRound
6167
) = underlyingFeed.latestRoundData();
6268

63-
answer = _calculateDiscountedAnswer(answer);
69+
answer = _calculateAdjustedAnswer(answer);
6470
}
6571

6672
/**
@@ -91,7 +97,7 @@ contract CustomAggregatorV3CompatibleFeedDiscounted is AggregatorV3Interface {
9197
updatedAt,
9298
answeredInRound
9399
) = underlyingFeed.getRoundData(_roundId);
94-
answer = _calculateDiscountedAnswer(answer);
100+
answer = _calculateAdjustedAnswer(answer);
95101
}
96102

97103
/**
@@ -105,27 +111,28 @@ contract CustomAggregatorV3CompatibleFeedDiscounted is AggregatorV3Interface {
105111
* @inheritdoc AggregatorV3Interface
106112
*/
107113
function description() public view returns (string memory) {
108-
return
109-
string(
110-
abi.encodePacked(underlyingFeed.description(), " Discounted")
111-
);
114+
if (adjustmentPercentage == 0) return underlyingFeed.description();
115+
string memory suffix = adjustmentPercentage > 0
116+
? " PriceLowered"
117+
: " PriceRaised";
118+
return string(abi.encodePacked(underlyingFeed.description(), suffix));
112119
}
113120

114121
/**
115-
* @dev calculates the discounted answer
116-
* @param _answer the answer to discount
117-
* @return the discounted answer
122+
* @dev calculates the adjusted answer
123+
* @param _answer the answer to adjust
124+
* @return the adjusted answer
118125
*/
119-
function _calculateDiscountedAnswer(int256 _answer)
126+
function _calculateAdjustedAnswer(int256 _answer)
120127
internal
121128
view
122129
returns (int256)
123130
{
124-
require(_answer >= 0, "CAD: !_answer");
131+
require(_answer >= 0, "CAA: !_answer");
125132

126-
int256 discount = (_answer * int256(discountPercentage)) /
133+
int256 adjustment = (_answer * adjustmentPercentage) /
127134
int256(100 * 10**decimals());
128135

129-
return _answer - discount;
136+
return _answer - adjustment;
130137
}
131138
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.9;
3+
4+
import "../feeds/CustomAggregatorV3CompatibleFeedAdjusted.sol";
5+
6+
contract CustomAggregatorV3CompatibleFeedAdjustedTester is
7+
CustomAggregatorV3CompatibleFeedAdjusted
8+
{
9+
constructor(address _underlyingFeed, int256 _adjustmentPercentage)
10+
CustomAggregatorV3CompatibleFeedAdjusted(
11+
_underlyingFeed,
12+
_adjustmentPercentage
13+
)
14+
{}
15+
16+
function getAdjustedAnswer(int256 _answer) public view returns (int256) {
17+
return _calculateAdjustedAnswer(_answer);
18+
}
19+
}

contracts/testers/CustomAggregatorV3CompatibleFeedDiscountedTester.sol

Lines changed: 0 additions & 19 deletions
This file was deleted.

helpers/contracts.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type TokenContractNames = {
2626
type CommonContractNames = Omit<TokenContractNames, 'token'> & {
2727
ac: string;
2828
customAggregator: string;
29-
customAggregatorDiscounted: string;
29+
customAggregatorAdjusted: string;
3030
layerZero: {
3131
oftAdapter: string;
3232
vaultComposer: string;
@@ -149,7 +149,7 @@ export const getCommonContractNames = (): CommonContractNames => {
149149
dataFeed: 'DataFeed',
150150
customAggregator: 'CustomAggregatorV3CompatibleFeed',
151151
customAggregatorGrowth: 'CustomAggregatorV3CompatibleFeedGrowth',
152-
customAggregatorDiscounted: 'CustomAggregatorV3CompatibleFeedDiscounted',
152+
customAggregatorAdjusted: 'CustomAggregatorV3CompatibleFeedAdjusted',
153153
roles: 'MidasAccessControlRoles',
154154
dataFeedComposite: 'CompositeDataFeed',
155155
dataFeedMultiply: 'CompositeDataFeedMultiply',

scripts/deploy/common/data-feed.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ export type DeployCustomAggregatorRegularConfig =
7272
type?: 'REGULAR';
7373
};
7474

75-
export type DeployCustomAggregatorDiscountedConfig = {
76-
discountPercentage: BigNumberish;
75+
export type DeployCustomAggregatorAdjustedConfig = {
76+
adjustmentPercentage: BigNumberish;
7777
underlyingFeed: `0x${string}` | 'customFeed';
7878
};
7979

@@ -410,14 +410,14 @@ export const deployMTokenDataFeed = async (
410410
);
411411
};
412412

413-
export const deployMTokenCustomAggregatorDiscounted = async (
413+
export const deployMTokenCustomAggregatorAdjusted = async (
414414
hre: HardhatRuntimeEnvironment,
415415
token: MTokenName,
416416
) => {
417-
await deployCustomAggregatorDiscounted(
417+
await deployCustomAggregatorAdjusted(
418418
hre,
419419
token,
420-
getDeploymentGenericConfig(hre, token, 'customAggregatorDiscounted'),
420+
getDeploymentGenericConfig(hre, token, 'customAggregatorAdjusted'),
421421
);
422422
};
423423

@@ -536,10 +536,10 @@ const deployCustomAggregator = async (
536536
);
537537
};
538538

539-
const deployCustomAggregatorDiscounted = async (
539+
const deployCustomAggregatorAdjusted = async (
540540
hre: HardhatRuntimeEnvironment,
541541
token: MTokenName,
542-
networkConfig?: DeployCustomAggregatorDiscountedConfig,
542+
networkConfig?: DeployCustomAggregatorAdjustedConfig,
543543
) => {
544544
const addresses = getCurrentAddresses(hre);
545545

@@ -558,7 +558,7 @@ const deployCustomAggregatorDiscounted = async (
558558

559559
await deployAndVerify(
560560
hre,
561-
getCommonContractNames().customAggregatorDiscounted,
562-
[underlyingFeed, networkConfig.discountPercentage],
561+
getCommonContractNames().customAggregatorAdjusted,
562+
[underlyingFeed, networkConfig.adjustmentPercentage],
563563
);
564564
};

scripts/deploy/common/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types';
33

44
import { AddFeeWaivedConfig, AddPaymentTokensConfig } from './common-vault';
55
import {
6+
DeployCustomAggregatorAdjustedConfig,
67
DeployCustomAggregatorConfig,
7-
DeployCustomAggregatorDiscountedConfig,
88
DeployDataFeedConfig,
99
SetRoundDataConfig,
1010
} from './data-feed';
@@ -94,7 +94,7 @@ export type PostDeployConfig = {
9494
export type DeploymentConfig = {
9595
genericConfigs: {
9696
customAggregator?: DeployCustomAggregatorConfig;
97-
customAggregatorDiscounted?: DeployCustomAggregatorDiscountedConfig;
97+
customAggregatorAdjusted?: DeployCustomAggregatorAdjustedConfig;
9898
dataFeed?: DeployDataFeedConfig;
9999
};
100100
networkConfigs: Record<

scripts/deploy/misc/deploy_CustomAggregatorDiscounted.ts renamed to scripts/deploy/misc/deploy_CustomAggregatorAdjusted.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { HardhatRuntimeEnvironment } from 'hardhat/types';
22

33
import { getMTokenOrThrow } from '../../../helpers/utils';
4-
import { deployMTokenCustomAggregatorDiscounted } from '../common/data-feed';
4+
import { deployMTokenCustomAggregatorAdjusted } from '../common/data-feed';
55
import { DeployFunction } from '../common/types';
66

77
const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
88
const mToken = getMTokenOrThrow(hre);
9-
await deployMTokenCustomAggregatorDiscounted(hre, mToken);
9+
await deployMTokenCustomAggregatorAdjusted(hre, mToken);
1010
};
1111

1212
export default func;

test/common/fixtures.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import {
4343
RedemptionVaultWithMTokenTest__factory,
4444
AaveV3PoolMock__factory,
4545
MorphoVaultMock__factory,
46-
CustomAggregatorV3CompatibleFeedDiscountedTester__factory,
46+
CustomAggregatorV3CompatibleFeedAdjustedTester__factory,
4747
DepositVaultWithAaveTest__factory,
4848
DepositVaultWithMorphoTest__factory,
4949
DepositVaultWithMTokenTest__factory,
@@ -714,8 +714,8 @@ export const defaultDeploy = async () => {
714714
parseUnits('10000', mockedAggregatorDecimals),
715715
);
716716

717-
const customFeedDiscounted =
718-
await new CustomAggregatorV3CompatibleFeedDiscountedTester__factory(
717+
const customFeedAdjusted =
718+
await new CustomAggregatorV3CompatibleFeedAdjustedTester__factory(
719719
owner,
720720
).deploy(customFeed.address, parseUnits('10', 8));
721721

@@ -820,7 +820,7 @@ export const defaultDeploy = async () => {
820820

821821
return {
822822
customFeed,
823-
customFeedDiscounted,
823+
customFeedAdjusted,
824824
customFeedGrowth,
825825
mTBILL,
826826
mBASIS,

0 commit comments

Comments
 (0)