Skip to content

Commit

Permalink
v1.5.1: Add Uniswap v3 TWAP as a fallback oracle to Chainlink (#152)
Browse files Browse the repository at this point in the history
* Update coverage [skip ci]

* Deploy LINK/USDC to base sepolia

* v1.5 testnet redeploy to redo migration

* Add SizeFactory and SizeRegistry (#5)

* Add SizeFactory

* Split factory/registry due to contract size limit

* Create SizeRegistryFactoryTest

* Add more tests for 2 markets

* Test createMarket

* Add more tests

* Add fork test

* Bump

* Bump CI

* Refactor SizeRegistryFactoryTest

* Add isMarket function

* Change description to percent instead of BP

* Fix fork test

* Use ISize and implementation in constructor

* Add PriceFeed factory

* Fix slither

* Change _ by | on descriptions

* Fix test

* Remove unused code

* v1.5 migration with `reinitialize` (#7)

* Create migration function

* Create NonTransferrableScaledTokenV1_5Test (WIP)

* Attempt build

* Fix circular dependency

* Add Size deployment to SizeRegistry on tests

* Pin foundry version

* WIP

* WIP + compiling

* Alternate branch

* Fix getUserView

* Create withdrawV1_2 function

* Do migration in a single reinitialize

* Add testFork_ForkReinitializeV1_5_set_2_existing_markets

* Create separate tests to check gas usage

* Add v1.5 at the end of NonTransferrableScaledTokenV1_5

* Fix _testFork_ForkReinitializeV1_5_migrate

* Rollback SizeDataView struct to not break integrations

* Fix getMarketsDescriptions

* Fix tests

* Fix compilation warnings

* Fix fork test

* Attempt fix slither

* fix slither

* attempt fix slither

* Fix slither

* Fix slither

* Add more consistency checks

* Add more checks to reinitialize fn

* Remove blank line

* Add new methods

* Add more tests

* Disable slither calls-loop

* Fix checks by using only scaled balances

* Fix fork test

* Fix CI

* Add v1 token to /deprecated folder

* Remove unused code

* getBorrowATokensDescriptionsV1_5

* Fix README

* Increase test coverage

* Upgrade SizeView.version to v1.5

* Add withdraw checks

* Fix tests

* Add comment

* Fix NonTransferrableScaledTokenV1_5.allowance

* Create deposit/withdraw fork test

* Deploy LINK/USDC to base sepolia

* Deploy SizeRegistry, SizeFactory to base-sepolia

* Update migration procedure

* Add audit tests

* Add per user checks

* Fix recommendations from v1.5 review

* Fix error

* v1.5 libraries on prepare_crytic

* Redeploy SizeFactory to base-sepolia

* Update coverage [skip ci]

* Deploy SizeFactory to production

* "$@"

* Add more information about the deployment process

* Add Uniswap v3 oracle WIP

* Done UniswapV3PriceFeed (does not compile)

* Compiling

* Fix SizeFactory tests

* Add ChainlinkSequencerUptimeFeedTest

* Fix tests

* Finish UniswapV3PriceFeedTest

* Fix PriceFeed tests

* Add averageBlockTime to increase the cardinality

* Fix unit tests

* Add Custodia Security audit

* Fix CI

* Fix fork test

* Restructure folders

* Add IPriceFeedV1_5_1 interface

* Ignore warnings from Aave v3 compilation

* format

* Remove unused code

* Increase the coverage on price feeds to 100%

* Change variable name from pool to uniswapV3Pool

* Addresses issues from ChainDefenders review

* Deploy SizeFactory v1.5.1

---------

Co-authored-by: Size <[email protected]>
  • Loading branch information
aviggiano and sizecash authored Dec 17, 2024
1 parent 936b3ff commit 262c590
Show file tree
Hide file tree
Showing 51 changed files with 3,659 additions and 274 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ jobs:
path: |
out/Size.sol/Size.json
out/SizeFactory.sol/SizeFactory.json
out/IPriceFeed.sol/IPriceFeed.json
out/PriceFeed.sol/PriceFeed.json
out/IPool.sol/IPool.json
out/IERC20Metadata.sol/IERC20Metadata.json
out/Errors.sol/Errors.json
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ medusa

# Custom
selectors.txt

# Typechain
types/
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@
[submodule "lib/halmos-cheatcodes"]
path = lib/halmos-cheatcodes
url = https://github.com/a16z/halmos-cheatcodes
[submodule "lib/v3-periphery"]
path = lib/v3-periphery
url = https://github.com/Uniswap/v3-periphery
[submodule "lib/v3-core"]
path = lib/v3-core
url = https://github.com/Uniswap/v3-core
43 changes: 7 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Target networks:

## Audits

- [2024-12-10 - ChainDefenders](./audits/2024-12-10-ChainDefenders.pdf)
- [2024-11-13 - Custodia Security](./audits/2024-11-13-Custodia-Security.pdf)
- [2024-06-10 - Code4rena](https://code4rena.com/reports/2024-06-size)
- [2024-06-08 - Spearbit](./audits/2024-06-08-Spearbit.pdf)
- [2024-03-26 - Solidified](./audits/2024-03-26-Solidified.pdf)
Expand Down Expand Up @@ -208,14 +210,11 @@ for i in {0..5}; do halmos --loop $i; done

## Known limitations

- The protocol currently supports only a single market (USDC/ETH for borrow/collateral tokens)
- The protocol does not support rebasing/fee-on-transfer tokens
- The protocol does not support tokens with different decimals than the current market
- The protocol only supports tokens compliant with the IERC20Metadata interface
- The protocol only supports pre-vetted tokens
- The protocol owner, KEEPER_ROLE, PAUSER_ROLE, and BORROW_RATE_UPDATER_ROLE are trusted
- The protocol does not have any fallback oracles.
- Price feeds must be redeployed and updated in case any Chainlink configuration changes (stale price timeouts, decimals, etc)
- The protocol uses Uniswap TWAP as a fallback oracle in case Chainlink is stale.
- In case Chainlink reports a wrong price, the protocol state cannot be guaranteed. This may cause incorrect liquidations, among other issues
- In case the protocol is paused, the price of the collateral may change during the unpause event. This may cause unforseen liquidations, among other issues
- It is not possible to pause individual functions. Nevertheless, BORROW_RATE_UPDATER_ROLE and admin functions are enabled even if the protocol is paused
Expand Down Expand Up @@ -268,43 +267,15 @@ If it does not work, try removing `--verify`

### Deployment checklist

0. Due dilligence on borrow/collateral tokens: non-rebasing, IERC20Metadata
1. Deploy
2. Grant `KEEPER_ROLE` to keeper bot
3. Grant `BORROW_RATE_UPDATER_ROLE` to updater bot
4. Grant `PAUSER_ROLE` to pauser bot
2. Grant `KEEPER_ROLE` to liquidation contract
3. Grant `BORROW_RATE_UPDATER_ROLE` to bot
4. Grant `PAUSER_ROLE` to bot, multisig signers

## Upgrade

```bash
source .env.sepolia
forge script script/Upgrade.s.sol --rpc-url $RPC_URL --gas-limit 30000000 --sender $DEPLOYER_ADDRESS --account $DEPLOYER_ACCOUNT --ffi --verify -vvvvv
```

### v1.5 migration

1. Deploy the SizeFactory

```bash
source .env
export NETWORK_CONFIGURATION=base-sepolia-size-factory
forge script script/DeploySizeFactory.s.sol --rpc-url $RPC_URL --gas-limit 30000000 --sender $DEPLOYER_ADDRESS --account $DEPLOYER_ACCOUNT --ffi --verify -vvvvv
```

2. Manually call `sizeFactory.addMarket` (x2), `sizeFactory.addPriceFeed` (x2)

3. Manually call `sizeFactory.createBorrowATokenV1_5`

4. Verify the correctness through `sizeFactory.get{Markets,PriceFeeds}Descriptions`

5. Pause all markets

6. Call `GetV1_5ReinitializeDataScript`

```bash
source .env
forge script script/GetV1_5ReinitializeData.s.sol --rpc-url $RPC_URL --gas-limit 30000000 --sender $DEPLOYER_ADDRESS --account $DEPLOYER_ACCOUNT --ffi -vvvvv
```

7. Manually upgrade and reinitialize the markets: `size.upgradeToAndCall(sizeFactory.sizeImplementation(), "reinitialize")`

8. Unpause all markets
Binary file added audits/2024-11-13-Custodia-Security.pdf
Binary file not shown.
Binary file added audits/2024-12-10-ChainDefenders.pdf
Binary file not shown.
1,077 changes: 1,077 additions & 0 deletions broadcast/UpgradeSizeFactory.s.sol/8453/run-1734432794.json

Large diffs are not rendered by default.

1,077 changes: 1,077 additions & 0 deletions broadcast/UpgradeSizeFactory.s.sol/8453/run-latest.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion deployments/base-production-size-factory.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"chainId": "8453",
"commit": "e294ea5",
"deployments": {
"SizeFactory-implementation": "0xFa64CC164b87De05382dD7EfB3B2236ce8D90709",
"SizeFactory-implementation": "0x3281853D11B6AdAFaa23d01652211F8170C7eF3c",
"SizeFactory-proxy": "0x330Dc31dB45672c1F565cf3EC91F9a01f8f3DF0b"
},
"networkConfiguration": "base-production-size-factory",
Expand Down
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
no_match_test = 'testFork_'
solc_version = '0.8.23'
evm_version = 'shanghai'
ignored_warnings_from = ["lib/aave-v3-core"]

[profile.fork]
src = "src"
Expand Down
1 change: 1 addition & 0 deletions lib/v3-core
Submodule v3-core added at 6562c5
1 change: 1 addition & 0 deletions lib/v3-periphery
Submodule v3-periphery added at b325bb
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "Size v2",
"scripts": {
"solhint": "solhint \"src/**/*.sol\" --max-warnings 0",
"typechain": "npx typechain --target=ethers-v6",
"get-libraries": "(j=$((0x10)); find src/libraries test/helpers/libraries -type f | sed 's/.*\\///' | sed 's/.sol//' | while read i; do echo -n \"($i,$(printf \"0x%x\" $j))\\n\";j=$((j+1));done) | paste -sd, -",
"echidna-property": "echidna . --contract CryticTester --config echidna.yaml --test-mode property",
"echidna-assertion": "echidna . --contract CryticTester --config echidna.yaml --test-mode assertion",
Expand Down
2 changes: 2 additions & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
@crytic/properties=lib/properties
@aave=lib/aave-v3-core/contracts
halmos-cheatcodes=lib/halmos-cheatcodes/src
@uniswap/v3-core=lib/v3-core
@uniswap/v3-periphery=lib/v3-periphery
1 change: 1 addition & 0 deletions script/BaseScript.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap
import {ISize} from "@src/interfaces/ISize.sol";
import {SizeFactory} from "@src/v1.5/SizeFactory.sol";

import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {IPriceFeed} from "@src/oracle/IPriceFeed.sol";
import {ISizeV1_5} from "@src/v1.5/interfaces/ISizeV1_5.sol";
import {Script} from "forge-std/Script.sol";
Expand Down
23 changes: 14 additions & 9 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,29 +56,34 @@ contract DeployScript is BaseScript, Networks, Deploy {
);
parameters.push(
Parameter({
key: "underlyingCollateralTokenAggregator",
value: Strings.toHexString(params.underlyingCollateralTokenAggregator)
key: "priceFeedParams.baseAggregator",
value: Strings.toHexString(address(params.priceFeedParams.baseAggregator))
})
);
parameters.push(
Parameter({
key: "underlyingBorrowTokenAggregator",
value: Strings.toHexString(params.underlyingBorrowTokenAggregator)
key: "priceFeedParams.quoteAggregator",
value: Strings.toHexString(address(params.priceFeedParams.quoteAggregator))
})
);
parameters.push(
Parameter({
key: "underlyingCollateralTokenHeartbeat",
value: Strings.toString(params.underlyingCollateralTokenHeartbeat)
key: "priceFeedParams.baseStalePriceInterval",
value: Strings.toString(params.priceFeedParams.baseStalePriceInterval)
})
);
parameters.push(
Parameter({
key: "underlyingBorrowTokenHeartbeat",
value: Strings.toString(params.underlyingBorrowTokenHeartbeat)
key: "priceFeedParams.quoteStalePriceInterval",
value: Strings.toString(params.priceFeedParams.quoteStalePriceInterval)
})
);
parameters.push(
Parameter({
key: "priceFeedParams.sequencerUptimeFeed",
value: Strings.toHexString(address(params.priceFeedParams.sequencerUptimeFeed))
})
);
parameters.push(Parameter({key: "sequencerUptimeFeed", value: Strings.toHexString(params.sequencerUptimeFeed)}));
parameters.push(Parameter({key: "variablePool", value: Strings.toHexString(address(variablePool))}));

parameters.push(Parameter({key: "fragmentationFee", value: Strings.toString(params.fragmentationFee)}));
Expand Down
15 changes: 5 additions & 10 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.23;
import {IPool} from "@aave/interfaces/IPool.sol";

import {WadRayMath} from "@aave/protocol/libraries/math/WadRayMath.sol";
import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

import "@crytic/properties/contracts/util/Hevm.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
Expand All @@ -15,7 +16,7 @@ import {PoolMock} from "@test/mocks/PoolMock.sol";

import {IPriceFeed} from "@src/oracle/IPriceFeed.sol";

import {PriceFeed} from "@src/oracle/PriceFeed.sol";
import {PriceFeed, PriceFeedParams} from "@src/oracle/v1.5.1/PriceFeed.sol";

import {PriceFeedMock} from "@test/mocks/PriceFeedMock.sol";

Expand Down Expand Up @@ -189,18 +190,12 @@ abstract contract Deploy {
variablePool = IPool(_networkParams.variablePool);

if (
_networkParams.underlyingCollateralTokenAggregator == address(0)
&& _networkParams.underlyingBorrowTokenAggregator == address(0)
_networkParams.priceFeedParams.baseAggregator == AggregatorV3Interface(address(0))
&& _networkParams.priceFeedParams.quoteAggregator == AggregatorV3Interface(address(0))
) {
priceFeed = new PriceFeedMock(_owner);
} else {
priceFeed = new PriceFeed(
_networkParams.underlyingCollateralTokenAggregator,
_networkParams.underlyingBorrowTokenAggregator,
_networkParams.sequencerUptimeFeed,
_networkParams.underlyingCollateralTokenHeartbeat,
_networkParams.underlyingBorrowTokenHeartbeat
);
priceFeed = new PriceFeed(_networkParams.priceFeedParams);
}

if (_networkParams.variablePool == address(0)) {
Expand Down
47 changes: 47 additions & 0 deletions script/GetChainlinkAggregatorInformation.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {EnumerableMap} from "@openzeppelin/contracts/utils/structs/EnumerableMap.sol";
import {console} from "forge-std/Script.sol";

import {Vm} from "forge-std/Vm.sol";

import {BaseScript} from "@script/BaseScript.sol";
import {Deploy} from "@script/Deploy.sol";
import {Networks} from "@script/Networks.sol";

contract GetChainlinkAggregatorInformationScript is BaseScript, Networks, Deploy {
EnumerableMap.AddressToUintMap addresses;

function setUp() public {}

event NewRound(uint256 roundId, address startedBy, uint256 startedAt);

function run() public ignoreGas {
uint256 deploymentBlock = 17147278;
address aggregator = 0x330eC3210511cC8f5A87A737A08905092e033AF3;

bytes32[] memory topics = new bytes32[](1);
topics[0] = NewRound.selector;

uint256 toBlock = vm.getBlockNumber();
uint256 fromBlock = deploymentBlock;
uint256 batchSize = 100_000;

Vm.EthGetLogs[] memory logs;

while (fromBlock < toBlock) {
uint256 endBlock = (fromBlock + batchSize > toBlock) ? toBlock : fromBlock + batchSize;

logs = vm.eth_getLogs(fromBlock, endBlock, aggregator, topics);

for (uint256 j = 0; j < logs.length; j++) {
Vm.EthGetLogs memory log = logs[j];
uint64 blockNumber = log.blockNumber;
console.log("%s", blockNumber);
}

fromBlock = endBlock + 1;
}
}
}
Loading

0 comments on commit 262c590

Please sign in to comment.