Skip to content

Commit

Permalink
fix: oracle written timestamp
Browse files Browse the repository at this point in the history
* fix: write current block timestamp instead of previous timestamp for oracle observation
* fix: change arg in internal func sig to reflect correct timestamp
* ci: update solc version
* lint: fix issues
* ci: update hashes
* ci: remove pin on foundry version
* test: add assert to make sure latest timestamp written
* test: test case to make sure latest timestamp is written
* fix: failing tests
* fix: bug in test case
* lib: bump `forge-std` to v1.7.6
* ci: update gas snapshot
  • Loading branch information
xenide authored Jan 23, 2024
1 parent 573a2db commit c066d02
Show file tree
Hide file tree
Showing 16 changed files with 255 additions and 233 deletions.
351 changes: 176 additions & 175 deletions .gas-snapshot

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: forge build

lint:
Expand All @@ -41,7 +41,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: npm run test:unit

test-integration:
Expand All @@ -52,7 +52,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: npm run test:integration

test-e2e:
Expand All @@ -63,7 +63,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: npm run test:e2e

test-uniswap-v2:
Expand All @@ -75,7 +75,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- uses: actions/setup-node@v3
with:
node-version-file: ".nvmrc"
Expand All @@ -93,7 +93,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: npm run install:balancer
- run: npm run build:balancer
- run: npm run test:balancer
Expand All @@ -108,7 +108,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: forge snapshot --check
env:
FOUNDRY_PROFILE: default
Expand All @@ -122,7 +122,7 @@ jobs:
submodules: recursive
- uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-e15e33a07c0920189fc336391f538c3dad53da73
version: nightly
- run: ./script/coverage_patch_deployer.sh && forge coverage --report lcov
env:
FOUNDRY_PROFILE: coverage
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ V1.0
Are you interested in helping us build the future of Reservoir?
Contribute in these ways:

- For SECURITY related or sensitive bugs, please get in touch with the team at [email protected] or on discord instead of opening an issue on github.
- For SECURITY related or sensitive bugs, please get in touch with the team
at [email protected] or on discord instead of opening an issue on github.

- If you find bugs or code errors, you can open a new
[issue ticket here.](https://github.com/reservoir-labs/amm-core/issues/new)
Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[profile.default]
solc = "0.8.19"
solc = "0.8.23"
#via_ir = true
bytecode_hash = "ipfs"
optimizer_runs = 1_000_000
Expand Down
8 changes: 4 additions & 4 deletions script/optimized-deployer-meta
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"constant_product_hash": "0xde6d8452b97c785350ce9f82090dfb5962933aa5467827310798925c8725013b",
"factory_hash": "0xaafa0bd4694a22c24f8ef26cfd45864f11be2102e269ee6a831d2c659b30f08f",
"oracle_caller_hash": "0x1dcb29ca6399be1a5f8a4b3f168a83ff20697718c3d5434ddeeb4a8050fdc615",
"stable_hash": "0x1289a8879d4d1992d308d2a4d8457a5ca8d57e07effe092f2a1f21b0b9b10619"
"constant_product_hash": "0x7f3a12e644606d9d166691742af07487155a1b86cc1a97a9ca21a5b474c3fd14",
"factory_hash": "0x0aa0c77b70a77a082be061cb9565cbe92d8ee7b8a74007287d597c000c0d4ec4",
"oracle_caller_hash": "0x9c8ae1fb85485b08e88ceed1c47608205b81b6c7b438c1770abd5dedf6188423",
"stable_hash": "0x044e7b5a6e582680c9a2dfcb895bd9993c9462c3cf17048f408a3c714600e37d"
}
8 changes: 4 additions & 4 deletions script/unoptimized-deployer-meta
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"constant_product_hash": "0x71f0d385cb55f83e9dd571b118cb5ee391542d27ff471998ea316d3693b21308",
"factory_hash": "0xa61785bbfa1f668e1ad6e2aff9c6fc4ed961b95ae7cc54c6463d49b259b2e984",
"oracle_caller_hash": "0x6e5b6d511ec5f70fdae7be4b74be5a313df4168f1b50dee9fc571e4414697354",
"stable_hash": "0xa17d9c01054e0d89b5da9d84936c6960c6f82f7981951978cc2aff275d943f5a"
"constant_product_hash": "0xf2204f73059bda42b0910c810137b13b403a9087928123890443c76b866d4135",
"factory_hash": "0x64c369a012abcc9c156cce47a6a1a0916225795135bec914ac0083327650b949",
"oracle_caller_hash": "0x99643805c6f1cf50d6f68ecdaba00a6dc4694001423319968799766504a28e1b",
"stable_hash": "0x76047e8e6a3e3291cd4334776733b188fb11d2d83851f3ffe0861cc90afa3925"
}
8 changes: 4 additions & 4 deletions src/ReservoirDeployer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ contract ReservoirDeployer {
uint256 public step = 0;

// Bytecode hashes.
bytes32 public constant FACTORY_HASH = bytes32(0xaafa0bd4694a22c24f8ef26cfd45864f11be2102e269ee6a831d2c659b30f08f);
bytes32 public constant FACTORY_HASH = bytes32(0x0aa0c77b70a77a082be061cb9565cbe92d8ee7b8a74007287d597c000c0d4ec4);
bytes32 public constant CONSTANT_PRODUCT_HASH =
bytes32(0xde6d8452b97c785350ce9f82090dfb5962933aa5467827310798925c8725013b);
bytes32 public constant STABLE_HASH = bytes32(0x1289a8879d4d1992d308d2a4d8457a5ca8d57e07effe092f2a1f21b0b9b10619);
bytes32(0x7f3a12e644606d9d166691742af07487155a1b86cc1a97a9ca21a5b474c3fd14);
bytes32 public constant STABLE_HASH = bytes32(0x044e7b5a6e582680c9a2dfcb895bd9993c9462c3cf17048f408a3c714600e37d);
bytes32 public constant ORACLE_CALLER_HASH =
bytes32(0x1dcb29ca6399be1a5f8a4b3f168a83ff20697718c3d5434ddeeb4a8050fdc615);
bytes32(0x9c8ae1fb85485b08e88ceed1c47608205b81b6c7b438c1770abd5dedf6188423);

// Deployment addresses.
GenericFactory public factory;
Expand Down
4 changes: 2 additions & 2 deletions src/ReservoirPair.sol
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20 {
lTimeElapsed = lBlockTimestamp - aBlockTimestampLast;
}
if (lTimeElapsed > 0 && aReserve0 != 0 && aReserve1 != 0) {
_updateOracle(aReserve0, aReserve1, lTimeElapsed, aBlockTimestampLast);
_updateOracle(aReserve0, aReserve1, lTimeElapsed, lBlockTimestamp);
}

// update reserves to match latest balances
Expand Down Expand Up @@ -544,7 +544,7 @@ abstract contract ReservoirPair is IAssetManagedPair, ReservoirERC20 {
}
}

function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aTimestampLast)
function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aCurrentTimestamp)
internal
virtual;
}
4 changes: 2 additions & 2 deletions src/curve/constant-product/ConstantProductPair.sol
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ contract ConstantProductPair is ReservoirPair {
ORACLE METHODS
//////////////////////////////////////////////////////////////////////////*/

function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aTimestampLast)
function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aCurrentTimestamp)
internal
override
{
Expand All @@ -246,7 +246,7 @@ contract ConstantProductPair is ReservoirPair {
previous.logAccClampedPrice + int56(currLogClampedPrice) * int56(int256(uint256(aTimeElapsed)));
int56 logAccLiq = previous.logAccLiquidity + int56(lCurrLogLiq) * int56(int256(uint256(aTimeElapsed)));
_slot0.index += 1;
_observations[_slot0.index] = Observation(logAccRawPrice, logAccClampedPrice, logAccLiq, aTimestampLast);
_observations[_slot0.index] = Observation(logAccRawPrice, logAccClampedPrice, logAccLiq, aCurrentTimestamp);
}
}
}
4 changes: 2 additions & 2 deletions src/curve/stable/StablePair.sol
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ contract StablePair is ReservoirPair {
ORACLE METHODS
//////////////////////////////////////////////////////////////////////////*/

function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aTimestampLast)
function _updateOracle(uint256 aReserve0, uint256 aReserve1, uint32 aTimeElapsed, uint32 aCurrentTimestamp)
internal
override
{
Expand All @@ -301,7 +301,7 @@ contract StablePair is ReservoirPair {
previous.logAccClampedPrice + int56(currLogClampedPrice) * int56(int256(uint256(aTimeElapsed)));
int56 logAccLiq = previous.logAccLiquidity + int56(currLogLiq) * int56(int256(uint256(aTimeElapsed)));
_slot0.index += 1;
_observations[_slot0.index] = Observation(logAccRawPrice, logAccClampedPrice, logAccLiq, aTimestampLast);
_observations[_slot0.index] = Observation(logAccRawPrice, logAccClampedPrice, logAccLiq, aCurrentTimestamp);
}
}
}
1 change: 1 addition & 0 deletions test/__fixtures/BaseTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ConstantProductPair } from "src/curve/constant-product/ConstantProductP
import { StablePair, AmplificationData } from "src/curve/stable/StablePair.sol";
import { StableMintBurn } from "src/curve/stable/StableMintBurn.sol";

// solhint-disable-next-line max-states-count
abstract contract BaseTest is Test {
using FactoryStoreLib for GenericFactory;

Expand Down
10 changes: 5 additions & 5 deletions test/unit/AssetManagedPair.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ contract AssetManagedPairTest is BaseTest {

function testMint_AfterLoss(uint256 aNewManagedBalance0, uint256 aNewManagedBalance1) external allPairs {
// assume
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 10e18);
uint256 lNewManagedBalance1 = bound(aNewManagedBalance1, 1, 10e18);
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 9e18);
uint256 lNewManagedBalance1 = bound(aNewManagedBalance1, 1, 9e18);

// arrange
vm.prank(address(_factory));
Expand All @@ -234,8 +234,8 @@ contract AssetManagedPairTest is BaseTest {

function testBurn_AfterLoss(uint256 aNewManagedBalance0, uint256 aNewManagedBalance1) external allPairs {
// assume
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 10e18);
uint256 lNewManagedBalance1 = bound(aNewManagedBalance1, 1, 10e18);
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 9e18);
uint256 lNewManagedBalance1 = bound(aNewManagedBalance1, 1, 9e18);

// arrange
vm.prank(address(_factory));
Expand All @@ -259,7 +259,7 @@ contract AssetManagedPairTest is BaseTest {

function testSwap_AfterLoss(uint256 aNewManagedBalance0) external allPairs {
// assume
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 10e18);
uint256 lNewManagedBalance0 = bound(aNewManagedBalance0, 1, 9e18);

// arrange
int256 lSwapAmt = 1e18;
Expand Down
64 changes: 41 additions & 23 deletions test/unit/OracleWriter.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,6 @@ contract OracleWriterTest is BaseTest {
_pair.observation(lIndex);
}

function testUpdateOracle_WriteOldReservesNotNew() external allPairs {
// arrange
uint256 lJumpAhead = 10;
(uint104 lReserve0,,,) = _pair.getReserves();
assertEq(lReserve0, Constants.INITIAL_MINT_AMOUNT);
_tokenA.mint(address(_pair), 10e18);

// act - call sync to trigger a write to the oracle
_stepTime(lJumpAhead);
_pair.sync();

// assert - make sure that the written observation is of the previous reserves, not the new reserves
(uint256 lNewReserve0,,, uint16 lIndex) = _pair.getReserves();

Observation memory lObs = _oracleCaller.observation(_pair, lIndex);
assertEq(lNewReserve0, 110e18);
assertApproxEqRel(
LogCompression.fromLowResLog(lObs.logAccLiquidity / int56(int256(lJumpAhead))),
Constants.INITIAL_MINT_AMOUNT,
0.0001e18
);
}

function testUpdateOracleCaller() external allPairs {
// arrange
address lNewOracleCaller = address(0x555);
Expand Down Expand Up @@ -122,6 +99,47 @@ contract OracleWriterTest is BaseTest {
_pair.setMaxChangeRate(lMaxChangeRate);
}

function testUpdateOracle_WriteOldReservesNotNew() external allPairs {
// arrange
uint256 lJumpAhead = 10;
(uint104 lReserve0,,,) = _pair.getReserves();
assertEq(lReserve0, Constants.INITIAL_MINT_AMOUNT);
_tokenA.mint(address(_pair), 10e18);

// act - call sync to trigger a write to the oracle
_stepTime(lJumpAhead);
_pair.sync();

// assert - make sure that the written observation is of the previous reserves, not the new reserves
(uint256 lNewReserve0,,, uint16 lIndex) = _pair.getReserves();

Observation memory lObs = _oracleCaller.observation(_pair, lIndex);
assertEq(lNewReserve0, 110e18);
assertApproxEqRel(
LogCompression.fromLowResLog(lObs.logAccLiquidity / int56(int256(lJumpAhead))),
Constants.INITIAL_MINT_AMOUNT,
0.0001e18
);
}

function testUpdateOracle_LatestTimestampWritten(uint256 aJumpAhead) external allPairs {
// assume
uint256 lJumpAhead = bound(aJumpAhead, 10, type(uint16).max);

// arrange
uint256 lStartingTimestamp = block.timestamp;
_stepTime(lJumpAhead);

// act
_tokenA.mint(address(_pair), 5e18);
_pair.swap(5e18, true, address(this), "");

// assert
(,,, uint16 lIndex) = _pair.getReserves();
Observation memory lObs = _oracleCaller.observation(_pair, lIndex);
assertEq(lObs.timestamp, lStartingTimestamp + lJumpAhead);
}

function testOracle_CompareLiquidityTwoCurves_Balanced(uint32 aNewStartTime)
external
randomizeStartTime(aNewStartTime)
Expand Down
2 changes: 1 addition & 1 deletion test/unit/StablePair.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ contract StablePairTest is BaseTest {
(uint256 lExpectedPlatformFee, uint256 lGrowthInLiq) =
_calcExpectedPlatformFee(lPlatformFee, lPair, lReserve0, lReserve1, lTotalSupply, lOldLiq);
assertEq(lPair.balanceOf(_platformFeeTo), lExpectedPlatformFee);
if (aPlatformFee > 0) {
if (lPlatformFee > 0) {
assertGt(lPair.balanceOf(_platformFeeTo), 0);
}
assertApproxEqRel(
Expand Down
1 change: 1 addition & 0 deletions test/unit/gas/ConstantProductPair.gas.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ contract ConstantProductPairGas is BaseTest {
_oraclePair.burn(address(this));

// This pair will let a user swap without writing the oracle.
// solhint-disable-next-line reentrancy
_simplePair = ConstantProductPair(_factory.createPair(IERC20(address(_tokenA)), IERC20(address(_tokenC)), 0));
_tokenA.mint(address(_simplePair), 100e18);
_tokenC.mint(address(_simplePair), 100e18);
Expand Down

0 comments on commit c066d02

Please sign in to comment.