Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Adds scaling function to _readTwap #30

Merged
merged 1 commit into from
Aug 16, 2024
Merged
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
Binary file added audits/[email protected]
Binary file not shown.
Binary file added audits/[email protected]
Binary file not shown.
2 changes: 2 additions & 0 deletions script/Aggor.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ contract AggorScript is Script {
address uniswapBaseToken,
address uniswapQuoteToken,
uint8 uniswapBaseTokenDecimals,
uint8 uniswapQuoteTokenDecimals,
uint32 uniswapLookback,
uint128 agreementDistance,
uint32 ageThreshold
Expand All @@ -40,6 +41,7 @@ contract AggorScript is Script {
uniswapBaseToken,
uniswapQuoteToken,
uniswapBaseTokenDecimals,
uniswapQuoteTokenDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand Down
24 changes: 22 additions & 2 deletions src/Aggor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {LibMedian} from "./libs/LibMedian.sol";

/**
* @title Aggor
* @custom:version v1.0.0
* @custom:version v1.0.1
*
* @notice Oracle aggregator distributing trust among different oracle providers
*
Expand Down Expand Up @@ -74,6 +74,8 @@ contract Aggor is IAggor, IToll, Auth {
/// @inheritdoc IAggor
uint8 public immutable uniswapBaseTokenDecimals;
/// @inheritdoc IAggor
uint8 public immutable uniswapQuoteTokenDecimals;
/// @inheritdoc IAggor
uint32 public immutable uniswapLookback;

// -- Mutable Configurations --
Expand Down Expand Up @@ -103,6 +105,7 @@ contract Aggor is IAggor, IToll, Auth {
address uniswapBaseToken_,
address uniswapQuoteToken_,
uint8 uniswapBaseTokenDecimals_,
uint8 uniswapQuoteTokenDecimals_,
uint32 uniswapLookback_,
uint128 agreementDistance_,
uint32 ageThreshold_
Expand All @@ -113,6 +116,7 @@ contract Aggor is IAggor, IToll, Auth {
uniswapBaseToken_,
uniswapQuoteToken_,
uniswapBaseTokenDecimals_,
uniswapQuoteTokenDecimals_,
uniswapLookback_
);

Expand All @@ -124,6 +128,7 @@ contract Aggor is IAggor, IToll, Auth {
uniswapBaseToken = uniswapBaseToken_;
uniswapQuoteToken = uniswapQuoteToken_;
uniswapBaseTokenDecimals = uniswapBaseTokenDecimals_;
uniswapQuoteTokenDecimals = uniswapQuoteTokenDecimals_;
uniswapLookback = uniswapLookback_;

// Emit events indicating address(0) and _bud are tolled.
Expand All @@ -142,6 +147,7 @@ contract Aggor is IAggor, IToll, Auth {
address uniswapBaseToken_,
address uniswapQuoteToken_,
uint8 uniswapBaseTokenDecimals_,
uint8 uniswapQuoteTokenDecimals_,
uint32 uniswapLookback_
) internal view {
require(uniswapPool_ != address(0), "Uniswap pool must not be zero");
Expand All @@ -163,7 +169,7 @@ contract Aggor is IAggor, IToll, Auth {
"Uniswap quote token mismatch"
);

// Verify base token's decimals.
// Verify token decimals.
require(
uniswapBaseTokenDecimals_ == IERC20(uniswapBaseToken_).decimals(),
"Uniswap base token decimals mismatch"
Expand All @@ -172,6 +178,10 @@ contract Aggor is IAggor, IToll, Auth {
uniswapBaseTokenDecimals_ <= _MAX_UNISWAP_BASE_DECIMALS,
"Uniswap base token decimals too high"
);
require(
uniswapQuoteTokenDecimals_ == IERC20(uniswapQuoteToken_).decimals(),
"Uniswap quote token decimals mismatch"
);

// Verify TWAP is initialized.
// Specifically, verify that the TWAP's oldest observation is older
Expand Down Expand Up @@ -338,6 +348,14 @@ contract Aggor is IAggor, IToll, Auth {
uniswapLookback
);

if (uniswapQuoteTokenDecimals <= decimals) {
// Scale up
twap *= 10 ** (decimals - uniswapQuoteTokenDecimals);
} else {
// Scale down
twap /= 10 ** (uniswapQuoteTokenDecimals - decimals);
}

if (twap <= type(uint128).max) {
return (true, uint128(twap));
} else {
Expand Down Expand Up @@ -488,6 +506,7 @@ contract Aggor_BASE_QUOTE_COUNTER is Aggor {
address uniswapBaseToken_,
address uniswapQuoteToken_,
uint8 uniswapBaseDec_,
uint8 uniswapQuoteDec_,
uint32 uniswapLookback_,
uint128 agreementDistance_,
uint32 ageThreshold_
Expand All @@ -501,6 +520,7 @@ contract Aggor_BASE_QUOTE_COUNTER is Aggor {
uniswapBaseToken_,
uniswapQuoteToken_,
uniswapBaseDec_,
uniswapQuoteDec_,
uniswapLookback_,
agreementDistance_,
ageThreshold_
Expand Down
7 changes: 7 additions & 0 deletions src/IAggor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ interface IAggor {
view
returns (uint8 baseTokenDecimals);

/// @notice Returns the Uniswap pool's quote token's decimals.
/// @return quoteTokenDecimals The Uniswap pool's quote token's decimals.
function uniswapQuoteTokenDecimals()
external
view
returns (uint8 quoteTokenDecimals);

/// @notice Returns the time in seconds to use as lookback for Uniswap Twap
/// oracle.
/// @return lookback The time in seconds to use as lookback.
Expand Down
32 changes: 30 additions & 2 deletions test/Aggor.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ contract AggorTest is Test {
// Twap Provider:
address uniswapPool = address(new UniswapPoolMock());
address uniswapBaseToken = address(new ERC20Mock("base", "base", 18));
address uniswapQuoteToken = address(new ERC20Mock("quote", "quote", 18));
address uniswapQuoteToken = address(new ERC20Mock("quote", "quote", 6));
uint32 uniswapLookback = 1 days;

// For more info, see mocks/UniswapPoolMock::observe().
uint valTwap = 999_902;
uint valTwap = 99_990_200; // Scaled for 10^Aggor.decimals()

// Configurations:
uint128 agreementDistance = 9e17; // = 0.9e18 = 10%
Expand All @@ -58,6 +58,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
IERC20(uniswapBaseToken).decimals(),
IERC20(uniswapQuoteToken).decimals(),
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -74,6 +75,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
IERC20(uniswapBaseToken).decimals(),
IERC20(uniswapQuoteToken).decimals(),
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -85,6 +87,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
IERC20(uniswapBaseToken).decimals(),
IERC20(uniswapQuoteToken).decimals(),
uniswapLookback
);
}
Expand All @@ -93,6 +96,7 @@ contract AggorTest is Test {

function test_Deployment_FailsIf_UniswapPoolZeroAddress() public {
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap pool must not be zero");
new Aggor(
Expand All @@ -104,6 +108,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -115,12 +120,14 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback
);
}

function test_Deployment_FailsIf_BaseTokenEqualsQuoteToken() public {
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap tokens must not be equal");
new Aggor(
Expand All @@ -132,6 +139,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapBaseToken, // <- !
decimals,
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -143,13 +151,15 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapBaseToken, // <- !
decimals,
quoteDecimals,
uniswapLookback
);
}

function test_Deployment_FailsIf_BaseTokenNotPoolToken() public {
address notPoolToken = address(new ERC20Mock("", "", 18));
uint8 decimals = IERC20(notPoolToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap base token mismatch");
new Aggor(
Expand All @@ -161,6 +171,7 @@ contract AggorTest is Test {
notPoolToken, // <- !
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -172,13 +183,15 @@ contract AggorTest is Test {
notPoolToken, // <- !
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback
);
}

function test_Deployment_FailsIf_QuoteTokenNotPoolToken() public {
address notPoolToken = address(new ERC20Mock("", "", 18));
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap quote token mismatch");
new Aggor(
Expand All @@ -190,6 +203,7 @@ contract AggorTest is Test {
uniswapBaseToken,
notPoolToken, // <- !
decimals,
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -201,12 +215,14 @@ contract AggorTest is Test {
uniswapBaseToken,
notPoolToken, // <- !
decimals,
quoteDecimals,
uniswapLookback
);
}

function test_Deployment_FailsIf_BaseTokenDecimalsWrong() public {
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap base token decimals mismatch");
new Aggor(
Expand All @@ -218,6 +234,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals + 1, // <- !
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -229,6 +246,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals + 1, // <- !
quoteDecimals,
uniswapLookback
);
}
Expand All @@ -237,6 +255,7 @@ contract AggorTest is Test {
) public {
uniswapBaseToken = address(new ERC20Mock("base", "base", 100)); // <- !
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

UniswapPoolMock(uniswapPool).setToken0(uniswapBaseToken);

Expand All @@ -250,6 +269,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback,
agreementDistance,
ageThreshold
Expand All @@ -261,13 +281,15 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
uniswapLookback
);
}

function test_Deployment_FailsIf_UniswapLookbackBiggerThanOldestObservation(
) public {
uint8 decimals = IERC20(uniswapBaseToken).decimals();
uint8 quoteDecimals = IERC20(uniswapQuoteToken).decimals();

vm.expectRevert("Uniswap lookback too high");
new Aggor(
Expand All @@ -279,6 +301,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
type(uint32).max, // <- !
agreementDistance,
ageThreshold
Expand All @@ -290,6 +313,7 @@ contract AggorTest is Test {
uniswapBaseToken,
uniswapQuoteToken,
decimals,
quoteDecimals,
type(uint32).max
);
}
Expand Down Expand Up @@ -1048,6 +1072,7 @@ contract Aggor_VerifyTwapConfig is Aggor {
address uniswapBaseToken_,
address uniswapQuoteToken_,
uint8 uniswapBaseTokenDecimals_,
uint8 uniswapQuoteTokenDecimals_,
uint32 uniswapLookback_,
uint128 agreementDistance_,
uint32 ageThreshold_
Expand All @@ -1061,6 +1086,7 @@ contract Aggor_VerifyTwapConfig is Aggor {
uniswapBaseToken_,
uniswapQuoteToken_,
uniswapBaseTokenDecimals_,
uniswapQuoteTokenDecimals_,
uniswapLookback_,
agreementDistance_,
ageThreshold_
Expand All @@ -1072,13 +1098,15 @@ contract Aggor_VerifyTwapConfig is Aggor {
address uniswapBaseToken_,
address uniswapQuoteToken_,
uint8 uniswapBaseTokenDecimals_,
uint8 uniswapQuoteTokenDecimals_,
uint32 uniswapLookback_
) public view {
_verifyTwapConfig(
uniswapPool_,
uniswapBaseToken_,
uniswapQuoteToken_,
uniswapBaseTokenDecimals_,
uniswapQuoteTokenDecimals_,
uniswapLookback_
);
}
Expand Down
Loading
Loading