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

Initial implementation #2

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7f847c1
initial implementation
oddaf Feb 14, 2025
cb19f73
Update README.md
oddaf Feb 18, 2025
0e5cc1b
Update script/ConvDeploy.s.sol
oddaf Feb 18, 2025
21d776c
Update src/Conv.sol
oddaf Feb 18, 2025
53a9963
Update src/Conv.t.sol
oddaf Feb 18, 2025
88354f1
Update src/mock/RatesMapping.sol
oddaf Feb 18, 2025
5f26881
Update script/generate_compact_rates.py
oddaf Feb 18, 2025
8495de0
Update README.md
oddaf Feb 18, 2025
3485e7d
Update src/Conv.t.sol
oddaf Feb 18, 2025
5a55a62
Update src/Conv.t.sol
oddaf Feb 18, 2025
d0cf22b
Update src/Conv.t.sol
oddaf Feb 18, 2025
bc93da5
Update src/Conv.t.sol
oddaf Feb 18, 2025
6326080
Update src/Conv.sol
oddaf Feb 18, 2025
4b241dc
Update src/Conv.sol
oddaf Feb 18, 2025
bfcd30b
chore: update readme (rtob())
oddaf Feb 18, 2025
dd1c7a6
chore: license agreement on the contract generator script
oddaf Feb 18, 2025
2967466
fix: path in the rates mapping generator script
oddaf Feb 18, 2025
75fa976
refactor: Move gas metering test to script
oddaf Feb 18, 2025
a74a26e
fix: Unused state var
oddaf Feb 18, 2025
d9b74b6
refactor: btor function visibility to external
oddaf Feb 18, 2025
58e505e
fix: max bps on gas metering script
oddaf Feb 18, 2025
2b13f0e
refactor: move RATES initialization to declaration
oddaf Feb 18, 2025
9c5a8a6
chore: improve natspec, formatting
oddaf Feb 18, 2025
a3164f3
refactor: change optimizer runs to 200
oddaf Feb 18, 2025
c1f161d
chore: improve natspec for the Conv contract
oddaf Feb 19, 2025
f05eec6
feat: add rtob to Conv contract generation script
oddaf Feb 19, 2025
fc691c7
refactor: rename conv generation script
oddaf Feb 19, 2025
8fcc4c6
Update script/GasMetering.s.sol
oddaf Feb 20, 2025
991e692
Update script/generate_rates_mapping.py
oddaf Feb 21, 2025
6cafe02
Update src/Conv.sol
oddaf Feb 21, 2025
9896d39
Update src/Conv.sol
oddaf Feb 21, 2025
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
661 changes: 661 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## Conv

On-chain repository for MCD rates.

`Conv` stores all per-second MCD rates for annualized BPSs in a single on-chain repository.

It allows to convert BPS into `RAY` accumulators and _vice versa_.

### Motivation

Useful for validation using human-friendly notation, which drastically reduces the cognitive overhead when checking rates.

Requirements:
- The rates need to have full precision compared to rates currently used in MCD (https://ipfs.io/ipfs/QmVp4mhhbwWGTfbh2BzwQB9eiBrQBKiqcPRZCaAxNUaar6)
- Read cost should be reasonable, allowing other components of the system to use it without too much overhead.
- The contract needs to be deployable efficiently (low priority, one time cost).

### Design

We explored several ways to store or calculate rates onchain and arrive at this approach, for details see [this](https://github.com/dewiz-xyz/conv-research).

The contract makes use of optimized storage to ease the cost of deployment. Each rate is stored as `rate - RAY`, so only the relevant part of the rate takes space in storage. Each rate is stored in 8 bytes, so every storage position fits exactly four rates.

On reads, the function `btor(bps)` will fetch the correct storage slot, fetch the desired rate within it, add one RAY and return the result.

The contract also includes a conversion function `rtob(ray)` that calculates the annualized BPS rate from the per-second rate.

### Limitations

- Since rates are stored in 8 bytes, the max BPS that can be used without reimplementing this contract is **7891**.
- EIP-170: Due to contract size limits on Ethereum mainnet, the ceiling for rates is 6k. On L2s that do not enforce the limit this does not apply.
- Gas cost of deployment: With the current 30M block gas ceiling on Ethereum mainnet, up to ~5.5k rates can be stored.

## Deployments

- **5000bps Ethereum Mainnet**: tbd

## Usage

### Build

```shell
$ forge build
```

### Test

```shell
$ forge test
```

### Gas Snapshots

```shell
$ forge snapshot
```

### Deploy

```shell
$ forge script script/ConvDeploy.s.sol:ConvDeployScript \
--rpc-url $ETH_RPC_URL \
--broadcast
```
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ libs = ["lib"]
solc = '0.8.24'

optimizer = true
optimizer_runs = 1
optimizer_runs = 200

[fuzz]
runs = 256000
Expand Down
36 changes: 36 additions & 0 deletions script/ConvDeploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: 2025 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {ScriptTools} from "dss-test/ScriptTools.sol";
import {Conv} from "src/Conv.sol";

contract ConvDeployScript is Script {
using ScriptTools for string;

string constant NAME = "conv-deploy";

function run() external {
vm.startBroadcast();

Conv conv = new Conv();

vm.stopBroadcast();

ScriptTools.exportContract(NAME, "conv", address(conv));
}
}
146 changes: 146 additions & 0 deletions script/GasMetering.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// SPDX-FileCopyrightText: 2025 Dai Foundation <www.daifoundation.org>
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.24;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";
import {Conv} from "src/Conv.sol";

contract GasMeteringScript is Script {
function run() external {
Conv conv;

uint256 gasBefore = gasleft();
conv = new Conv();
console.log("Deploy: ", gasBefore - gasleft());

for (uint256 i; i <= 5_000; i += 123) {
gasBefore = gasleft();
conv.btor(i);
console.log("btor", i, ":", gasBefore - gasleft());
}

uint256[] memory rates = new uint256[](101);

rates[0] = 1000000000000000000000000000;
rates[1] = 1000000000315522921573372069;
rates[2] = 1000000000627937192491029810;
rates[3] = 1000000000937303470807876289;
rates[4] = 1000000001243680656318820312;
rates[5] = 1000000001547125957863212448;
rates[6] = 1000000001847694957439350562;
rates[7] = 1000000002145441671308778766;
rates[8] = 1000000002440418608258400030;
rates[9] = 1000000002732676825177582095;
rates[10] = 1000000003022265980097387650;
rates[11] = 1000000003309234382829738808;
rates[12] = 1000000003593629043335673582;
rates[13] = 1000000003875495717943815211;
rates[14] = 1000000004154878953532704765;
rates[15] = 1000000004431822129783699001;
rates[16] = 1000000004706367499604668374;
rates[17] = 1000000004978556227818707070;
rates[18] = 1000000005248428428206454010;
rates[19] = 1000000005516023198985389892;
rates[20] = 1000000005781378656804591712;
rates[21] = 1000000006044531969328866955;
rates[22] = 1000000006305519386481930552;
rates[23] = 1000000006564376270414306730;
rates[24] = 1000000006821137124257914908;
rates[25] = 1000000007075835619725814915;
rates[26] = 1000000007328504623612325153;
rates[27] = 1000000007579176223245671878;
rates[28] = 1000000007827881750942464045;
rates[29] = 1000000008074651807510602798;
rates[30] = 1000000008319516284844715115;
rates[31] = 1000000008562504387655836125;
rates[32] = 1000000008803644654374843395;
rates[33] = 1000000009042964977267059505;
rates[34] = 1000000009280492621793477151;
rates[35] = 1000000009516254245252215861;
rates[36] = 1000000009750275914732082986;
rates[37] = 1000000009982583124408477109;
rates[38] = 1000000010213200812210332586;
rates[39] = 1000000010442153375885353361;
rates[40] = 1000000010669464688489416886;
rates[41] = 1000000010895158113324739488;
rates[42] = 1000000011119256518350177948;
rates[43] = 1000000011341782290085893805;
rates[44] = 1000000011562757347033522598;
rates[45] = 1000000011782203152631966084;
rates[46] = 1000000012000140727767957524;
rates[47] = 1000000012216590662859635112;
rates[48] = 1000000012431573129530493155;
rates[49] = 1000000012645107891890261872;
rates[50] = 1000000012857214317438491659;
rates[51] = 1000000013067911387605883890;
rates[52] = 1000000013277217707947715318;
rates[53] = 1000000013485151518003044532;
rates[54] = 1000000013691730700832764691;
rates[55] = 1000000013896972792248974855;
rates[56] = 1000000014100894989747580713;
rates[57] = 1000000014303514161155502800;
rates[58] = 1000000014504846853003364537;
rates[59] = 1000000014704909298634052283;
rates[60] = 1000000014903717426057083481;
rates[61] = 1000000015101286865558285606;
rates[62] = 1000000015297632957073876761;
rates[63] = 1000000015492770757337647112;
rates[64] = 1000000015686715046809567945;
rates[65] = 1000000015879480336393800741;
rates[66] = 1000000016071080873953741499;
rates[67] = 1000000016261530650631414500;
rates[68] = 1000000016450843406978224029;
rates[69] = 1000000016639032638903781446;
rates[70] = 1000000016826111603449247521;
rates[71] = 1000000017012093324391365593;
rates[72] = 1000000017196990597683109018;
rates[73] = 1000000017380815996736626004;
rates[74] = 1000000017563581877553935633;
rates[75] = 1000000017745300383710610088;
rates[76] = 1000000017925983451197469286;
rates[77] = 1000000018105642813125114801;
rates[78] = 1000000018284290004295939569;
rates[79] = 1000000018461936365648068049;
rates[80] = 1000000018638593048575507813;
rates[81] = 1000000018814271019128627481;
rates[82] = 1000000018988981062098917230;
rates[83] = 1000000019162733784991836346;
rates[84] = 1000000019335539621891407188;
rates[85] = 1000000019507408837220076029;
rates[86] = 1000000019678351529397228463;
rates[87] = 1000000019848377634399619849;
rates[88] = 1000000020017496929226859581;
rates[89] = 1000000020185719035274971385;
rates[90] = 1000000020353053421620940223;
rates[91] = 1000000020519509408221049399;
rates[92] = 1000000020685096169025709028;
rates[93] = 1000000020849822735013378765;
rates[94] = 1000000021013697997146093523;
rates[95] = 1000000021176730709249010667;
rates[96] = 1000000021338929490816310513;
rates[97] = 1000000021500302829745698932;
rates[98] = 1000000021660859085003681151;
rates[99] = 1000000021820606489223699321;
rates[100] = 1000000021979553151239153027;

for (uint256 i; i < rates.length; i++) {
gasBefore = gasleft();
conv.rtob(rates[i]);
console.log("rtob", rates[i], ":", gasBefore - gasleft());
}
}
}
Loading
Loading