├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── .husky
└── pre-commit
├── .lintstagedrc
├── .npmrc
├── .prettierrc.json
├── .solhint.json
├── README.md
├── foundry.toml
├── package.json
├── pnpm-lock.yaml
├── remappings.txt
├── script
├── cli
│ ├── README.md
│ ├── build-helper
│ │ └── library.ts
│ ├── build-hoax-helper
│ │ └── library.ts
│ ├── findBestOptimizerRuns.ts
│ ├── main.ts
│ ├── renameTestContracts.ts
│ ├── toNamedImports.ts
│ ├── types.ts
│ └── utils.ts
└── updateEnv.ts
├── src
├── AddressHelper.sol
├── ArrayHelper.sol
├── BaseScript.sol
├── BytesHelper.sol
├── FraxTest.sol
├── FrxTransparentProxy.sol
├── Logger.sol
├── NumberFormat.sol
├── StringsHelper.sol
├── TestHelper.sol
├── VmHelper.sol
├── access-control
│ ├── v1
│ │ ├── Timelock2Step.sol
│ │ └── interfaces
│ │ │ └── ITimelock2Step.sol
│ └── v2
│ │ ├── Operator2Step.sol
│ │ ├── OperatorRole.sol
│ │ ├── PublicReentrancyGuard.sol
│ │ ├── Timelock2Step.sol
│ │ └── interfaces
│ │ ├── IOperator2Step.sol
│ │ ├── IOperatorRole.sol
│ │ └── ITimelock2Step.sol
└── oracles
│ ├── AggregatorV3InterfaceStructHelper.sol
│ └── OracleHelper.sol
├── test
├── LoggerTest.t.sol
├── NumberFormatTest.t.sol
├── TestArrayHelper.t.sol
├── TestFrxProxy.t.sol
├── TestMultipleSetup.t.sol
└── TestSlotDump.t.sol
└── tsconfig.json
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 | name: Node.js CI
4 | on:
5 | push:
6 | branches: master
7 | pull_request:
8 | jobs:
9 | build:
10 | timeout-minutes: 60
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/setup-node@v2
14 | with:
15 | node-version: 16.x
16 | - uses: actions/checkout@v2
17 | - uses: pnpm/action-setup@v2
18 | with:
19 | version: 8.11.0
20 |
21 | - name: Install Foundry
22 | uses: foundry-rs/foundry-toolchain@v1
23 | with:
24 | version: nightly
25 | - run: pnpm i
26 | - run: forge build
27 | - run: pnpm test
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiler files
2 | cache/
3 | out/
4 |
5 | # Ignores development broadcast logs
6 | !/broadcast
7 | /broadcast/*/31337/
8 | /broadcast/**/dry-run/
9 |
10 | # Docs
11 | docs/
12 |
13 | # Dotenv file
14 | .env
15 |
16 | # node
17 | node_modules
18 |
19 | #misc
20 | .DS_Store
21 |
22 | # build
23 | dist
24 |
25 | .vscode
26 | package-lock.json
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | npx lint-staged
2 |
--------------------------------------------------------------------------------
/.lintstagedrc:
--------------------------------------------------------------------------------
1 | {
2 | "*.{js,json,sol,ts,yaml,yml}": [
3 | "prettier --config ./.prettierrc.json --write"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | public-hoist-pattern=*
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "useTabs": false,
4 | "plugins": ["prettier-plugin-solidity"],
5 | "overrides": [
6 | {
7 | "files": "*.sol",
8 | "options": {
9 | "bracketSpacing": true,
10 | "tabWidth": 4,
11 | "singleQuote": false,
12 | "parser": "solidity-parse"
13 | }
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/.solhint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "solhint:recommended",
3 | "plugins": ["prettier"],
4 | "rules": {
5 | "code-complexity": ["warn", 8],
6 | "compiler-version": ["warn", ">=0.8.0"],
7 | "const-name-snakecase": "off",
8 | "constructor-syntax": "error",
9 | "func-visibility": ["warn", { "ignoreConstructors": true }],
10 | "max-line-length": ["warn", 120],
11 | "not-rely-on-time": "warn",
12 | "prettier/prettier": [
13 | "warn",
14 | {
15 | "endOfLine": "auto"
16 | }
17 | ],
18 | "reason-string": ["warn", { "maxLength": 32 }],
19 | "func-param-name-mixedCase": "warn",
20 | "named-parameters-mapping": "warn",
21 | "private-vars-leading-underscore": "warn",
22 | "no-console": "warn"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Frax Style Guide (Work In Progress)
2 |
3 | ## The intention of this style guide is first and foremost to increase readability of code and reduce the potential for bugs. Readability reduces overhead for new readers which includes colleagues and most importantly auditors. Additionally, consistency reduces cognitive overhead. When people read our code they should walk away feeling “Holy shit these guys are obsessed”. This comes with trade-offs, most obvious the speed at which code is **********initially********** written.
4 |
5 | ## This style guide is meant to be collaborative and in its current state is just a first pass (with some highly opinionated items), so if you disagree please reach out or make a PR instead of just ignoring it. Good programmers are flexible and the guide is pointless if we don’t follow it.
6 |
7 | # Principles
8 |
9 | ### Optimize for the reader (auditor) and fellow developers, not the writer
10 |
11 | We explicitly optimize for the experience of the reader, not the writer. Implicitly this means that the speed of writing new code will decrease. The ultimate goal of these rules is to provide a framework that allows new readers the ability to quickly understand the codebase and to reduce the surface area for auditor focus.
12 |
13 | ### Be consistent
14 |
15 | Good engineers are flexible not dogmatic, don’t mix and match styles. Consistency reduces cognitive overhead for readers.
16 |
17 | # Repository
18 |
19 | ### Use kebab-case for repository names and folder names
20 |
21 | Example: `@FraxFinance/fraxlend-dev`
22 |
23 | ### Use `-dev` suffix to indicate internal repos, public repos should have the same name without `-dev`
24 |
25 | Example:
26 | Private Repo: `fraxlend-dev`
27 | Public Repo: `fraxlend`
28 |
29 | ### Utilize forge + prettier as the default formatter
30 |
31 | This repo contains a .prettierrc.json file for use with prettier. Prettier is significantly smarter and has better line-wrapping heuristics than forge
32 |
33 | ### Utilize solhint as the default linter
34 |
35 | This repo contains a .solhint.json file for use with solhint
36 |
37 | ### Utilize husky and lint-staged to lint all files pre-commit
38 |
39 | This repo has an example `.lintstagedrc` file and `.husky` folder for reference
40 |
41 | ## File Names
42 |
43 | ### One Contract/Interface/Library per File
44 |
45 | Utilize an import file if you would like to group files together by namespace for easy importing
46 |
47 | Example:
48 |
49 | ```solidity
50 | // This file aggregates the different contracts and should be named appropriately
51 | import { SomeContract } from ".SomeContract.sol";
52 | import { SomeContract1 } from ".SomeContract1.sol";
53 | import { SomeContract2 } from ".SomeContract2.sol";
54 | import { SomeContract3 } from ".SomeContract3.sol";
55 | ```
56 |
57 | ### Use PascalCase.sol for file names containing Contracts
58 |
59 | ### Use IPascalCase.sol for file names containing interfaces
60 |
61 | ### File Name should exactly match the name of the contract/interface/library
62 |
63 | ### Files containing tests should start with word `Test` and end with `.t.sol`
64 |
65 | Example: `TestFraxlendPairCore.t.sol`
66 |
67 | ### Use camelCase for files containing a group of free functions
68 |
69 | Example: `deployFunctions.sol` (contains no contracts just a collection of free functions)
70 |
71 | ### Root directory should contains `src`, `test`, `script` directories
72 |
73 | `src` contains contracts and interfaces which are deployed
74 |
75 | `test` contains test contracts
76 |
77 | `script` contains files for scripting including repo management and deploy scripts
78 |
79 | # Misc
80 |
81 | ### Use pnpm to install github dependencies
82 | Why: submodules dont provide lockfiles or commit binding. We need to be sure that we are running/deploying the exact same code across machines.
83 | Why: Breaking changes are common and explicitly upgrading can prevent issues across machines
84 |
85 | ### Prefer node_module packages over github packages for secure code
86 |
87 | Why: Latest code can be unstable and pnpm packages are typically release candidates
88 |
89 | ### Use Proper licenses
90 |
91 | Proprietary: `// SPDX-License-Identifier: BUSL-1.1`
92 |
93 | Open and composable: TODO
94 |
95 | # Language Features
96 |
97 | ### Do not rely on via-ir to solve stack-too-deep errors
98 |
99 | Why: via-ir is slow and reduces testing speed. If reaching `stack too deep` your code complexity is probably too high. For src code, reduce complexity, for tests use param/return structs.
100 |
101 | ### Use named input params when invoking functions
102 | Required for functions with 2+ parameters
103 |
104 | Example:
105 |
106 | ```solidity
107 | function fooBar(address _foo, address _bar) internal;
108 |
109 | //Good
110 | fooBar({ _foo: address(123), _bar: address(345)});
111 |
112 | //Bad
113 | fooBar(address(345), address(123));
114 | ```
115 |
116 | Why:
117 |
118 | - Reduces potential bugs introduced during refactors which change order of functions
119 | - Reduces overhead for readers as code intention is more clear, eliminates need to look at function definition
120 |
121 | # Source File Structure
122 |
123 | ### File Structure should be in the following order:
124 |
125 | 1. license
126 | 2. pragma
127 | 3. Frax Ascii art
128 | 4. imports
129 | 5. ConstructorParams Struct
130 | 6. Contract
131 |
132 | ### Imports should occur in the following order:
133 |
134 | 1. github packages
135 | 2. node_module packages
136 | 3. contracts
137 | 4. interfaces
138 | - within each category, items should be alphabetical
139 |
140 | ### Use named imports { SomeContract } from "./SomeContract.sol";
141 |
142 | Why:
143 | - [Forge best practices](https://book.getfoundry.sh/tutorials/best-practices)
144 | - Reduces the need for the reader to have additional context when coming across an identifier. Because identifiers are otherwise inherited, the location of an identifier is not known to the reader without a global search or IDE tooling
145 | - Solves issues with naming collisions
146 | - Makes compilation (and therefore testing) faster and makes verified code smaller
147 |
148 | ### Call inherited contract constructors in the order they are inherited
149 |
150 | Why: Helps solve stack-too-deep errors, consistency, reinforces order of constructor execution
151 |
152 | ## Naming
153 |
154 | ### Immutable and constant variables should be CONSTANT_CASE
155 |
156 | ### Internal and private functions should be prepended with an underscore _someInternalFunction _somePrivateFunction
157 |
158 | ## Avoid abbreviations and acronyms in variables names, prefer descriptive variable names
159 |
160 | Code should be self-documenting. Give as descriptive a name as possible. It is far more important to make your code immediately understandable by a new reader than to optimize line wrapping. Do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.
161 |
162 | | Allowed | |
163 | | --- | --- |
164 | | errorCount | No abbreviation. |
165 | | dnsConnectionIndex | Most people know what "DNS" stands for. |
166 | | referrerUrl | Ditto for "URL". |
167 | | customerId | "Id" is both ubiquitous and unlikely to be misunderstood. |
168 |
169 | | Disallowed | |
170 | | --- | --- |
171 | | n | Meaningless. |
172 | | nErr | Ambiguous abbreviation. |
173 | | nCompConns | Ambiguous abbreviation. |
174 | | wgcConnections | Only your group knows what this stands for. |
175 | | pcReader | Lots of things can be abbreviated "pc". |
176 | | cstmrId | Deletes internal letters. |
177 | | kSecondsPerDay | Do not use Hungarian notation. |
178 |
179 | ## Method names
180 |
181 | ### Method names are written in camelCase and are typically verbs or verb phrases
182 |
183 | Example: sendMessage or stopProcess.
184 |
185 | ### Enum names are written in PascalCase and should generally be singular nouns. Individual items within the enum are named in CONSTANT_CASE.
186 |
187 | ### Parameter names are written in camelCase and prepended with an _ if memory or without to designate storage pointers
188 |
189 | Example:
190 |
191 | ```solidity
192 | function sendMessage(string memory _messageBody, string storage messageHeader);
193 | ```
194 |
195 | ### Storage variable names are written in camelCase
196 |
197 | ### Local variable names are written in _camelCase and prepended with an underscore to differentiate from storage variables
198 |
199 | ## Use google’s camelCase algorithm to handle acronyms/abbreviations and edge cases
200 | Additional Info: [Google camelCase Algorithm](https://google.github.io/styleguide/jsguide.html#naming-camel-case-defined)
201 | Additional clarity: for words like iOS veFXS or gOhm, when prefix letter is single treat as one word, when prefix letters are >1 (frxETH or veFXS) treat prefix as separate word:
202 |
203 | | Prose form | Correct | Incorrect |
204 | | --- | --- | --- |
205 | | veFXS | veFxs | veFXS |
206 | | some gOhm item | someGohmItem | someGOHMItem |
207 | | XML HTTP request | xmlHttpRequest | XMLHTTPRequest |
208 | | iOS | ios | IOS |
209 | | new customer ID | newCustomerId | newCustomerID |
210 | | inner stopwatch | innerStopwatch | innerStopWatch |
211 | | supports IPv6 on iOS? | supportsIpv6OnIos | supportsIPv6OnIOS |
212 | | YouTube importer | youTubeImporter | YoutubeImporter* |
213 | | gOHM ERC-20 | gohmErc20 | gOHMERC20 |
214 | | some veFXS item | someVeFxsItem | someVeFXSItem |
215 |
216 | ## Code Structure / Architecture
217 |
218 | ### Be thoughtful about breaking up code and inheriting.
219 | One pattern used in fraxlend is a separation of view helper functions and the core logic. This is a separation by threat model.
220 |
221 | ### Group related code together
222 | Be thoughtful about the order in which you would like to present information to a new reader. For internal functions used in a single place, group them next to the external function they are used in. If they are used in multiple places follow guidelines below.
223 |
224 | ### Within a contract code should be in the following order:
225 | [Open for discussion on this item]
226 |
227 | 1. storage variables
228 | 2. constructor
229 | 3. internals/helpers used in multiple places
230 | 4. external functions
231 | 5. custom errors
232 | 6. Events should be defined in the interface.
233 |
234 |
235 | ### Explicitly assign default values to named return params for maximum readability
236 |
237 | ### Empty catch blocks should have comments explaining why they are acceptable
238 |
239 | ### [Important] Separate calculation and storage mutation functions when possible.
240 | This aids in testing and separation of concerns, helps adhere to checks-effects-interactions patterns. For calculations, use storage pointers as arguments to reduce SLOADs if necessary. Allows for the creation of preview functions to create a preview of some action, this is required for compose-ability (see ERC4626 for an example of preview functions)
241 | See: TODO: governance example in delegation
242 |
243 | ### Avoid mutations when possible
244 | Gas savings is not a good reason to mutate. Write readable code then optimize gas when necessary. Makes debugging easier and code understanding more clear.
245 |
246 | ### Avoid modifiers unless you need to take action both before and after function invocation
247 | Create internal functions in the form of _requireCondition() which will revert on failure.
248 | Why: This allows optimizer to reduce bytecode more efficiently, works better with IDE and analysis tools, and increases code intention without needing to jump to modifier definition. Also order of execution is explicit. [Exception: when you need to run code both BEFORE and AFTER the wrapped function]
249 | ``` solidity
250 | // BAD
251 | modifier TimelockOnly() {
252 | if (msg.sender != TIMELOCK_ADDRESS) revert()
253 | }
254 |
255 | function WithdrawFees() TimelockOnly {
256 | // some code
257 | }
258 |
259 | // GOOD
260 | function _requireSenderIsTimelock() internal {
261 | if (msg.sender != TIMELOCK_ADDRESS) revert Unauthorized();
262 | }
263 |
264 | function WithdrawFees() {
265 | _requireSenderIsTimelock();
266 | // some code
267 | }
268 | ```
269 |
270 |
271 | ### Use custom errors over require statements, saves both byte code and gas
272 | ```solidity
273 | // Bad
274 | function _requireSenderIsTimelock() internal {
275 | require(msg.sender = TIMELOCK_ADDRESS, "unauthorized");
276 | }
277 |
278 | // Good
279 | function _requireSenderIsTimelock() internal {
280 | if (msg.sender != TIMELOCK_ADDRESS) revert Unauthorized();
281 | }
282 | ```
283 |
284 |
285 | ### Dont return expressions, instead assign named return param variable
286 |
287 |
288 | # Tests
289 | ### Separate scenario setup and test functions.
290 | Why: Tests for impure functions should be tested under a variety of state conditions. Separating test assertions and scenario setups allows for re-using code across multiple scenarios. See
291 |
292 | ### Write tests in a way that you can run the test suite against deployed contracts afterwards
293 | See: [Frax Governance Test Example](https://github.com/FraxFinance/frax-governance-dev/blob/098a14115b447f4de94902a4ff13882ac1059ee5/test/TestFraxGovernorFork.t.sol)
294 | See: [Fraxlend Oracles Test Example](https://github.com/FraxFinance/fraxlend-oracles-dev/blob/master/test/e2e/TestFraxUsdcCurveLpDualOracle.t.sol)
295 |
296 | ### Utilize fuzz tests
297 |
298 | ### Separate helpers to separate file
299 |
300 | ### Create invariant assertions that can be used in multiple places
301 |
302 | ### Dont sleep on echidna
303 |
304 | # Pre-Audit Checklist
305 |
306 | - 100% test coverage
307 | - Adheres to style guide
308 | - Example deployment instructions
309 | - Slither and Mythril instructions and remaining issues addressed
310 | - Video walkthrough of each external function flow
311 | - Access control documentation
312 | - Threat modeling documentation
313 | - Heavy commenting aimed at new reader
314 | - No TODO, console.log, or commented out code
315 |
--------------------------------------------------------------------------------
/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | src = 'src'
3 | out = 'out'
4 | libs = ["node_modules"]
5 |
6 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frax-standard-solidity",
3 | "version": "1.0.0",
4 | "description": "A standard library for frax solidity",
5 | "main": "src",
6 | "directories": {
7 | "lib": "lib",
8 | "test": "test"
9 | },
10 | "scripts": {
11 | "test": "forge test",
12 | "prepare": "husky install",
13 | "build": "tsc"
14 | },
15 | "author": "Drake Evans (twitter.com/drakeevansv1)",
16 | "license": "ISC",
17 | "dependencies": {
18 | "@chainlink/contracts": "^0.6.1",
19 | "@openzeppelin/contracts": "^5.0.1",
20 | "@types/fs-extra": "^11.0.4",
21 | "@types/node": "^18.19.7",
22 | "change-case": "^4.1.2",
23 | "commander": "^10.0.1",
24 | "date-fns": "^2.30.0",
25 | "ds-test": "github:dapphub/ds-test",
26 | "forge-std": "github:foundry-rs/forge-std#77041d2ce690e692d6e03cc812b57d1ddaa4d505",
27 | "fs-extra": "^11.2.0",
28 | "husky": "^8.0.3",
29 | "lint-staged": "^13.3.0",
30 | "prettier": "^3.2.2",
31 | "prettier-plugin-solidity": "^1.3.1",
32 | "solc": "^0.8.23",
33 | "solhint": "^3.6.2",
34 | "solhint-plugin-prettier": "^0.1.0",
35 | "solidity-bytes-utils": "^0.8.2",
36 | "toml": "^3.0.0",
37 | "ts-node": "^10.9.2",
38 | "typescript": "^5.3.3"
39 | },
40 | "devDependencies": {
41 | "glob": "^10.3.10"
42 | },
43 | "packageManager": "pnpm@10.2.1+sha512.398035c7bd696d0ba0b10a688ed558285329d27ea994804a52bad9167d8e3a72bcb993f9699585d3ca25779ac64949ef422757a6c31102c12ab932e5cbe5cc92"
44 | }
45 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: "9.0"
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | importers:
8 | .:
9 | dependencies:
10 | "@chainlink/contracts":
11 | specifier: ^0.6.1
12 | version: 0.6.1(ethers@5.8.0)
13 | "@openzeppelin/contracts":
14 | specifier: ^5.0.1
15 | version: 5.3.0
16 | "@types/fs-extra":
17 | specifier: ^11.0.4
18 | version: 11.0.4
19 | "@types/node":
20 | specifier: ^18.19.7
21 | version: 18.19.103
22 | change-case:
23 | specifier: ^4.1.2
24 | version: 4.1.2
25 | commander:
26 | specifier: ^10.0.1
27 | version: 10.0.1
28 | date-fns:
29 | specifier: ^2.30.0
30 | version: 2.30.0
31 | ds-test:
32 | specifier: github:dapphub/ds-test
33 | version: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0
34 | forge-std:
35 | specifier: github:foundry-rs/forge-std#77041d2ce690e692d6e03cc812b57d1ddaa4d505
36 | version: https://codeload.github.com/foundry-rs/forge-std/tar.gz/77041d2ce690e692d6e03cc812b57d1ddaa4d505
37 | fs-extra:
38 | specifier: ^11.2.0
39 | version: 11.3.0
40 | husky:
41 | specifier: ^8.0.3
42 | version: 8.0.3
43 | lint-staged:
44 | specifier: ^13.3.0
45 | version: 13.3.0
46 | prettier:
47 | specifier: ^3.2.2
48 | version: 3.5.3
49 | prettier-plugin-solidity:
50 | specifier: ^1.3.1
51 | version: 1.4.3(prettier@3.5.3)
52 | solc:
53 | specifier: ^0.8.23
54 | version: 0.8.30
55 | solhint:
56 | specifier: ^3.6.2
57 | version: 3.6.2(typescript@5.8.3)
58 | solhint-plugin-prettier:
59 | specifier: ^0.1.0
60 | version: 0.1.0(prettier-plugin-solidity@1.4.3(prettier@3.5.3))(prettier@3.5.3)
61 | solidity-bytes-utils:
62 | specifier: ^0.8.2
63 | version: 0.8.4
64 | toml:
65 | specifier: ^3.0.0
66 | version: 3.0.0
67 | ts-node:
68 | specifier: ^10.9.2
69 | version: 10.9.2(@types/node@18.19.103)(typescript@5.8.3)
70 | typescript:
71 | specifier: ^5.3.3
72 | version: 5.8.3
73 | devDependencies:
74 | glob:
75 | specifier: ^10.3.10
76 | version: 10.4.5
77 |
78 | packages:
79 | "@babel/code-frame@7.27.1":
80 | resolution:
81 | { integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== }
82 | engines: { node: ">=6.9.0" }
83 |
84 | "@babel/helper-validator-identifier@7.27.1":
85 | resolution:
86 | { integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== }
87 | engines: { node: ">=6.9.0" }
88 |
89 | "@babel/runtime@7.27.1":
90 | resolution:
91 | { integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog== }
92 | engines: { node: ">=6.9.0" }
93 |
94 | "@chainlink/contracts@0.6.1":
95 | resolution:
96 | { integrity: sha512-EuwijGexttw0UjfrW+HygwhQIrGAbqpf1ue28R55HhWMHBzphEH0PhWm8DQmFfj5OZNy8Io66N4L0nStkZ3QKQ== }
97 |
98 | "@cspotcode/source-map-support@0.8.1":
99 | resolution:
100 | { integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== }
101 | engines: { node: ">=12" }
102 |
103 | "@eth-optimism/contracts@0.5.40":
104 | resolution:
105 | { integrity: sha512-MrzV0nvsymfO/fursTB7m/KunkPsCndltVgfdHaT1Aj5Vi6R/doKIGGkOofHX+8B6VMZpuZosKCMQ5lQuqjt8w== }
106 | peerDependencies:
107 | ethers: ^5
108 |
109 | "@eth-optimism/core-utils@0.12.0":
110 | resolution:
111 | { integrity: sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw== }
112 |
113 | "@ethersproject/abi@5.8.0":
114 | resolution:
115 | { integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q== }
116 |
117 | "@ethersproject/abstract-provider@5.8.0":
118 | resolution:
119 | { integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg== }
120 |
121 | "@ethersproject/abstract-signer@5.8.0":
122 | resolution:
123 | { integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA== }
124 |
125 | "@ethersproject/address@5.8.0":
126 | resolution:
127 | { integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA== }
128 |
129 | "@ethersproject/base64@5.8.0":
130 | resolution:
131 | { integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ== }
132 |
133 | "@ethersproject/basex@5.8.0":
134 | resolution:
135 | { integrity: sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q== }
136 |
137 | "@ethersproject/bignumber@5.8.0":
138 | resolution:
139 | { integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA== }
140 |
141 | "@ethersproject/bytes@5.8.0":
142 | resolution:
143 | { integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A== }
144 |
145 | "@ethersproject/constants@5.8.0":
146 | resolution:
147 | { integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg== }
148 |
149 | "@ethersproject/contracts@5.8.0":
150 | resolution:
151 | { integrity: sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ== }
152 |
153 | "@ethersproject/hash@5.8.0":
154 | resolution:
155 | { integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA== }
156 |
157 | "@ethersproject/hdnode@5.8.0":
158 | resolution:
159 | { integrity: sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA== }
160 |
161 | "@ethersproject/json-wallets@5.8.0":
162 | resolution:
163 | { integrity: sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w== }
164 |
165 | "@ethersproject/keccak256@5.8.0":
166 | resolution:
167 | { integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng== }
168 |
169 | "@ethersproject/logger@5.8.0":
170 | resolution:
171 | { integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA== }
172 |
173 | "@ethersproject/networks@5.8.0":
174 | resolution:
175 | { integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg== }
176 |
177 | "@ethersproject/pbkdf2@5.8.0":
178 | resolution:
179 | { integrity: sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg== }
180 |
181 | "@ethersproject/properties@5.8.0":
182 | resolution:
183 | { integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw== }
184 |
185 | "@ethersproject/providers@5.8.0":
186 | resolution:
187 | { integrity: sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw== }
188 |
189 | "@ethersproject/random@5.8.0":
190 | resolution:
191 | { integrity: sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A== }
192 |
193 | "@ethersproject/rlp@5.8.0":
194 | resolution:
195 | { integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q== }
196 |
197 | "@ethersproject/sha2@5.8.0":
198 | resolution:
199 | { integrity: sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A== }
200 |
201 | "@ethersproject/signing-key@5.8.0":
202 | resolution:
203 | { integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w== }
204 |
205 | "@ethersproject/solidity@5.8.0":
206 | resolution:
207 | { integrity: sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA== }
208 |
209 | "@ethersproject/strings@5.8.0":
210 | resolution:
211 | { integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg== }
212 |
213 | "@ethersproject/transactions@5.8.0":
214 | resolution:
215 | { integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg== }
216 |
217 | "@ethersproject/units@5.8.0":
218 | resolution:
219 | { integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ== }
220 |
221 | "@ethersproject/wallet@5.8.0":
222 | resolution:
223 | { integrity: sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA== }
224 |
225 | "@ethersproject/web@5.8.0":
226 | resolution:
227 | { integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw== }
228 |
229 | "@ethersproject/wordlists@5.8.0":
230 | resolution:
231 | { integrity: sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg== }
232 |
233 | "@isaacs/cliui@8.0.2":
234 | resolution:
235 | { integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== }
236 | engines: { node: ">=12" }
237 |
238 | "@jridgewell/resolve-uri@3.1.2":
239 | resolution:
240 | { integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== }
241 | engines: { node: ">=6.0.0" }
242 |
243 | "@jridgewell/sourcemap-codec@1.5.0":
244 | resolution:
245 | { integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== }
246 |
247 | "@jridgewell/trace-mapping@0.3.9":
248 | resolution:
249 | { integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== }
250 |
251 | "@openzeppelin/contracts-upgradeable@4.9.6":
252 | resolution:
253 | { integrity: sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA== }
254 |
255 | "@openzeppelin/contracts@3.4.2":
256 | resolution:
257 | { integrity: sha512-z0zMCjyhhp4y7XKAcDAi3Vgms4T2PstwBdahiO0+9NaGICQKjynK3wduSRplTgk4LXmoO1yfDGO5RbjKYxtuxA== }
258 |
259 | "@openzeppelin/contracts@4.3.3":
260 | resolution:
261 | { integrity: sha512-tDBopO1c98Yk7Cv/PZlHqrvtVjlgK5R4J6jxLwoO7qxK4xqOiZG+zSkIvGFpPZ0ikc3QOED3plgdqjgNTnBc7g== }
262 |
263 | "@openzeppelin/contracts@5.3.0":
264 | resolution:
265 | { integrity: sha512-zj/KGoW7zxWUE8qOI++rUM18v+VeLTTzKs/DJFkSzHpQFPD/jKKF0TrMxBfGLl3kpdELCNccvB3zmofSzm4nlA== }
266 |
267 | "@pkgjs/parseargs@0.11.0":
268 | resolution:
269 | { integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== }
270 | engines: { node: ">=14" }
271 |
272 | "@prettier/sync@0.3.0":
273 | resolution:
274 | { integrity: sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw== }
275 | peerDependencies:
276 | prettier: ^3.0.0
277 |
278 | "@solidity-parser/parser@0.16.2":
279 | resolution:
280 | { integrity: sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg== }
281 |
282 | "@solidity-parser/parser@0.20.1":
283 | resolution:
284 | { integrity: sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw== }
285 |
286 | "@tsconfig/node10@1.0.11":
287 | resolution:
288 | { integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== }
289 |
290 | "@tsconfig/node12@1.0.11":
291 | resolution:
292 | { integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== }
293 |
294 | "@tsconfig/node14@1.0.3":
295 | resolution:
296 | { integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== }
297 |
298 | "@tsconfig/node16@1.0.4":
299 | resolution:
300 | { integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== }
301 |
302 | "@types/fs-extra@11.0.4":
303 | resolution:
304 | { integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ== }
305 |
306 | "@types/jsonfile@6.1.4":
307 | resolution:
308 | { integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ== }
309 |
310 | "@types/node@18.19.103":
311 | resolution:
312 | { integrity: sha512-hHTHp+sEz6SxFsp+SA+Tqrua3AbmlAw+Y//aEwdHrdZkYVRWdvWD3y5uPZ0flYOkgskaFWqZ/YGFm3FaFQ0pRw== }
313 |
314 | acorn-walk@8.3.4:
315 | resolution:
316 | { integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== }
317 | engines: { node: ">=0.4.0" }
318 |
319 | acorn@8.14.1:
320 | resolution:
321 | { integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== }
322 | engines: { node: ">=0.4.0" }
323 | hasBin: true
324 |
325 | aes-js@3.0.0:
326 | resolution:
327 | { integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== }
328 |
329 | ajv@6.12.6:
330 | resolution:
331 | { integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== }
332 |
333 | ajv@8.17.1:
334 | resolution:
335 | { integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== }
336 |
337 | ansi-escapes@5.0.0:
338 | resolution:
339 | { integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA== }
340 | engines: { node: ">=12" }
341 |
342 | ansi-regex@5.0.1:
343 | resolution:
344 | { integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== }
345 | engines: { node: ">=8" }
346 |
347 | ansi-regex@6.1.0:
348 | resolution:
349 | { integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== }
350 | engines: { node: ">=12" }
351 |
352 | ansi-styles@4.3.0:
353 | resolution:
354 | { integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== }
355 | engines: { node: ">=8" }
356 |
357 | ansi-styles@6.2.1:
358 | resolution:
359 | { integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== }
360 | engines: { node: ">=12" }
361 |
362 | antlr4@4.13.2:
363 | resolution:
364 | { integrity: sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg== }
365 | engines: { node: ">=16" }
366 |
367 | antlr4ts@0.5.0-alpha.4:
368 | resolution:
369 | { integrity: sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== }
370 |
371 | arg@4.1.3:
372 | resolution:
373 | { integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== }
374 |
375 | argparse@2.0.1:
376 | resolution:
377 | { integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== }
378 |
379 | assertion-error@1.1.0:
380 | resolution:
381 | { integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== }
382 |
383 | ast-parents@0.0.1:
384 | resolution:
385 | { integrity: sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== }
386 |
387 | astral-regex@2.0.0:
388 | resolution:
389 | { integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== }
390 | engines: { node: ">=8" }
391 |
392 | balanced-match@1.0.2:
393 | resolution:
394 | { integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== }
395 |
396 | bech32@1.1.4:
397 | resolution:
398 | { integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== }
399 |
400 | bn.js@4.12.2:
401 | resolution:
402 | { integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== }
403 |
404 | bn.js@5.2.2:
405 | resolution:
406 | { integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== }
407 |
408 | brace-expansion@2.0.1:
409 | resolution:
410 | { integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== }
411 |
412 | braces@3.0.3:
413 | resolution:
414 | { integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== }
415 | engines: { node: ">=8" }
416 |
417 | brorand@1.1.0:
418 | resolution:
419 | { integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== }
420 |
421 | bufio@1.2.3:
422 | resolution:
423 | { integrity: sha512-5Tt66bRzYUSlVZatc0E92uDenreJ+DpTBmSAUwL4VSxJn3e6cUyYwx+PoqML0GRZatgA/VX8ybhxItF8InZgqA== }
424 | engines: { node: ">=8.0.0" }
425 |
426 | callsites@3.1.0:
427 | resolution:
428 | { integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== }
429 | engines: { node: ">=6" }
430 |
431 | camel-case@4.1.2:
432 | resolution:
433 | { integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== }
434 |
435 | capital-case@1.0.4:
436 | resolution:
437 | { integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== }
438 |
439 | chai@4.5.0:
440 | resolution:
441 | { integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== }
442 | engines: { node: ">=4" }
443 |
444 | chalk@4.1.2:
445 | resolution:
446 | { integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== }
447 | engines: { node: ">=10" }
448 |
449 | chalk@5.3.0:
450 | resolution:
451 | { integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== }
452 | engines: { node: ^12.17.0 || ^14.13 || >=16.0.0 }
453 |
454 | change-case@4.1.2:
455 | resolution:
456 | { integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== }
457 |
458 | check-error@1.0.3:
459 | resolution:
460 | { integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== }
461 |
462 | cli-cursor@4.0.0:
463 | resolution:
464 | { integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg== }
465 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
466 |
467 | cli-truncate@3.1.0:
468 | resolution:
469 | { integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== }
470 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
471 |
472 | color-convert@2.0.1:
473 | resolution:
474 | { integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== }
475 | engines: { node: ">=7.0.0" }
476 |
477 | color-name@1.1.4:
478 | resolution:
479 | { integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== }
480 |
481 | colorette@2.0.20:
482 | resolution:
483 | { integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== }
484 |
485 | command-exists@1.2.9:
486 | resolution:
487 | { integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== }
488 |
489 | commander@10.0.1:
490 | resolution:
491 | { integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== }
492 | engines: { node: ">=14" }
493 |
494 | commander@11.0.0:
495 | resolution:
496 | { integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== }
497 | engines: { node: ">=16" }
498 |
499 | commander@8.3.0:
500 | resolution:
501 | { integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== }
502 | engines: { node: ">= 12" }
503 |
504 | constant-case@3.0.4:
505 | resolution:
506 | { integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== }
507 |
508 | cosmiconfig@8.3.6:
509 | resolution:
510 | { integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== }
511 | engines: { node: ">=14" }
512 | peerDependencies:
513 | typescript: ">=4.9.5"
514 | peerDependenciesMeta:
515 | typescript:
516 | optional: true
517 |
518 | create-require@1.1.1:
519 | resolution:
520 | { integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== }
521 |
522 | cross-spawn@7.0.6:
523 | resolution:
524 | { integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== }
525 | engines: { node: ">= 8" }
526 |
527 | date-fns@2.30.0:
528 | resolution:
529 | { integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== }
530 | engines: { node: ">=0.11" }
531 |
532 | debug@4.3.4:
533 | resolution:
534 | { integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== }
535 | engines: { node: ">=6.0" }
536 | peerDependencies:
537 | supports-color: "*"
538 | peerDependenciesMeta:
539 | supports-color:
540 | optional: true
541 |
542 | deep-eql@4.1.4:
543 | resolution:
544 | { integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== }
545 | engines: { node: ">=6" }
546 |
547 | diff@4.0.2:
548 | resolution:
549 | { integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== }
550 | engines: { node: ">=0.3.1" }
551 |
552 | dot-case@3.0.4:
553 | resolution:
554 | { integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== }
555 |
556 | ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0:
557 | resolution: { tarball: https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0 }
558 | version: 1.0.0
559 |
560 | eastasianwidth@0.2.0:
561 | resolution:
562 | { integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== }
563 |
564 | elliptic@6.6.1:
565 | resolution:
566 | { integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== }
567 |
568 | emoji-regex@8.0.0:
569 | resolution:
570 | { integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== }
571 |
572 | emoji-regex@9.2.2:
573 | resolution:
574 | { integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== }
575 |
576 | error-ex@1.3.2:
577 | resolution:
578 | { integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== }
579 |
580 | ethers@5.8.0:
581 | resolution:
582 | { integrity: sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg== }
583 |
584 | eventemitter3@5.0.1:
585 | resolution:
586 | { integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== }
587 |
588 | execa@7.2.0:
589 | resolution:
590 | { integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== }
591 | engines: { node: ^14.18.0 || ^16.14.0 || >=18.0.0 }
592 |
593 | fast-deep-equal@3.1.3:
594 | resolution:
595 | { integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== }
596 |
597 | fast-diff@1.3.0:
598 | resolution:
599 | { integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== }
600 |
601 | fast-json-stable-stringify@2.1.0:
602 | resolution:
603 | { integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== }
604 |
605 | fast-uri@3.0.6:
606 | resolution:
607 | { integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== }
608 |
609 | fill-range@7.1.1:
610 | resolution:
611 | { integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== }
612 | engines: { node: ">=8" }
613 |
614 | follow-redirects@1.15.9:
615 | resolution:
616 | { integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== }
617 | engines: { node: ">=4.0" }
618 | peerDependencies:
619 | debug: "*"
620 | peerDependenciesMeta:
621 | debug:
622 | optional: true
623 |
624 | foreground-child@3.3.1:
625 | resolution:
626 | { integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== }
627 | engines: { node: ">=14" }
628 |
629 | forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/77041d2ce690e692d6e03cc812b57d1ddaa4d505:
630 | resolution:
631 | { tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/77041d2ce690e692d6e03cc812b57d1ddaa4d505 }
632 | version: 1.9.7
633 |
634 | fs-extra@11.3.0:
635 | resolution:
636 | { integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew== }
637 | engines: { node: ">=14.14" }
638 |
639 | fs.realpath@1.0.0:
640 | resolution:
641 | { integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== }
642 |
643 | get-func-name@2.0.2:
644 | resolution:
645 | { integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== }
646 |
647 | get-stream@6.0.1:
648 | resolution:
649 | { integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== }
650 | engines: { node: ">=10" }
651 |
652 | glob@10.4.5:
653 | resolution:
654 | { integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== }
655 | hasBin: true
656 |
657 | glob@8.1.0:
658 | resolution:
659 | { integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== }
660 | engines: { node: ">=12" }
661 | deprecated: Glob versions prior to v9 are no longer supported
662 |
663 | graceful-fs@4.2.11:
664 | resolution:
665 | { integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== }
666 |
667 | has-flag@4.0.0:
668 | resolution:
669 | { integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== }
670 | engines: { node: ">=8" }
671 |
672 | hash.js@1.1.7:
673 | resolution:
674 | { integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== }
675 |
676 | header-case@2.0.4:
677 | resolution:
678 | { integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== }
679 |
680 | hmac-drbg@1.0.1:
681 | resolution:
682 | { integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== }
683 |
684 | human-signals@4.3.1:
685 | resolution:
686 | { integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== }
687 | engines: { node: ">=14.18.0" }
688 |
689 | husky@8.0.3:
690 | resolution:
691 | { integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== }
692 | engines: { node: ">=14" }
693 | hasBin: true
694 |
695 | ignore@5.3.2:
696 | resolution:
697 | { integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== }
698 | engines: { node: ">= 4" }
699 |
700 | import-fresh@3.3.1:
701 | resolution:
702 | { integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== }
703 | engines: { node: ">=6" }
704 |
705 | inflight@1.0.6:
706 | resolution:
707 | { integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== }
708 | deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
709 |
710 | inherits@2.0.4:
711 | resolution:
712 | { integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== }
713 |
714 | is-arrayish@0.2.1:
715 | resolution:
716 | { integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== }
717 |
718 | is-fullwidth-code-point@3.0.0:
719 | resolution:
720 | { integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== }
721 | engines: { node: ">=8" }
722 |
723 | is-fullwidth-code-point@4.0.0:
724 | resolution:
725 | { integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== }
726 | engines: { node: ">=12" }
727 |
728 | is-number@7.0.0:
729 | resolution:
730 | { integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== }
731 | engines: { node: ">=0.12.0" }
732 |
733 | is-stream@3.0.0:
734 | resolution:
735 | { integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== }
736 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
737 |
738 | isexe@2.0.0:
739 | resolution:
740 | { integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== }
741 |
742 | jackspeak@3.4.3:
743 | resolution:
744 | { integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== }
745 |
746 | js-sha3@0.8.0:
747 | resolution:
748 | { integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== }
749 |
750 | js-tokens@4.0.0:
751 | resolution:
752 | { integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== }
753 |
754 | js-yaml@4.1.0:
755 | resolution:
756 | { integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== }
757 | hasBin: true
758 |
759 | json-parse-even-better-errors@2.3.1:
760 | resolution:
761 | { integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== }
762 |
763 | json-schema-traverse@0.4.1:
764 | resolution:
765 | { integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== }
766 |
767 | json-schema-traverse@1.0.0:
768 | resolution:
769 | { integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== }
770 |
771 | jsonfile@6.1.0:
772 | resolution:
773 | { integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== }
774 |
775 | lilconfig@2.1.0:
776 | resolution:
777 | { integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== }
778 | engines: { node: ">=10" }
779 |
780 | lines-and-columns@1.2.4:
781 | resolution:
782 | { integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== }
783 |
784 | lint-staged@13.3.0:
785 | resolution:
786 | { integrity: sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ== }
787 | engines: { node: ^16.14.0 || >=18.0.0 }
788 | hasBin: true
789 |
790 | listr2@6.6.1:
791 | resolution:
792 | { integrity: sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg== }
793 | engines: { node: ">=16.0.0" }
794 | peerDependencies:
795 | enquirer: ">= 2.3.0 < 3"
796 | peerDependenciesMeta:
797 | enquirer:
798 | optional: true
799 |
800 | lodash.truncate@4.4.2:
801 | resolution:
802 | { integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== }
803 |
804 | lodash@4.17.21:
805 | resolution:
806 | { integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== }
807 |
808 | log-update@5.0.1:
809 | resolution:
810 | { integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw== }
811 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
812 |
813 | loupe@2.3.7:
814 | resolution:
815 | { integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== }
816 |
817 | lower-case@2.0.2:
818 | resolution:
819 | { integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== }
820 |
821 | lru-cache@10.4.3:
822 | resolution:
823 | { integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== }
824 |
825 | make-error@1.3.6:
826 | resolution:
827 | { integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== }
828 |
829 | memorystream@0.3.1:
830 | resolution:
831 | { integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== }
832 | engines: { node: ">= 0.10.0" }
833 |
834 | merge-stream@2.0.0:
835 | resolution:
836 | { integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== }
837 |
838 | micromatch@4.0.5:
839 | resolution:
840 | { integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== }
841 | engines: { node: ">=8.6" }
842 |
843 | mimic-fn@2.1.0:
844 | resolution:
845 | { integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== }
846 | engines: { node: ">=6" }
847 |
848 | mimic-fn@4.0.0:
849 | resolution:
850 | { integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== }
851 | engines: { node: ">=12" }
852 |
853 | minimalistic-assert@1.0.1:
854 | resolution:
855 | { integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== }
856 |
857 | minimalistic-crypto-utils@1.0.1:
858 | resolution:
859 | { integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== }
860 |
861 | minimatch@5.1.6:
862 | resolution:
863 | { integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== }
864 | engines: { node: ">=10" }
865 |
866 | minimatch@9.0.5:
867 | resolution:
868 | { integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== }
869 | engines: { node: ">=16 || 14 >=14.17" }
870 |
871 | minipass@7.1.2:
872 | resolution:
873 | { integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== }
874 | engines: { node: ">=16 || 14 >=14.17" }
875 |
876 | ms@2.1.2:
877 | resolution:
878 | { integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== }
879 |
880 | no-case@3.0.4:
881 | resolution:
882 | { integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== }
883 |
884 | npm-run-path@5.3.0:
885 | resolution:
886 | { integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== }
887 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
888 |
889 | once@1.4.0:
890 | resolution:
891 | { integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== }
892 |
893 | onetime@5.1.2:
894 | resolution:
895 | { integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== }
896 | engines: { node: ">=6" }
897 |
898 | onetime@6.0.0:
899 | resolution:
900 | { integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== }
901 | engines: { node: ">=12" }
902 |
903 | os-tmpdir@1.0.2:
904 | resolution:
905 | { integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== }
906 | engines: { node: ">=0.10.0" }
907 |
908 | package-json-from-dist@1.0.1:
909 | resolution:
910 | { integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== }
911 |
912 | param-case@3.0.4:
913 | resolution:
914 | { integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A== }
915 |
916 | parent-module@1.0.1:
917 | resolution:
918 | { integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== }
919 | engines: { node: ">=6" }
920 |
921 | parse-json@5.2.0:
922 | resolution:
923 | { integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== }
924 | engines: { node: ">=8" }
925 |
926 | pascal-case@3.1.2:
927 | resolution:
928 | { integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== }
929 |
930 | path-case@3.0.4:
931 | resolution:
932 | { integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== }
933 |
934 | path-key@3.1.1:
935 | resolution:
936 | { integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== }
937 | engines: { node: ">=8" }
938 |
939 | path-key@4.0.0:
940 | resolution:
941 | { integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== }
942 | engines: { node: ">=12" }
943 |
944 | path-scurry@1.11.1:
945 | resolution:
946 | { integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== }
947 | engines: { node: ">=16 || 14 >=14.18" }
948 |
949 | path-type@4.0.0:
950 | resolution:
951 | { integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== }
952 | engines: { node: ">=8" }
953 |
954 | pathval@1.1.1:
955 | resolution:
956 | { integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== }
957 |
958 | picocolors@1.1.1:
959 | resolution:
960 | { integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== }
961 |
962 | picomatch@2.3.1:
963 | resolution:
964 | { integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== }
965 | engines: { node: ">=8.6" }
966 |
967 | pidtree@0.6.0:
968 | resolution:
969 | { integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== }
970 | engines: { node: ">=0.10" }
971 | hasBin: true
972 |
973 | pluralize@8.0.0:
974 | resolution:
975 | { integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== }
976 | engines: { node: ">=4" }
977 |
978 | prettier-linter-helpers@1.0.0:
979 | resolution:
980 | { integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== }
981 | engines: { node: ">=6.0.0" }
982 |
983 | prettier-plugin-solidity@1.4.3:
984 | resolution:
985 | { integrity: sha512-Mrr/iiR9f9IaeGRMZY2ApumXcn/C5Gs3S7B7hWB3gigBFML06C0yEyW86oLp0eqiA0qg+46FaChgLPJCj/pIlg== }
986 | engines: { node: ">=18" }
987 | peerDependencies:
988 | prettier: ">=2.3.0"
989 |
990 | prettier@2.8.8:
991 | resolution:
992 | { integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== }
993 | engines: { node: ">=10.13.0" }
994 | hasBin: true
995 |
996 | prettier@3.5.3:
997 | resolution:
998 | { integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== }
999 | engines: { node: ">=14" }
1000 | hasBin: true
1001 |
1002 | punycode@2.3.1:
1003 | resolution:
1004 | { integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== }
1005 | engines: { node: ">=6" }
1006 |
1007 | require-from-string@2.0.2:
1008 | resolution:
1009 | { integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== }
1010 | engines: { node: ">=0.10.0" }
1011 |
1012 | resolve-from@4.0.0:
1013 | resolution:
1014 | { integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== }
1015 | engines: { node: ">=4" }
1016 |
1017 | restore-cursor@4.0.0:
1018 | resolution:
1019 | { integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg== }
1020 | engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 }
1021 |
1022 | rfdc@1.4.1:
1023 | resolution:
1024 | { integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== }
1025 |
1026 | scrypt-js@3.0.1:
1027 | resolution:
1028 | { integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== }
1029 |
1030 | semver@5.7.2:
1031 | resolution:
1032 | { integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== }
1033 | hasBin: true
1034 |
1035 | semver@7.7.2:
1036 | resolution:
1037 | { integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== }
1038 | engines: { node: ">=10" }
1039 | hasBin: true
1040 |
1041 | sentence-case@3.0.4:
1042 | resolution:
1043 | { integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== }
1044 |
1045 | shebang-command@2.0.0:
1046 | resolution:
1047 | { integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== }
1048 | engines: { node: ">=8" }
1049 |
1050 | shebang-regex@3.0.0:
1051 | resolution:
1052 | { integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== }
1053 | engines: { node: ">=8" }
1054 |
1055 | signal-exit@3.0.7:
1056 | resolution:
1057 | { integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== }
1058 |
1059 | signal-exit@4.1.0:
1060 | resolution:
1061 | { integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== }
1062 | engines: { node: ">=14" }
1063 |
1064 | slice-ansi@4.0.0:
1065 | resolution:
1066 | { integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== }
1067 | engines: { node: ">=10" }
1068 |
1069 | slice-ansi@5.0.0:
1070 | resolution:
1071 | { integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== }
1072 | engines: { node: ">=12" }
1073 |
1074 | snake-case@3.0.4:
1075 | resolution:
1076 | { integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== }
1077 |
1078 | solc@0.8.30:
1079 | resolution:
1080 | { integrity: sha512-9Srk/gndtBmoUbg4CE6ypAzPQlElv8ntbnl6SigUBAzgXKn35v87sj04uZeoZWjtDkdzT0qKFcIo/wl63UMxdw== }
1081 | engines: { node: ">=12.0.0" }
1082 | hasBin: true
1083 |
1084 | solhint-plugin-prettier@0.1.0:
1085 | resolution:
1086 | { integrity: sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw== }
1087 | peerDependencies:
1088 | prettier: ^3.0.0
1089 | prettier-plugin-solidity: ^1.0.0
1090 |
1091 | solhint@3.6.2:
1092 | resolution:
1093 | { integrity: sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ== }
1094 | hasBin: true
1095 |
1096 | solidity-bytes-utils@0.8.4:
1097 | resolution:
1098 | { integrity: sha512-/bjac5YR12i0plOKvGlhE51F5IWGP6rI8DJetCQlXcnwKWz/Hgf/vr+Qlk1BWz56xVcwVhmhCaDkTMnx5xvt0g== }
1099 |
1100 | string-argv@0.3.2:
1101 | resolution:
1102 | { integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== }
1103 | engines: { node: ">=0.6.19" }
1104 |
1105 | string-width@4.2.3:
1106 | resolution:
1107 | { integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== }
1108 | engines: { node: ">=8" }
1109 |
1110 | string-width@5.1.2:
1111 | resolution:
1112 | { integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== }
1113 | engines: { node: ">=12" }
1114 |
1115 | strip-ansi@6.0.1:
1116 | resolution:
1117 | { integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== }
1118 | engines: { node: ">=8" }
1119 |
1120 | strip-ansi@7.1.0:
1121 | resolution:
1122 | { integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== }
1123 | engines: { node: ">=12" }
1124 |
1125 | strip-final-newline@3.0.0:
1126 | resolution:
1127 | { integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== }
1128 | engines: { node: ">=12" }
1129 |
1130 | supports-color@7.2.0:
1131 | resolution:
1132 | { integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== }
1133 | engines: { node: ">=8" }
1134 |
1135 | table@6.9.0:
1136 | resolution:
1137 | { integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A== }
1138 | engines: { node: ">=10.0.0" }
1139 |
1140 | text-table@0.2.0:
1141 | resolution:
1142 | { integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== }
1143 |
1144 | tmp@0.0.33:
1145 | resolution:
1146 | { integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== }
1147 | engines: { node: ">=0.6.0" }
1148 |
1149 | to-regex-range@5.0.1:
1150 | resolution:
1151 | { integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== }
1152 | engines: { node: ">=8.0" }
1153 |
1154 | toml@3.0.0:
1155 | resolution:
1156 | { integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== }
1157 |
1158 | ts-node@10.9.2:
1159 | resolution:
1160 | { integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== }
1161 | hasBin: true
1162 | peerDependencies:
1163 | "@swc/core": ">=1.2.50"
1164 | "@swc/wasm": ">=1.2.50"
1165 | "@types/node": "*"
1166 | typescript: ">=2.7"
1167 | peerDependenciesMeta:
1168 | "@swc/core":
1169 | optional: true
1170 | "@swc/wasm":
1171 | optional: true
1172 |
1173 | tslib@2.8.1:
1174 | resolution:
1175 | { integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== }
1176 |
1177 | type-detect@4.1.0:
1178 | resolution:
1179 | { integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== }
1180 | engines: { node: ">=4" }
1181 |
1182 | type-fest@1.4.0:
1183 | resolution:
1184 | { integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== }
1185 | engines: { node: ">=10" }
1186 |
1187 | typescript@5.8.3:
1188 | resolution:
1189 | { integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== }
1190 | engines: { node: ">=14.17" }
1191 | hasBin: true
1192 |
1193 | undici-types@5.26.5:
1194 | resolution:
1195 | { integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== }
1196 |
1197 | universalify@2.0.1:
1198 | resolution:
1199 | { integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== }
1200 | engines: { node: ">= 10.0.0" }
1201 |
1202 | upper-case-first@2.0.2:
1203 | resolution:
1204 | { integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== }
1205 |
1206 | upper-case@2.0.2:
1207 | resolution:
1208 | { integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== }
1209 |
1210 | uri-js@4.4.1:
1211 | resolution:
1212 | { integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== }
1213 |
1214 | v8-compile-cache-lib@3.0.1:
1215 | resolution:
1216 | { integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== }
1217 |
1218 | which@2.0.2:
1219 | resolution:
1220 | { integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== }
1221 | engines: { node: ">= 8" }
1222 | hasBin: true
1223 |
1224 | wrap-ansi@7.0.0:
1225 | resolution:
1226 | { integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== }
1227 | engines: { node: ">=10" }
1228 |
1229 | wrap-ansi@8.1.0:
1230 | resolution:
1231 | { integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== }
1232 | engines: { node: ">=12" }
1233 |
1234 | wrappy@1.0.2:
1235 | resolution:
1236 | { integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== }
1237 |
1238 | ws@8.18.0:
1239 | resolution:
1240 | { integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== }
1241 | engines: { node: ">=10.0.0" }
1242 | peerDependencies:
1243 | bufferutil: ^4.0.1
1244 | utf-8-validate: ">=5.0.2"
1245 | peerDependenciesMeta:
1246 | bufferutil:
1247 | optional: true
1248 | utf-8-validate:
1249 | optional: true
1250 |
1251 | yaml@2.3.1:
1252 | resolution:
1253 | { integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== }
1254 | engines: { node: ">= 14" }
1255 |
1256 | yn@3.1.1:
1257 | resolution:
1258 | { integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== }
1259 | engines: { node: ">=6" }
1260 |
1261 | snapshots:
1262 | "@babel/code-frame@7.27.1":
1263 | dependencies:
1264 | "@babel/helper-validator-identifier": 7.27.1
1265 | js-tokens: 4.0.0
1266 | picocolors: 1.1.1
1267 |
1268 | "@babel/helper-validator-identifier@7.27.1": {}
1269 |
1270 | "@babel/runtime@7.27.1": {}
1271 |
1272 | "@chainlink/contracts@0.6.1(ethers@5.8.0)":
1273 | dependencies:
1274 | "@eth-optimism/contracts": 0.5.40(ethers@5.8.0)
1275 | "@openzeppelin/contracts": 4.3.3
1276 | "@openzeppelin/contracts-upgradeable": 4.9.6
1277 | "@openzeppelin/contracts-v0.7": "@openzeppelin/contracts@3.4.2"
1278 | transitivePeerDependencies:
1279 | - bufferutil
1280 | - ethers
1281 | - utf-8-validate
1282 |
1283 | "@cspotcode/source-map-support@0.8.1":
1284 | dependencies:
1285 | "@jridgewell/trace-mapping": 0.3.9
1286 |
1287 | "@eth-optimism/contracts@0.5.40(ethers@5.8.0)":
1288 | dependencies:
1289 | "@eth-optimism/core-utils": 0.12.0
1290 | "@ethersproject/abstract-provider": 5.8.0
1291 | "@ethersproject/abstract-signer": 5.8.0
1292 | ethers: 5.8.0
1293 | transitivePeerDependencies:
1294 | - bufferutil
1295 | - utf-8-validate
1296 |
1297 | "@eth-optimism/core-utils@0.12.0":
1298 | dependencies:
1299 | "@ethersproject/abi": 5.8.0
1300 | "@ethersproject/abstract-provider": 5.8.0
1301 | "@ethersproject/address": 5.8.0
1302 | "@ethersproject/bignumber": 5.8.0
1303 | "@ethersproject/bytes": 5.8.0
1304 | "@ethersproject/constants": 5.8.0
1305 | "@ethersproject/contracts": 5.8.0
1306 | "@ethersproject/hash": 5.8.0
1307 | "@ethersproject/keccak256": 5.8.0
1308 | "@ethersproject/properties": 5.8.0
1309 | "@ethersproject/providers": 5.8.0
1310 | "@ethersproject/rlp": 5.8.0
1311 | "@ethersproject/transactions": 5.8.0
1312 | "@ethersproject/web": 5.8.0
1313 | bufio: 1.2.3
1314 | chai: 4.5.0
1315 | transitivePeerDependencies:
1316 | - bufferutil
1317 | - utf-8-validate
1318 |
1319 | "@ethersproject/abi@5.8.0":
1320 | dependencies:
1321 | "@ethersproject/address": 5.8.0
1322 | "@ethersproject/bignumber": 5.8.0
1323 | "@ethersproject/bytes": 5.8.0
1324 | "@ethersproject/constants": 5.8.0
1325 | "@ethersproject/hash": 5.8.0
1326 | "@ethersproject/keccak256": 5.8.0
1327 | "@ethersproject/logger": 5.8.0
1328 | "@ethersproject/properties": 5.8.0
1329 | "@ethersproject/strings": 5.8.0
1330 |
1331 | "@ethersproject/abstract-provider@5.8.0":
1332 | dependencies:
1333 | "@ethersproject/bignumber": 5.8.0
1334 | "@ethersproject/bytes": 5.8.0
1335 | "@ethersproject/logger": 5.8.0
1336 | "@ethersproject/networks": 5.8.0
1337 | "@ethersproject/properties": 5.8.0
1338 | "@ethersproject/transactions": 5.8.0
1339 | "@ethersproject/web": 5.8.0
1340 |
1341 | "@ethersproject/abstract-signer@5.8.0":
1342 | dependencies:
1343 | "@ethersproject/abstract-provider": 5.8.0
1344 | "@ethersproject/bignumber": 5.8.0
1345 | "@ethersproject/bytes": 5.8.0
1346 | "@ethersproject/logger": 5.8.0
1347 | "@ethersproject/properties": 5.8.0
1348 |
1349 | "@ethersproject/address@5.8.0":
1350 | dependencies:
1351 | "@ethersproject/bignumber": 5.8.0
1352 | "@ethersproject/bytes": 5.8.0
1353 | "@ethersproject/keccak256": 5.8.0
1354 | "@ethersproject/logger": 5.8.0
1355 | "@ethersproject/rlp": 5.8.0
1356 |
1357 | "@ethersproject/base64@5.8.0":
1358 | dependencies:
1359 | "@ethersproject/bytes": 5.8.0
1360 |
1361 | "@ethersproject/basex@5.8.0":
1362 | dependencies:
1363 | "@ethersproject/bytes": 5.8.0
1364 | "@ethersproject/properties": 5.8.0
1365 |
1366 | "@ethersproject/bignumber@5.8.0":
1367 | dependencies:
1368 | "@ethersproject/bytes": 5.8.0
1369 | "@ethersproject/logger": 5.8.0
1370 | bn.js: 5.2.2
1371 |
1372 | "@ethersproject/bytes@5.8.0":
1373 | dependencies:
1374 | "@ethersproject/logger": 5.8.0
1375 |
1376 | "@ethersproject/constants@5.8.0":
1377 | dependencies:
1378 | "@ethersproject/bignumber": 5.8.0
1379 |
1380 | "@ethersproject/contracts@5.8.0":
1381 | dependencies:
1382 | "@ethersproject/abi": 5.8.0
1383 | "@ethersproject/abstract-provider": 5.8.0
1384 | "@ethersproject/abstract-signer": 5.8.0
1385 | "@ethersproject/address": 5.8.0
1386 | "@ethersproject/bignumber": 5.8.0
1387 | "@ethersproject/bytes": 5.8.0
1388 | "@ethersproject/constants": 5.8.0
1389 | "@ethersproject/logger": 5.8.0
1390 | "@ethersproject/properties": 5.8.0
1391 | "@ethersproject/transactions": 5.8.0
1392 |
1393 | "@ethersproject/hash@5.8.0":
1394 | dependencies:
1395 | "@ethersproject/abstract-signer": 5.8.0
1396 | "@ethersproject/address": 5.8.0
1397 | "@ethersproject/base64": 5.8.0
1398 | "@ethersproject/bignumber": 5.8.0
1399 | "@ethersproject/bytes": 5.8.0
1400 | "@ethersproject/keccak256": 5.8.0
1401 | "@ethersproject/logger": 5.8.0
1402 | "@ethersproject/properties": 5.8.0
1403 | "@ethersproject/strings": 5.8.0
1404 |
1405 | "@ethersproject/hdnode@5.8.0":
1406 | dependencies:
1407 | "@ethersproject/abstract-signer": 5.8.0
1408 | "@ethersproject/basex": 5.8.0
1409 | "@ethersproject/bignumber": 5.8.0
1410 | "@ethersproject/bytes": 5.8.0
1411 | "@ethersproject/logger": 5.8.0
1412 | "@ethersproject/pbkdf2": 5.8.0
1413 | "@ethersproject/properties": 5.8.0
1414 | "@ethersproject/sha2": 5.8.0
1415 | "@ethersproject/signing-key": 5.8.0
1416 | "@ethersproject/strings": 5.8.0
1417 | "@ethersproject/transactions": 5.8.0
1418 | "@ethersproject/wordlists": 5.8.0
1419 |
1420 | "@ethersproject/json-wallets@5.8.0":
1421 | dependencies:
1422 | "@ethersproject/abstract-signer": 5.8.0
1423 | "@ethersproject/address": 5.8.0
1424 | "@ethersproject/bytes": 5.8.0
1425 | "@ethersproject/hdnode": 5.8.0
1426 | "@ethersproject/keccak256": 5.8.0
1427 | "@ethersproject/logger": 5.8.0
1428 | "@ethersproject/pbkdf2": 5.8.0
1429 | "@ethersproject/properties": 5.8.0
1430 | "@ethersproject/random": 5.8.0
1431 | "@ethersproject/strings": 5.8.0
1432 | "@ethersproject/transactions": 5.8.0
1433 | aes-js: 3.0.0
1434 | scrypt-js: 3.0.1
1435 |
1436 | "@ethersproject/keccak256@5.8.0":
1437 | dependencies:
1438 | "@ethersproject/bytes": 5.8.0
1439 | js-sha3: 0.8.0
1440 |
1441 | "@ethersproject/logger@5.8.0": {}
1442 |
1443 | "@ethersproject/networks@5.8.0":
1444 | dependencies:
1445 | "@ethersproject/logger": 5.8.0
1446 |
1447 | "@ethersproject/pbkdf2@5.8.0":
1448 | dependencies:
1449 | "@ethersproject/bytes": 5.8.0
1450 | "@ethersproject/sha2": 5.8.0
1451 |
1452 | "@ethersproject/properties@5.8.0":
1453 | dependencies:
1454 | "@ethersproject/logger": 5.8.0
1455 |
1456 | "@ethersproject/providers@5.8.0":
1457 | dependencies:
1458 | "@ethersproject/abstract-provider": 5.8.0
1459 | "@ethersproject/abstract-signer": 5.8.0
1460 | "@ethersproject/address": 5.8.0
1461 | "@ethersproject/base64": 5.8.0
1462 | "@ethersproject/basex": 5.8.0
1463 | "@ethersproject/bignumber": 5.8.0
1464 | "@ethersproject/bytes": 5.8.0
1465 | "@ethersproject/constants": 5.8.0
1466 | "@ethersproject/hash": 5.8.0
1467 | "@ethersproject/logger": 5.8.0
1468 | "@ethersproject/networks": 5.8.0
1469 | "@ethersproject/properties": 5.8.0
1470 | "@ethersproject/random": 5.8.0
1471 | "@ethersproject/rlp": 5.8.0
1472 | "@ethersproject/sha2": 5.8.0
1473 | "@ethersproject/strings": 5.8.0
1474 | "@ethersproject/transactions": 5.8.0
1475 | "@ethersproject/web": 5.8.0
1476 | bech32: 1.1.4
1477 | ws: 8.18.0
1478 | transitivePeerDependencies:
1479 | - bufferutil
1480 | - utf-8-validate
1481 |
1482 | "@ethersproject/random@5.8.0":
1483 | dependencies:
1484 | "@ethersproject/bytes": 5.8.0
1485 | "@ethersproject/logger": 5.8.0
1486 |
1487 | "@ethersproject/rlp@5.8.0":
1488 | dependencies:
1489 | "@ethersproject/bytes": 5.8.0
1490 | "@ethersproject/logger": 5.8.0
1491 |
1492 | "@ethersproject/sha2@5.8.0":
1493 | dependencies:
1494 | "@ethersproject/bytes": 5.8.0
1495 | "@ethersproject/logger": 5.8.0
1496 | hash.js: 1.1.7
1497 |
1498 | "@ethersproject/signing-key@5.8.0":
1499 | dependencies:
1500 | "@ethersproject/bytes": 5.8.0
1501 | "@ethersproject/logger": 5.8.0
1502 | "@ethersproject/properties": 5.8.0
1503 | bn.js: 5.2.2
1504 | elliptic: 6.6.1
1505 | hash.js: 1.1.7
1506 |
1507 | "@ethersproject/solidity@5.8.0":
1508 | dependencies:
1509 | "@ethersproject/bignumber": 5.8.0
1510 | "@ethersproject/bytes": 5.8.0
1511 | "@ethersproject/keccak256": 5.8.0
1512 | "@ethersproject/logger": 5.8.0
1513 | "@ethersproject/sha2": 5.8.0
1514 | "@ethersproject/strings": 5.8.0
1515 |
1516 | "@ethersproject/strings@5.8.0":
1517 | dependencies:
1518 | "@ethersproject/bytes": 5.8.0
1519 | "@ethersproject/constants": 5.8.0
1520 | "@ethersproject/logger": 5.8.0
1521 |
1522 | "@ethersproject/transactions@5.8.0":
1523 | dependencies:
1524 | "@ethersproject/address": 5.8.0
1525 | "@ethersproject/bignumber": 5.8.0
1526 | "@ethersproject/bytes": 5.8.0
1527 | "@ethersproject/constants": 5.8.0
1528 | "@ethersproject/keccak256": 5.8.0
1529 | "@ethersproject/logger": 5.8.0
1530 | "@ethersproject/properties": 5.8.0
1531 | "@ethersproject/rlp": 5.8.0
1532 | "@ethersproject/signing-key": 5.8.0
1533 |
1534 | "@ethersproject/units@5.8.0":
1535 | dependencies:
1536 | "@ethersproject/bignumber": 5.8.0
1537 | "@ethersproject/constants": 5.8.0
1538 | "@ethersproject/logger": 5.8.0
1539 |
1540 | "@ethersproject/wallet@5.8.0":
1541 | dependencies:
1542 | "@ethersproject/abstract-provider": 5.8.0
1543 | "@ethersproject/abstract-signer": 5.8.0
1544 | "@ethersproject/address": 5.8.0
1545 | "@ethersproject/bignumber": 5.8.0
1546 | "@ethersproject/bytes": 5.8.0
1547 | "@ethersproject/hash": 5.8.0
1548 | "@ethersproject/hdnode": 5.8.0
1549 | "@ethersproject/json-wallets": 5.8.0
1550 | "@ethersproject/keccak256": 5.8.0
1551 | "@ethersproject/logger": 5.8.0
1552 | "@ethersproject/properties": 5.8.0
1553 | "@ethersproject/random": 5.8.0
1554 | "@ethersproject/signing-key": 5.8.0
1555 | "@ethersproject/transactions": 5.8.0
1556 | "@ethersproject/wordlists": 5.8.0
1557 |
1558 | "@ethersproject/web@5.8.0":
1559 | dependencies:
1560 | "@ethersproject/base64": 5.8.0
1561 | "@ethersproject/bytes": 5.8.0
1562 | "@ethersproject/logger": 5.8.0
1563 | "@ethersproject/properties": 5.8.0
1564 | "@ethersproject/strings": 5.8.0
1565 |
1566 | "@ethersproject/wordlists@5.8.0":
1567 | dependencies:
1568 | "@ethersproject/bytes": 5.8.0
1569 | "@ethersproject/hash": 5.8.0
1570 | "@ethersproject/logger": 5.8.0
1571 | "@ethersproject/properties": 5.8.0
1572 | "@ethersproject/strings": 5.8.0
1573 |
1574 | "@isaacs/cliui@8.0.2":
1575 | dependencies:
1576 | string-width: 5.1.2
1577 | string-width-cjs: string-width@4.2.3
1578 | strip-ansi: 7.1.0
1579 | strip-ansi-cjs: strip-ansi@6.0.1
1580 | wrap-ansi: 8.1.0
1581 | wrap-ansi-cjs: wrap-ansi@7.0.0
1582 |
1583 | "@jridgewell/resolve-uri@3.1.2": {}
1584 |
1585 | "@jridgewell/sourcemap-codec@1.5.0": {}
1586 |
1587 | "@jridgewell/trace-mapping@0.3.9":
1588 | dependencies:
1589 | "@jridgewell/resolve-uri": 3.1.2
1590 | "@jridgewell/sourcemap-codec": 1.5.0
1591 |
1592 | "@openzeppelin/contracts-upgradeable@4.9.6": {}
1593 |
1594 | "@openzeppelin/contracts@3.4.2": {}
1595 |
1596 | "@openzeppelin/contracts@4.3.3": {}
1597 |
1598 | "@openzeppelin/contracts@5.3.0": {}
1599 |
1600 | "@pkgjs/parseargs@0.11.0":
1601 | optional: true
1602 |
1603 | "@prettier/sync@0.3.0(prettier@3.5.3)":
1604 | dependencies:
1605 | prettier: 3.5.3
1606 |
1607 | "@solidity-parser/parser@0.16.2":
1608 | dependencies:
1609 | antlr4ts: 0.5.0-alpha.4
1610 |
1611 | "@solidity-parser/parser@0.20.1": {}
1612 |
1613 | "@tsconfig/node10@1.0.11": {}
1614 |
1615 | "@tsconfig/node12@1.0.11": {}
1616 |
1617 | "@tsconfig/node14@1.0.3": {}
1618 |
1619 | "@tsconfig/node16@1.0.4": {}
1620 |
1621 | "@types/fs-extra@11.0.4":
1622 | dependencies:
1623 | "@types/jsonfile": 6.1.4
1624 | "@types/node": 18.19.103
1625 |
1626 | "@types/jsonfile@6.1.4":
1627 | dependencies:
1628 | "@types/node": 18.19.103
1629 |
1630 | "@types/node@18.19.103":
1631 | dependencies:
1632 | undici-types: 5.26.5
1633 |
1634 | acorn-walk@8.3.4:
1635 | dependencies:
1636 | acorn: 8.14.1
1637 |
1638 | acorn@8.14.1: {}
1639 |
1640 | aes-js@3.0.0: {}
1641 |
1642 | ajv@6.12.6:
1643 | dependencies:
1644 | fast-deep-equal: 3.1.3
1645 | fast-json-stable-stringify: 2.1.0
1646 | json-schema-traverse: 0.4.1
1647 | uri-js: 4.4.1
1648 |
1649 | ajv@8.17.1:
1650 | dependencies:
1651 | fast-deep-equal: 3.1.3
1652 | fast-uri: 3.0.6
1653 | json-schema-traverse: 1.0.0
1654 | require-from-string: 2.0.2
1655 |
1656 | ansi-escapes@5.0.0:
1657 | dependencies:
1658 | type-fest: 1.4.0
1659 |
1660 | ansi-regex@5.0.1: {}
1661 |
1662 | ansi-regex@6.1.0: {}
1663 |
1664 | ansi-styles@4.3.0:
1665 | dependencies:
1666 | color-convert: 2.0.1
1667 |
1668 | ansi-styles@6.2.1: {}
1669 |
1670 | antlr4@4.13.2: {}
1671 |
1672 | antlr4ts@0.5.0-alpha.4: {}
1673 |
1674 | arg@4.1.3: {}
1675 |
1676 | argparse@2.0.1: {}
1677 |
1678 | assertion-error@1.1.0: {}
1679 |
1680 | ast-parents@0.0.1: {}
1681 |
1682 | astral-regex@2.0.0: {}
1683 |
1684 | balanced-match@1.0.2: {}
1685 |
1686 | bech32@1.1.4: {}
1687 |
1688 | bn.js@4.12.2: {}
1689 |
1690 | bn.js@5.2.2: {}
1691 |
1692 | brace-expansion@2.0.1:
1693 | dependencies:
1694 | balanced-match: 1.0.2
1695 |
1696 | braces@3.0.3:
1697 | dependencies:
1698 | fill-range: 7.1.1
1699 |
1700 | brorand@1.1.0: {}
1701 |
1702 | bufio@1.2.3: {}
1703 |
1704 | callsites@3.1.0: {}
1705 |
1706 | camel-case@4.1.2:
1707 | dependencies:
1708 | pascal-case: 3.1.2
1709 | tslib: 2.8.1
1710 |
1711 | capital-case@1.0.4:
1712 | dependencies:
1713 | no-case: 3.0.4
1714 | tslib: 2.8.1
1715 | upper-case-first: 2.0.2
1716 |
1717 | chai@4.5.0:
1718 | dependencies:
1719 | assertion-error: 1.1.0
1720 | check-error: 1.0.3
1721 | deep-eql: 4.1.4
1722 | get-func-name: 2.0.2
1723 | loupe: 2.3.7
1724 | pathval: 1.1.1
1725 | type-detect: 4.1.0
1726 |
1727 | chalk@4.1.2:
1728 | dependencies:
1729 | ansi-styles: 4.3.0
1730 | supports-color: 7.2.0
1731 |
1732 | chalk@5.3.0: {}
1733 |
1734 | change-case@4.1.2:
1735 | dependencies:
1736 | camel-case: 4.1.2
1737 | capital-case: 1.0.4
1738 | constant-case: 3.0.4
1739 | dot-case: 3.0.4
1740 | header-case: 2.0.4
1741 | no-case: 3.0.4
1742 | param-case: 3.0.4
1743 | pascal-case: 3.1.2
1744 | path-case: 3.0.4
1745 | sentence-case: 3.0.4
1746 | snake-case: 3.0.4
1747 | tslib: 2.8.1
1748 |
1749 | check-error@1.0.3:
1750 | dependencies:
1751 | get-func-name: 2.0.2
1752 |
1753 | cli-cursor@4.0.0:
1754 | dependencies:
1755 | restore-cursor: 4.0.0
1756 |
1757 | cli-truncate@3.1.0:
1758 | dependencies:
1759 | slice-ansi: 5.0.0
1760 | string-width: 5.1.2
1761 |
1762 | color-convert@2.0.1:
1763 | dependencies:
1764 | color-name: 1.1.4
1765 |
1766 | color-name@1.1.4: {}
1767 |
1768 | colorette@2.0.20: {}
1769 |
1770 | command-exists@1.2.9: {}
1771 |
1772 | commander@10.0.1: {}
1773 |
1774 | commander@11.0.0: {}
1775 |
1776 | commander@8.3.0: {}
1777 |
1778 | constant-case@3.0.4:
1779 | dependencies:
1780 | no-case: 3.0.4
1781 | tslib: 2.8.1
1782 | upper-case: 2.0.2
1783 |
1784 | cosmiconfig@8.3.6(typescript@5.8.3):
1785 | dependencies:
1786 | import-fresh: 3.3.1
1787 | js-yaml: 4.1.0
1788 | parse-json: 5.2.0
1789 | path-type: 4.0.0
1790 | optionalDependencies:
1791 | typescript: 5.8.3
1792 |
1793 | create-require@1.1.1: {}
1794 |
1795 | cross-spawn@7.0.6:
1796 | dependencies:
1797 | path-key: 3.1.1
1798 | shebang-command: 2.0.0
1799 | which: 2.0.2
1800 |
1801 | date-fns@2.30.0:
1802 | dependencies:
1803 | "@babel/runtime": 7.27.1
1804 |
1805 | debug@4.3.4:
1806 | dependencies:
1807 | ms: 2.1.2
1808 |
1809 | deep-eql@4.1.4:
1810 | dependencies:
1811 | type-detect: 4.1.0
1812 |
1813 | diff@4.0.2: {}
1814 |
1815 | dot-case@3.0.4:
1816 | dependencies:
1817 | no-case: 3.0.4
1818 | tslib: 2.8.1
1819 |
1820 | ds-test@https://codeload.github.com/dapphub/ds-test/tar.gz/e282159d5170298eb2455a6c05280ab5a73a4ef0: {}
1821 |
1822 | eastasianwidth@0.2.0: {}
1823 |
1824 | elliptic@6.6.1:
1825 | dependencies:
1826 | bn.js: 4.12.2
1827 | brorand: 1.1.0
1828 | hash.js: 1.1.7
1829 | hmac-drbg: 1.0.1
1830 | inherits: 2.0.4
1831 | minimalistic-assert: 1.0.1
1832 | minimalistic-crypto-utils: 1.0.1
1833 |
1834 | emoji-regex@8.0.0: {}
1835 |
1836 | emoji-regex@9.2.2: {}
1837 |
1838 | error-ex@1.3.2:
1839 | dependencies:
1840 | is-arrayish: 0.2.1
1841 |
1842 | ethers@5.8.0:
1843 | dependencies:
1844 | "@ethersproject/abi": 5.8.0
1845 | "@ethersproject/abstract-provider": 5.8.0
1846 | "@ethersproject/abstract-signer": 5.8.0
1847 | "@ethersproject/address": 5.8.0
1848 | "@ethersproject/base64": 5.8.0
1849 | "@ethersproject/basex": 5.8.0
1850 | "@ethersproject/bignumber": 5.8.0
1851 | "@ethersproject/bytes": 5.8.0
1852 | "@ethersproject/constants": 5.8.0
1853 | "@ethersproject/contracts": 5.8.0
1854 | "@ethersproject/hash": 5.8.0
1855 | "@ethersproject/hdnode": 5.8.0
1856 | "@ethersproject/json-wallets": 5.8.0
1857 | "@ethersproject/keccak256": 5.8.0
1858 | "@ethersproject/logger": 5.8.0
1859 | "@ethersproject/networks": 5.8.0
1860 | "@ethersproject/pbkdf2": 5.8.0
1861 | "@ethersproject/properties": 5.8.0
1862 | "@ethersproject/providers": 5.8.0
1863 | "@ethersproject/random": 5.8.0
1864 | "@ethersproject/rlp": 5.8.0
1865 | "@ethersproject/sha2": 5.8.0
1866 | "@ethersproject/signing-key": 5.8.0
1867 | "@ethersproject/solidity": 5.8.0
1868 | "@ethersproject/strings": 5.8.0
1869 | "@ethersproject/transactions": 5.8.0
1870 | "@ethersproject/units": 5.8.0
1871 | "@ethersproject/wallet": 5.8.0
1872 | "@ethersproject/web": 5.8.0
1873 | "@ethersproject/wordlists": 5.8.0
1874 | transitivePeerDependencies:
1875 | - bufferutil
1876 | - utf-8-validate
1877 |
1878 | eventemitter3@5.0.1: {}
1879 |
1880 | execa@7.2.0:
1881 | dependencies:
1882 | cross-spawn: 7.0.6
1883 | get-stream: 6.0.1
1884 | human-signals: 4.3.1
1885 | is-stream: 3.0.0
1886 | merge-stream: 2.0.0
1887 | npm-run-path: 5.3.0
1888 | onetime: 6.0.0
1889 | signal-exit: 3.0.7
1890 | strip-final-newline: 3.0.0
1891 |
1892 | fast-deep-equal@3.1.3: {}
1893 |
1894 | fast-diff@1.3.0: {}
1895 |
1896 | fast-json-stable-stringify@2.1.0: {}
1897 |
1898 | fast-uri@3.0.6: {}
1899 |
1900 | fill-range@7.1.1:
1901 | dependencies:
1902 | to-regex-range: 5.0.1
1903 |
1904 | follow-redirects@1.15.9: {}
1905 |
1906 | foreground-child@3.3.1:
1907 | dependencies:
1908 | cross-spawn: 7.0.6
1909 | signal-exit: 4.1.0
1910 |
1911 | forge-std@https://codeload.github.com/foundry-rs/forge-std/tar.gz/77041d2ce690e692d6e03cc812b57d1ddaa4d505: {}
1912 |
1913 | fs-extra@11.3.0:
1914 | dependencies:
1915 | graceful-fs: 4.2.11
1916 | jsonfile: 6.1.0
1917 | universalify: 2.0.1
1918 |
1919 | fs.realpath@1.0.0: {}
1920 |
1921 | get-func-name@2.0.2: {}
1922 |
1923 | get-stream@6.0.1: {}
1924 |
1925 | glob@10.4.5:
1926 | dependencies:
1927 | foreground-child: 3.3.1
1928 | jackspeak: 3.4.3
1929 | minimatch: 9.0.5
1930 | minipass: 7.1.2
1931 | package-json-from-dist: 1.0.1
1932 | path-scurry: 1.11.1
1933 |
1934 | glob@8.1.0:
1935 | dependencies:
1936 | fs.realpath: 1.0.0
1937 | inflight: 1.0.6
1938 | inherits: 2.0.4
1939 | minimatch: 5.1.6
1940 | once: 1.4.0
1941 |
1942 | graceful-fs@4.2.11: {}
1943 |
1944 | has-flag@4.0.0: {}
1945 |
1946 | hash.js@1.1.7:
1947 | dependencies:
1948 | inherits: 2.0.4
1949 | minimalistic-assert: 1.0.1
1950 |
1951 | header-case@2.0.4:
1952 | dependencies:
1953 | capital-case: 1.0.4
1954 | tslib: 2.8.1
1955 |
1956 | hmac-drbg@1.0.1:
1957 | dependencies:
1958 | hash.js: 1.1.7
1959 | minimalistic-assert: 1.0.1
1960 | minimalistic-crypto-utils: 1.0.1
1961 |
1962 | human-signals@4.3.1: {}
1963 |
1964 | husky@8.0.3: {}
1965 |
1966 | ignore@5.3.2: {}
1967 |
1968 | import-fresh@3.3.1:
1969 | dependencies:
1970 | parent-module: 1.0.1
1971 | resolve-from: 4.0.0
1972 |
1973 | inflight@1.0.6:
1974 | dependencies:
1975 | once: 1.4.0
1976 | wrappy: 1.0.2
1977 |
1978 | inherits@2.0.4: {}
1979 |
1980 | is-arrayish@0.2.1: {}
1981 |
1982 | is-fullwidth-code-point@3.0.0: {}
1983 |
1984 | is-fullwidth-code-point@4.0.0: {}
1985 |
1986 | is-number@7.0.0: {}
1987 |
1988 | is-stream@3.0.0: {}
1989 |
1990 | isexe@2.0.0: {}
1991 |
1992 | jackspeak@3.4.3:
1993 | dependencies:
1994 | "@isaacs/cliui": 8.0.2
1995 | optionalDependencies:
1996 | "@pkgjs/parseargs": 0.11.0
1997 |
1998 | js-sha3@0.8.0: {}
1999 |
2000 | js-tokens@4.0.0: {}
2001 |
2002 | js-yaml@4.1.0:
2003 | dependencies:
2004 | argparse: 2.0.1
2005 |
2006 | json-parse-even-better-errors@2.3.1: {}
2007 |
2008 | json-schema-traverse@0.4.1: {}
2009 |
2010 | json-schema-traverse@1.0.0: {}
2011 |
2012 | jsonfile@6.1.0:
2013 | dependencies:
2014 | universalify: 2.0.1
2015 | optionalDependencies:
2016 | graceful-fs: 4.2.11
2017 |
2018 | lilconfig@2.1.0: {}
2019 |
2020 | lines-and-columns@1.2.4: {}
2021 |
2022 | lint-staged@13.3.0:
2023 | dependencies:
2024 | chalk: 5.3.0
2025 | commander: 11.0.0
2026 | debug: 4.3.4
2027 | execa: 7.2.0
2028 | lilconfig: 2.1.0
2029 | listr2: 6.6.1
2030 | micromatch: 4.0.5
2031 | pidtree: 0.6.0
2032 | string-argv: 0.3.2
2033 | yaml: 2.3.1
2034 | transitivePeerDependencies:
2035 | - enquirer
2036 | - supports-color
2037 |
2038 | listr2@6.6.1:
2039 | dependencies:
2040 | cli-truncate: 3.1.0
2041 | colorette: 2.0.20
2042 | eventemitter3: 5.0.1
2043 | log-update: 5.0.1
2044 | rfdc: 1.4.1
2045 | wrap-ansi: 8.1.0
2046 |
2047 | lodash.truncate@4.4.2: {}
2048 |
2049 | lodash@4.17.21: {}
2050 |
2051 | log-update@5.0.1:
2052 | dependencies:
2053 | ansi-escapes: 5.0.0
2054 | cli-cursor: 4.0.0
2055 | slice-ansi: 5.0.0
2056 | strip-ansi: 7.1.0
2057 | wrap-ansi: 8.1.0
2058 |
2059 | loupe@2.3.7:
2060 | dependencies:
2061 | get-func-name: 2.0.2
2062 |
2063 | lower-case@2.0.2:
2064 | dependencies:
2065 | tslib: 2.8.1
2066 |
2067 | lru-cache@10.4.3: {}
2068 |
2069 | make-error@1.3.6: {}
2070 |
2071 | memorystream@0.3.1: {}
2072 |
2073 | merge-stream@2.0.0: {}
2074 |
2075 | micromatch@4.0.5:
2076 | dependencies:
2077 | braces: 3.0.3
2078 | picomatch: 2.3.1
2079 |
2080 | mimic-fn@2.1.0: {}
2081 |
2082 | mimic-fn@4.0.0: {}
2083 |
2084 | minimalistic-assert@1.0.1: {}
2085 |
2086 | minimalistic-crypto-utils@1.0.1: {}
2087 |
2088 | minimatch@5.1.6:
2089 | dependencies:
2090 | brace-expansion: 2.0.1
2091 |
2092 | minimatch@9.0.5:
2093 | dependencies:
2094 | brace-expansion: 2.0.1
2095 |
2096 | minipass@7.1.2: {}
2097 |
2098 | ms@2.1.2: {}
2099 |
2100 | no-case@3.0.4:
2101 | dependencies:
2102 | lower-case: 2.0.2
2103 | tslib: 2.8.1
2104 |
2105 | npm-run-path@5.3.0:
2106 | dependencies:
2107 | path-key: 4.0.0
2108 |
2109 | once@1.4.0:
2110 | dependencies:
2111 | wrappy: 1.0.2
2112 |
2113 | onetime@5.1.2:
2114 | dependencies:
2115 | mimic-fn: 2.1.0
2116 |
2117 | onetime@6.0.0:
2118 | dependencies:
2119 | mimic-fn: 4.0.0
2120 |
2121 | os-tmpdir@1.0.2: {}
2122 |
2123 | package-json-from-dist@1.0.1: {}
2124 |
2125 | param-case@3.0.4:
2126 | dependencies:
2127 | dot-case: 3.0.4
2128 | tslib: 2.8.1
2129 |
2130 | parent-module@1.0.1:
2131 | dependencies:
2132 | callsites: 3.1.0
2133 |
2134 | parse-json@5.2.0:
2135 | dependencies:
2136 | "@babel/code-frame": 7.27.1
2137 | error-ex: 1.3.2
2138 | json-parse-even-better-errors: 2.3.1
2139 | lines-and-columns: 1.2.4
2140 |
2141 | pascal-case@3.1.2:
2142 | dependencies:
2143 | no-case: 3.0.4
2144 | tslib: 2.8.1
2145 |
2146 | path-case@3.0.4:
2147 | dependencies:
2148 | dot-case: 3.0.4
2149 | tslib: 2.8.1
2150 |
2151 | path-key@3.1.1: {}
2152 |
2153 | path-key@4.0.0: {}
2154 |
2155 | path-scurry@1.11.1:
2156 | dependencies:
2157 | lru-cache: 10.4.3
2158 | minipass: 7.1.2
2159 |
2160 | path-type@4.0.0: {}
2161 |
2162 | pathval@1.1.1: {}
2163 |
2164 | picocolors@1.1.1: {}
2165 |
2166 | picomatch@2.3.1: {}
2167 |
2168 | pidtree@0.6.0: {}
2169 |
2170 | pluralize@8.0.0: {}
2171 |
2172 | prettier-linter-helpers@1.0.0:
2173 | dependencies:
2174 | fast-diff: 1.3.0
2175 |
2176 | prettier-plugin-solidity@1.4.3(prettier@3.5.3):
2177 | dependencies:
2178 | "@solidity-parser/parser": 0.20.1
2179 | prettier: 3.5.3
2180 | semver: 7.7.2
2181 |
2182 | prettier@2.8.8:
2183 | optional: true
2184 |
2185 | prettier@3.5.3: {}
2186 |
2187 | punycode@2.3.1: {}
2188 |
2189 | require-from-string@2.0.2: {}
2190 |
2191 | resolve-from@4.0.0: {}
2192 |
2193 | restore-cursor@4.0.0:
2194 | dependencies:
2195 | onetime: 5.1.2
2196 | signal-exit: 3.0.7
2197 |
2198 | rfdc@1.4.1: {}
2199 |
2200 | scrypt-js@3.0.1: {}
2201 |
2202 | semver@5.7.2: {}
2203 |
2204 | semver@7.7.2: {}
2205 |
2206 | sentence-case@3.0.4:
2207 | dependencies:
2208 | no-case: 3.0.4
2209 | tslib: 2.8.1
2210 | upper-case-first: 2.0.2
2211 |
2212 | shebang-command@2.0.0:
2213 | dependencies:
2214 | shebang-regex: 3.0.0
2215 |
2216 | shebang-regex@3.0.0: {}
2217 |
2218 | signal-exit@3.0.7: {}
2219 |
2220 | signal-exit@4.1.0: {}
2221 |
2222 | slice-ansi@4.0.0:
2223 | dependencies:
2224 | ansi-styles: 4.3.0
2225 | astral-regex: 2.0.0
2226 | is-fullwidth-code-point: 3.0.0
2227 |
2228 | slice-ansi@5.0.0:
2229 | dependencies:
2230 | ansi-styles: 6.2.1
2231 | is-fullwidth-code-point: 4.0.0
2232 |
2233 | snake-case@3.0.4:
2234 | dependencies:
2235 | dot-case: 3.0.4
2236 | tslib: 2.8.1
2237 |
2238 | solc@0.8.30:
2239 | dependencies:
2240 | command-exists: 1.2.9
2241 | commander: 8.3.0
2242 | follow-redirects: 1.15.9
2243 | js-sha3: 0.8.0
2244 | memorystream: 0.3.1
2245 | semver: 5.7.2
2246 | tmp: 0.0.33
2247 | transitivePeerDependencies:
2248 | - debug
2249 |
2250 | solhint-plugin-prettier@0.1.0(prettier-plugin-solidity@1.4.3(prettier@3.5.3))(prettier@3.5.3):
2251 | dependencies:
2252 | "@prettier/sync": 0.3.0(prettier@3.5.3)
2253 | prettier: 3.5.3
2254 | prettier-linter-helpers: 1.0.0
2255 | prettier-plugin-solidity: 1.4.3(prettier@3.5.3)
2256 |
2257 | solhint@3.6.2(typescript@5.8.3):
2258 | dependencies:
2259 | "@solidity-parser/parser": 0.16.2
2260 | ajv: 6.12.6
2261 | antlr4: 4.13.2
2262 | ast-parents: 0.0.1
2263 | chalk: 4.1.2
2264 | commander: 10.0.1
2265 | cosmiconfig: 8.3.6(typescript@5.8.3)
2266 | fast-diff: 1.3.0
2267 | glob: 8.1.0
2268 | ignore: 5.3.2
2269 | js-yaml: 4.1.0
2270 | lodash: 4.17.21
2271 | pluralize: 8.0.0
2272 | semver: 7.7.2
2273 | strip-ansi: 6.0.1
2274 | table: 6.9.0
2275 | text-table: 0.2.0
2276 | optionalDependencies:
2277 | prettier: 2.8.8
2278 | transitivePeerDependencies:
2279 | - typescript
2280 |
2281 | solidity-bytes-utils@0.8.4: {}
2282 |
2283 | string-argv@0.3.2: {}
2284 |
2285 | string-width@4.2.3:
2286 | dependencies:
2287 | emoji-regex: 8.0.0
2288 | is-fullwidth-code-point: 3.0.0
2289 | strip-ansi: 6.0.1
2290 |
2291 | string-width@5.1.2:
2292 | dependencies:
2293 | eastasianwidth: 0.2.0
2294 | emoji-regex: 9.2.2
2295 | strip-ansi: 7.1.0
2296 |
2297 | strip-ansi@6.0.1:
2298 | dependencies:
2299 | ansi-regex: 5.0.1
2300 |
2301 | strip-ansi@7.1.0:
2302 | dependencies:
2303 | ansi-regex: 6.1.0
2304 |
2305 | strip-final-newline@3.0.0: {}
2306 |
2307 | supports-color@7.2.0:
2308 | dependencies:
2309 | has-flag: 4.0.0
2310 |
2311 | table@6.9.0:
2312 | dependencies:
2313 | ajv: 8.17.1
2314 | lodash.truncate: 4.4.2
2315 | slice-ansi: 4.0.0
2316 | string-width: 4.2.3
2317 | strip-ansi: 6.0.1
2318 |
2319 | text-table@0.2.0: {}
2320 |
2321 | tmp@0.0.33:
2322 | dependencies:
2323 | os-tmpdir: 1.0.2
2324 |
2325 | to-regex-range@5.0.1:
2326 | dependencies:
2327 | is-number: 7.0.0
2328 |
2329 | toml@3.0.0: {}
2330 |
2331 | ts-node@10.9.2(@types/node@18.19.103)(typescript@5.8.3):
2332 | dependencies:
2333 | "@cspotcode/source-map-support": 0.8.1
2334 | "@tsconfig/node10": 1.0.11
2335 | "@tsconfig/node12": 1.0.11
2336 | "@tsconfig/node14": 1.0.3
2337 | "@tsconfig/node16": 1.0.4
2338 | "@types/node": 18.19.103
2339 | acorn: 8.14.1
2340 | acorn-walk: 8.3.4
2341 | arg: 4.1.3
2342 | create-require: 1.1.1
2343 | diff: 4.0.2
2344 | make-error: 1.3.6
2345 | typescript: 5.8.3
2346 | v8-compile-cache-lib: 3.0.1
2347 | yn: 3.1.1
2348 |
2349 | tslib@2.8.1: {}
2350 |
2351 | type-detect@4.1.0: {}
2352 |
2353 | type-fest@1.4.0: {}
2354 |
2355 | typescript@5.8.3: {}
2356 |
2357 | undici-types@5.26.5: {}
2358 |
2359 | universalify@2.0.1: {}
2360 |
2361 | upper-case-first@2.0.2:
2362 | dependencies:
2363 | tslib: 2.8.1
2364 |
2365 | upper-case@2.0.2:
2366 | dependencies:
2367 | tslib: 2.8.1
2368 |
2369 | uri-js@4.4.1:
2370 | dependencies:
2371 | punycode: 2.3.1
2372 |
2373 | v8-compile-cache-lib@3.0.1: {}
2374 |
2375 | which@2.0.2:
2376 | dependencies:
2377 | isexe: 2.0.0
2378 |
2379 | wrap-ansi@7.0.0:
2380 | dependencies:
2381 | ansi-styles: 4.3.0
2382 | string-width: 4.2.3
2383 | strip-ansi: 6.0.1
2384 |
2385 | wrap-ansi@8.1.0:
2386 | dependencies:
2387 | ansi-styles: 6.2.1
2388 | string-width: 5.1.2
2389 | strip-ansi: 7.1.0
2390 |
2391 | wrappy@1.0.2: {}
2392 |
2393 | ws@8.18.0: {}
2394 |
2395 | yaml@2.3.1: {}
2396 |
2397 | yn@3.1.1: {}
2398 |
--------------------------------------------------------------------------------
/remappings.txt:
--------------------------------------------------------------------------------
1 | forge-std/=node_modules/forge-std/src/
2 | solidity-bytes-utils/=node_modules/solidity-bytes-utils/
3 | @openzeppelin/=node_modules/@openzeppelin/
4 | @chainlink/=node_modules/@chainlink/
5 | ds-test/=node_modules/ds-test/src/
--------------------------------------------------------------------------------
/script/cli/README.md:
--------------------------------------------------------------------------------
1 | # Installation
2 | ```
3 | npm i
4 | npm run build
5 | npm link
6 | ```
--------------------------------------------------------------------------------
/script/cli/build-helper/library.ts:
--------------------------------------------------------------------------------
1 | import { camelCase } from "change-case";
2 | import { AbiItem, Struct, Input } from "../types";
3 |
4 | const makeStruct = (func: AbiItem): Struct => {
5 | return {
6 | name: firstToUppercase(func.name) + "Return",
7 | items: func.outputs.map((output, index) => {
8 | return {
9 | name: getOutputName(output, index),
10 | type: getOutputType(output).replace(" memory", ""),
11 | };
12 | }),
13 | };
14 | };
15 |
16 | const getOutputType = (output: Input) => {
17 | const isDynamic = output.internalType.match(/(struct|^bytes$|\[\])/);
18 | if (isDynamic) {
19 | const words = output.internalType.split(" ");
20 | return words[words.length - 1] + " memory";
21 | } else {
22 | return output.internalType;
23 | }
24 | };
25 |
26 | const getOutputName = (output: Input, index) => {
27 | const cleanedName = output.name.replace(/^_/, "");
28 | const name = cleanedName ? cleanedName : "returnVal" + index;
29 | return name;
30 | };
31 |
32 | const getInputName = (input: Input, index) => {
33 | const cleanedName = input.name.replace(/^_/, "");
34 | const name = cleanedName ? cleanedName : "_arg" + index;
35 | return name;
36 | };
37 |
38 | const firstToUppercase = (str: string) => {
39 | return str.charAt(0).toUpperCase() + str.slice(1);
40 | };
41 |
42 | export const buildHelperAction = async (abi, name, options) => {
43 | const NAME = name;
44 | const INAME = options?.i ?? null;
45 | const RETURN_NAME = "_return";
46 | process.stdout.write(await buildHelper(abi, NAME, INAME, RETURN_NAME));
47 | };
48 |
49 | export const buildHelper = async (abi, NAME, INAME, RETURN_NAME) => {
50 | const funcs = (abi as AbiItem[]).filter((item) => item.type === "function" && item?.outputs?.length > 1);
51 |
52 | const items = funcs.map((func) => {
53 | const struct = makeStruct(func);
54 | const structString = `
55 | struct ${struct.name} {
56 | ${struct.items.map((item) => ` ${item.type} ${item.name};`).join("\n ")}
57 | }`;
58 | const funcOut = {
59 | name: func.name,
60 | args: func.inputs.map((input) => {
61 | return {
62 | name: input.name,
63 | type: input.internalType,
64 | };
65 | }),
66 | };
67 | const argTypeStrings = funcOut.args.map((arg, index) => arg.type + " " + (arg.name ? arg.name : "arg" + index));
68 | const argStrings = funcOut.args.map((arg, index) => (arg.name ? arg.name : "arg" + index));
69 | const name = `_${camelCase(NAME)}`;
70 | const nameType = `${NAME}`;
71 | const nameWithType = `${nameType} ${name}`;
72 | const functionArgs = `${[nameWithType, ...argTypeStrings].join(", ")}`;
73 | const iFunctionArgs = `${[nameWithType, ...argTypeStrings].join(", ")}`.replace(NAME, INAME);
74 | const structItemsString = `${struct.items.map((item) => RETURN_NAME + "." + item.name).join(", ")}`;
75 | const funcString = `
76 | function __${func.name}( ${functionArgs} ) internal ${func.stateMutability} returns (${
77 | struct.name
78 | } memory ${RETURN_NAME}) {
79 | ( ${structItemsString} ) = ${name}.${func.name}(${argStrings.join(", ")});
80 | }`;
81 |
82 | const interfaceString = `
83 | function __${func.name}(${iFunctionArgs}) internal ${func.stateMutability} returns (${
84 | struct.name
85 | } memory ${RETURN_NAME}) {
86 | ${nameWithType} = ${NAME}(address(${name}));
87 | return __${func.name}(${[name, ...argStrings].filter(Boolean).join(", ")});
88 | }`;
89 |
90 | return [structString, funcString, interfaceString];
91 | });
92 |
93 | const outputString = `
94 | // SPDX-License-Identifier: ISC
95 | pragma solidity ^0.8.19;
96 |
97 | import "src/${NAME}.sol";
98 |
99 | library ${NAME}StructHelper {
100 | ${items.map((item) => item[0] + "\n" + item[1] + "\n" + (INAME ? item[2] : "")).join("\n ")}
101 | }`;
102 | return outputString;
103 | };
104 |
--------------------------------------------------------------------------------
/script/cli/build-hoax-helper/library.ts:
--------------------------------------------------------------------------------
1 | import { camelCase } from "change-case";
2 | import { AbiItem, Struct, Input } from "../types";
3 | import {
4 | isDynamicType,
5 | getFileContractNames,
6 | getOutDirectory,
7 | getAbiFromFile,
8 | getHelperDirectory,
9 | newGetAbi,
10 | } from "../utils";
11 | import fs from "fs";
12 | import path from "path";
13 |
14 | export const hoaxAction = (paths, watch = false) => {
15 | console.log("file: library.ts:15 ~ hoaxAction ~ watch:", watch);
16 | if (watch) {
17 | console.log("file: library.ts:15 ~ hoaxAction ~ paths:", paths);
18 | paths.forEach((path) => {
19 | let timeout;
20 | const watcher = fs.watch(path, (eventType, filename) => {
21 | if (filename && eventType === "change") {
22 | if (timeout) {
23 | clearTimeout(timeout);
24 | }
25 |
26 | timeout = setTimeout(() => {
27 | // Your function to be run after a delay and file changes.
28 | processOnePath(path).catch((err) => {});
29 | }, 1500);
30 | }
31 | });
32 | });
33 | } else {
34 | paths.forEach(processOnePath);
35 | }
36 | };
37 |
38 | const processOnePath = async (filePath) => {
39 | const abis = (await newGetAbi(filePath)) as { [key: string]: { abi: AbiItem } };
40 |
41 | const abiWithContractName = Object.entries(abis).map(([contractName, { abi }]) => {
42 | return {
43 | contractName,
44 | abi,
45 | };
46 | });
47 |
48 | abiWithContractName.forEach(async (item) => {
49 | const hoaxFile = await buildHoaxHelper(item.abi, item.contractName, filePath);
50 | const helperDirectory = getHelperDirectory();
51 | fs.writeFileSync(path.join(helperDirectory, `${item.contractName}HoaxHelper.sol`), hoaxFile);
52 | });
53 | };
54 |
55 | export const buildHoaxHelperAction = async (abi, name) => {
56 | const NAME = name;
57 | process.stdout.write(await buildHoaxHelper(abi, NAME));
58 | };
59 |
60 | const formatType = (internalType, contractName) => {
61 | if (isDynamicType(internalType)) {
62 | if (internalType.includes("struct")) {
63 | return internalType.replace("struct ", contractName + ".") + " memory";
64 | } else if (internalType.includes("contract")) {
65 | return internalType.replace("contract ", "");
66 | } else return internalType + " memory";
67 | } else {
68 | return internalType;
69 | }
70 | };
71 |
72 | export const buildHoaxHelper = async (abi, NAME, filePath = null) => {
73 | const funcs = (abi as AbiItem[]).filter((item) => item.type === "function");
74 |
75 | const items = funcs.map((func) => {
76 | const funcOut = {
77 | name: func.name,
78 | args: func.inputs.map((input) => {
79 | return {
80 | name: input.name,
81 | type: formatType(input.internalType, NAME),
82 | };
83 | }),
84 | returns: func.outputs.map((output) => {
85 | return {
86 | name: output.name,
87 | type: formatType(output.internalType, NAME),
88 | };
89 | }),
90 | };
91 | const argTypeStrings = funcOut.args.map((arg, index) => arg.type + " " + (arg.name ? arg.name : "arg" + index));
92 | const returnTypeStrings = funcOut.returns.map(
93 | (output, index) => output.type + " " + (output.name ? output.name : "return" + index)
94 | );
95 | const argStrings = funcOut.args.map((arg, index) => (arg.name ? arg.name : "arg" + index));
96 | const returnStrings = funcOut.returns.map((arg, index) => (arg.name ? arg.name : "return" + index));
97 | const name = `_${camelCase(NAME)}`;
98 | const nameType = `${NAME}`;
99 | const nameWithType = `${nameType} ${name}`;
100 | const functionArgs = `${[nameWithType, ...argTypeStrings].join(", ")}`;
101 | const cleanedStateMutability = func.stateMutability
102 | .replace("payable", "")
103 | .replace("view", "")
104 | .replace("non", "")
105 | .replace("pure", "");
106 | const isPayable = func.stateMutability.includes("payable") && !func.stateMutability.includes("nonpayable");
107 | const returnsFuncDef = `${returnTypeStrings.length ? "returns (" + returnTypeStrings + ")" : ""}`;
108 | const returnArgsAssign = `${returnTypeStrings.length ? "(" + returnStrings + ") = " : ""}`;
109 |
110 | const funcString = `
111 | function __${func.name}_As( ${[
112 | nameWithType,
113 | "address _impersonator",
114 | isPayable ? "uint256 _value" : null,
115 | ...argTypeStrings,
116 | ]
117 | .filter(Boolean)
118 | .join(", ")} ) internal ${cleanedStateMutability} ${returnsFuncDef} {
119 | vm.startPrank(_impersonator);
120 | ${returnArgsAssign} ${name}.${func.name}${isPayable ? "{ value: _value}" : ""}(${argStrings});
121 | vm.stopPrank();
122 | }`;
123 |
124 | return [funcString];
125 | });
126 |
127 | const outputString = `
128 | // SPDX-License-Identifier: ISC
129 | pragma solidity ^0.8.19;
130 |
131 | // **NOTE** This file is auto-generated do not edit it directly.
132 | // Run \`frax hoax\` to re-generate it.
133 |
134 |
135 | import { Vm } from "forge-std/Test.sol";
136 | import ${filePath ? '"' + filePath + '"' : '"src/contracts/' + NAME + '.sol"'};
137 |
138 | library ${NAME}HoaxHelper {
139 |
140 | address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
141 | Vm internal constant vm = Vm(VM_ADDRESS);
142 |
143 | ${items.map((item) => item[0]).join("\n ")}
144 | }`;
145 | return outputString;
146 | };
147 |
--------------------------------------------------------------------------------
/script/cli/findBestOptimizerRuns.ts:
--------------------------------------------------------------------------------
1 | import { execSync } from "child_process";
2 |
3 | // NOTE: Work In Progress
4 |
5 | const args = process.argv.slice(2);
6 |
7 | const COMMAND = `forge build --skip test --sizes --contracts src/src`;
8 | function binarySearch(min: number, max: number, target: number): number | null {
9 | let left = min;
10 | let right = max;
11 | const runs = [{}] as { left?: number; right?: number; mid?: number; margin?: number; greaterThan?: number }[];
12 |
13 | while (left <= right) {
14 | const mid = Math.floor((left * right) ** 0.5);
15 | const margin = getContractSize(mid);
16 | const lastLower = runs.find((item) => item?.greaterThan === -1);
17 | const lastUpper = runs.find((item) => item?.greaterThan === -1);
18 |
19 | if (margin === target || mid + 1 === right || lastLower?.margin === lastUpper?.margin) {
20 | return mid;
21 | } else if (margin > target) {
22 | runs.push({ left, right, mid, margin, greaterThan: 1 });
23 | console.log(`setting left to ${mid + 1}...`);
24 | left = mid + 1;
25 | } else {
26 | console.log(`setting right to ${mid - 1}...`);
27 | runs.push({ left, right, mid, margin, greaterThan: -1 });
28 | right = mid - 1;
29 | }
30 | }
31 |
32 | return null;
33 | }
34 |
35 | function getContractSize(index: number): number {
36 | console.log(`Building with ${index} optimizer runs...`);
37 | const command = COMMAND + ` --optimizer-runs ${index} | grep FraxlendPair`;
38 | console.log("command:", command);
39 | const output = execSync(command).toString() as string;
40 | console.log("getContractSize ~ output:", output);
41 | const fraxlendPairLine = output.match(/FraxlendPair .*\n/)?.[0];
42 | console.log("fraxlendPairLine:", fraxlendPairLine);
43 | const marginString = fraxlendPairLine.split("|")[2].trim();
44 | console.log("marginString:", marginString);
45 | const margin = Number(marginString);
46 | console.log("margin:", margin);
47 | return margin;
48 | }
49 |
50 | binarySearch(Number.parseInt(args[0]), Number.parseInt(args[1]), Number.parseInt(args[2]));
51 |
--------------------------------------------------------------------------------
/script/cli/main.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import { Command } from "commander";
4 | import { buildHelperAction } from "./build-helper/library";
5 | import { buildHoaxHelperAction, hoaxAction } from "./build-hoax-helper/library";
6 | import { toNamedImports } from "./toNamedImports";
7 | import { getAbi, newGetAbi, getFilesFromFraxToml } from "./utils";
8 |
9 | const program = new Command();
10 |
11 | program.name("frax");
12 |
13 | program
14 | .command("buildStructHelper")
15 | .argument("", "path to abi file or name of contract")
16 | .argument("", "name of Library Helper")
17 | .option("-i ", "--interface ", "name of interface")
18 | .action(async (abiPath, name, options) => {
19 | const abi = getAbi(abiPath);
20 | await buildHelperAction(abi, name, options);
21 | });
22 |
23 | program
24 | .command("buildHoaxHelper")
25 | .argument("", "path to abi file or name of contract")
26 | .argument("", "name of Library Helper")
27 | .action(async (abiPath, name, options) => {
28 | const abi = getAbi(abiPath);
29 | await buildHoaxHelperAction(abi, name);
30 | });
31 |
32 | program
33 | .command("hoax")
34 | .option("-w, --watch", "watch files")
35 | .argument("[paths...]", "paths to source files")
36 | .action(async (paths, options) => {
37 | if (paths.length > 0) {
38 | await hoaxAction(paths, options.watch);
39 | } else {
40 | const defaultPaths = getFilesFromFraxToml();
41 | await hoaxAction(defaultPaths, options.watch);
42 | }
43 | });
44 |
45 | program
46 | .command("renameImports")
47 | .argument("", "glob path to abi file")
48 | .action((paths) => {
49 | toNamedImports(paths);
50 | });
51 |
52 | program
53 | .command("abi")
54 | .argument("", "glob path to abi file")
55 | .action(async (paths) => {
56 | const abi = await newGetAbi(paths[0]);
57 | const abiString = JSON.stringify(abi, null, 2);
58 | process.stdout.write(abiString);
59 | });
60 |
61 | program.parse();
62 |
--------------------------------------------------------------------------------
/script/cli/renameTestContracts.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs/promises";
2 | import * as path from "path";
3 |
4 | async function renameSolidity(filePath) {
5 | const fileExtension = path.basename(filePath).match(/\..*/)?.[0] as string;
6 | const fileName = path.basename(filePath).replace(fileExtension, "");
7 | // console.log("file: rename.ts:6 ~ renameSolidity ~ fileName:", fileName);
8 | // console.log("file: rename.ts:8 ~ renameSolidity ~ fileExtension:", fileExtension);
9 | const fileContents = (await fs.readFile(filePath, "utf8")).toString();
10 | const replace = `contract Test${fileName.replace("Test", "")}`;
11 | const find = fileContents.match(/contract [a-zA-Z0-9_]+/)?.[0] as string;
12 | // console.log("file: rename.ts:12 ~ renameSolidity ~ replace:", replace);
13 | // console.log("file: rename.ts:12 ~ renameSolidity ~ find:", find);
14 | const newFileContents = fileContents.replace(find, replace);
15 | await fs.writeFile(filePath, newFileContents, "utf8");
16 | // console.log("file: rename.ts:12 ~ renameSolidity ~ replace:", replace);
17 | }
18 |
19 | const args = process.argv.slice(2);
20 | args.forEach(renameSolidity);
21 |
--------------------------------------------------------------------------------
/script/cli/toNamedImports.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs/promises";
2 | import * as path from "path";
3 |
4 | export async function renameFileImports(filePath) {
5 | filePath = path.resolve(filePath);
6 | if (!(await fs.lstat(filePath)).isFile()) return;
7 | const fileContents = (await fs.readFile(path.resolve(filePath), "utf8")).toString();
8 | const importStatements =
9 | (fileContents.match(/import\s+".*;/g) as string[])?.filter((item) => {
10 | return !item.includes("forge-std") && !item.includes("frax-std");
11 | }) ?? [];
12 | const entries = importStatements.map((statement) => {
13 | const matches = statement.match(/\/([a-zA-Z0-9_]+)\./g);
14 | const name = matches?.[matches.length - 1].match(/[a-zA-Z0-9_]+/)?.[0] as string;
15 | const path = statement.match(/".*?";/)?.[0] as string;
16 | const replace = `import { ${name} } from ${path}`;
17 | return { original: statement, name, path, replace };
18 | });
19 | const newFileContents = entries.reduce((acc, entry) => {
20 | return acc.replace(entry.original, entry.replace);
21 | }, fileContents);
22 | fs.writeFile(filePath, newFileContents, "utf8");
23 | }
24 |
25 | export async function toNamedImports(filePaths) {
26 | filePaths.forEach(renameFileImports);
27 | }
28 |
--------------------------------------------------------------------------------
/script/cli/types.ts:
--------------------------------------------------------------------------------
1 | export interface AbiItem {
2 | inputs: Input[];
3 | stateMutability?: StateMutability;
4 | type: ABIType;
5 | name: string;
6 | anonymous?: boolean;
7 | outputs: Input[];
8 | }
9 |
10 | export interface Input {
11 | internalType: InternalTypeEnum;
12 | name: string;
13 | type: InternalTypeEnum;
14 | indexed?: boolean;
15 | components?: Input[];
16 | }
17 |
18 | export enum InternalTypeEnum {
19 | Address = "address",
20 | Bool = "bool",
21 | Bytes = "bytes",
22 | ContractIERC20 = "contract IERC20",
23 | ContractIRateCalculatorV2 = "contract IRateCalculatorV2",
24 | String = "string",
25 | StructFraxlendPairCoreCurrentRateInfo = "struct FraxlendPairCore.CurrentRateInfo",
26 | StructVaultAccount = "struct VaultAccount",
27 | Tuple = "tuple",
28 | TypeAddress = "address[]",
29 | Uint128 = "uint128",
30 | Uint184 = "uint184",
31 | Uint256 = "uint256",
32 | Uint32 = "uint32",
33 | Uint64 = "uint64",
34 | Uint8 = "uint8",
35 | }
36 |
37 | export enum StateMutability {
38 | Nonpayable = "nonpayable",
39 | Pure = "pure",
40 | View = "view",
41 | }
42 |
43 | export enum ABIType {
44 | Constructor = "constructor",
45 | Error = "error",
46 | Event = "event",
47 | Function = "function",
48 | }
49 |
50 | export interface StructItem {
51 | name: string;
52 | type: string;
53 | }
54 |
55 | export interface Struct {
56 | name: string;
57 | items: StructItem[];
58 | }
59 |
60 | export interface Func {
61 | name: string;
62 | args: { name: string; type: string }[];
63 | }
64 |
65 | export interface OutputItem {
66 | struct: Struct;
67 | func: Func;
68 | }
69 |
--------------------------------------------------------------------------------
/script/cli/utils.ts:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import fs from "fs";
3 | import toml from "toml";
4 | import { glob } from "glob";
5 | import { execSync } from "child_process";
6 |
7 | export const getFilesFromFraxToml = () => {
8 | const fraxConfig = parseFraxToml();
9 | const files = fraxConfig.files;
10 | return files;
11 | };
12 |
13 | export const getFileContractNames = (fileContents) => {
14 | const contractNames = [];
15 | const contractRegex = /contract\s+(\w+)/g;
16 | let match = contractRegex.exec(fileContents);
17 | while (match) {
18 | contractNames.push(match[1]);
19 | match = contractRegex.exec(fileContents);
20 | }
21 | return contractNames;
22 | };
23 |
24 | export const getOutFileFromSourcePath = (sourcePath) => {
25 | const fileName = path.basename(sourcePath);
26 | const fileContents = fs.readFileSync(sourcePath).toString();
27 | const contractNames = getFileContractNames(fileContents);
28 | const outDirectory = getOutDirectory();
29 | const abiFilePaths = contractNames.map((contractName) => path.join(outDirectory, fileName, `${contractName}.json`));
30 | return abiFilePaths;
31 | };
32 |
33 | export const getAbiWithName = async (name) => {
34 | const outDirectory = getOutDirectory();
35 | const abiFilePaths = await glob(`${outDirectory}/**/${name}.json`);
36 | if (abiFilePaths.length === 0) {
37 | throw new Error(`No abi file found for ${name}`);
38 | } else if (abiFilePaths.length > 1) {
39 | throw new Error(`Multiple abi files found for ${name}`);
40 | }
41 | const abi = getAbiFromFile(abiFilePaths[0]);
42 | return abi;
43 | };
44 |
45 | export const getAbiFromFile = (abiPath) => {
46 | let abi = JSON.parse(fs.readFileSync(abiPath).toString());
47 | if (Object.keys(abi).includes("abi")) {
48 | abi = abi.abi;
49 | }
50 | return abi;
51 | };
52 |
53 | export const getAbiFromPath = (abiPath) => {
54 | const abi = getAbiFromFile(abiPath);
55 | return abi;
56 | };
57 |
58 | export const getAbi = (abiPath) => {
59 | if (!abiPath.includes("/")) {
60 | const outDirectory = getOutDirectory();
61 | abiPath = path.join(outDirectory, abiPath + ".sol", `${abiPath}.json`);
62 | } else {
63 | abiPath = path.resolve(abiPath);
64 | }
65 |
66 | let abi = JSON.parse(fs.readFileSync(abiPath).toString());
67 | if (Object.keys(abi).includes("abi")) {
68 | abi = abi.abi;
69 | }
70 | return abi;
71 | };
72 |
73 | const parseFoundryToml = () => {
74 | const foundryTomlPath = path.resolve("foundry.toml");
75 | const foundryConfigString = fs.readFileSync(foundryTomlPath, "utf-8").toString();
76 | const foundryConfig = toml.parse(foundryConfigString);
77 | return foundryConfig;
78 | };
79 |
80 | export const getOutDirectory = () => {
81 | const foundryConfig = parseFoundryToml();
82 | const outValue = foundryConfig.profile.default.out;
83 | const outDirectory = path.resolve(outValue);
84 | return outDirectory;
85 | };
86 |
87 | const parseFraxToml = () => {
88 | const fraxTomlPath = path.resolve("frax.toml");
89 | const fraxConfigString = fs.readFileSync(fraxTomlPath, "utf-8").toString();
90 | const fraxConfig = toml.parse(fraxConfigString);
91 | return fraxConfig;
92 | };
93 |
94 | export const getHelperDirectory = () => {
95 | const fraxConfig = parseFraxToml();
96 | const helperValue = fraxConfig.helper_dir;
97 | const helperDirectory = path.resolve(helperValue);
98 | return helperDirectory;
99 | };
100 |
101 | export const isDynamicType = (internalType) => {
102 | if (internalType.includes("[")) {
103 | return true;
104 | }
105 |
106 | if (internalType === "bytes") {
107 | return true;
108 | }
109 |
110 | if (internalType.includes("struct")) {
111 | return true;
112 | }
113 |
114 | if (internalType.includes("contract")) {
115 | return true;
116 | }
117 |
118 | if (internalType.includes("string")) {
119 | return true;
120 | }
121 |
122 | return false;
123 | };
124 |
125 | export const newGetAbi = async (filePath) => {
126 | const contractBasename = path.basename(filePath);
127 | const input = {
128 | language: "Solidity",
129 | sources: {
130 | [filePath]: {
131 | urls: [filePath],
132 | },
133 | },
134 | settings: {
135 | remappings: remappingsToArray(),
136 | metadata: {
137 | bytecodeHash: "none",
138 | appendCBOR: true,
139 | },
140 | outputSelection: {
141 | [filePath]: {
142 | "*": ["abi"],
143 | },
144 | },
145 | evmVersion: "london",
146 | libraries: {},
147 | },
148 | };
149 | const fileName = `${Date.now().toString()}${contractBasename}${Math.random()}.json`;
150 | fs.writeFileSync(fileName, JSON.stringify(input));
151 | const command = `solc --pretty-json ${getIncludeSources()
152 | .map((item) => "--include-path " + item)
153 | .join(" ")} --base-path . --standard-json ${fileName}`;
154 | const output = execSync(command).toString();
155 | fs.unlink(fileName, () => {});
156 | const parsed = JSON.parse(output);
157 | delete parsed.sources;
158 | return parsed.contracts[filePath];
159 | };
160 |
161 | const remappingsToArray = () => {
162 | const contents = fs.readFileSync("remappings.txt").toString();
163 | const lines = contents.split("\n").filter(Boolean);
164 | return lines;
165 | };
166 |
167 | const getIncludeSources = () => {
168 | const foundryConfig = parseFoundryToml();
169 | const includeSources = foundryConfig.profile.default.libs;
170 | return includeSources;
171 | };
172 |
173 | function importCallbackGenerator(includeSources) {
174 | return function readFileCallback(sourcePath) {
175 | const prefixes = includeSources;
176 | for (const prefix of prefixes) {
177 | const prefixedSourcePath = (prefix ? prefix + "/" : "") + sourcePath;
178 |
179 | if (fs.existsSync(prefixedSourcePath)) {
180 | try {
181 | return { contents: fs.readFileSync(prefixedSourcePath).toString("utf8") };
182 | } catch (e) {
183 | return { error: "Error reading " + prefixedSourcePath + ": " + e };
184 | }
185 | }
186 | }
187 | return { error: "File not found inside the base path or any of the include paths." };
188 | };
189 | }
190 |
--------------------------------------------------------------------------------
/script/updateEnv.ts:
--------------------------------------------------------------------------------
1 | import { format } from "date-fns";
2 | import * as fs from "fs-extra";
3 | import path from "path";
4 |
5 | const DEPLOYMENTS_PATH = path.resolve("deployments");
6 | const METADATA_PATH = path.resolve("out");
7 |
8 | const chainToNetwork = {
9 | 1: "mainnet",
10 | };
11 |
12 | const main = async () => {
13 | const args = process.argv.slice(2);
14 | const chainId = args[0];
15 | const contractName = args[1];
16 | const contractAddress = args[2];
17 | const constructorArguments = args[3];
18 |
19 | if (!fs.existsSync(DEPLOYMENTS_PATH)) fs.mkdirSync(DEPLOYMENTS_PATH);
20 |
21 | const networkName = chainToNetwork[chainId];
22 | const networkDirPath = path.resolve(DEPLOYMENTS_PATH, networkName);
23 | if (!fs.existsSync(networkDirPath)) {
24 | fs.mkdirSync(networkDirPath);
25 | const chainIdFilePath = path.resolve(networkDirPath, ".chainId");
26 | fs.writeFileSync(chainIdFilePath, chainId.toString());
27 | }
28 |
29 | const metadataPath = path.resolve(METADATA_PATH, contractName + ".sol", contractName + ".json");
30 | const metadata = JSON.parse(fs.readFileSync(metadataPath, "utf8"));
31 | const outputData = {
32 | abi: metadata.abi,
33 | bytecode: metadata.bytecode,
34 | deployedBytecode: metadata.deployedBytecode,
35 | metadata: metadata.metadata,
36 | address: contractAddress,
37 | constructorArgs: constructorArguments,
38 | };
39 | const outputString = JSON.stringify(outputData, null, 2);
40 | const latestFilePath = path.resolve(networkDirPath, contractName + ".json");
41 | void (await Promise.all([
42 | fs.promises.writeFile(latestFilePath, outputString),
43 | (() => {
44 | const newDeploymentPath = path.resolve(networkDirPath, format(Date.now(), "yyyyMMdd_HH.mm.ss"));
45 | const thisDeploymentFilePath = path.resolve(newDeploymentPath, contractName + ".json");
46 | if (!["hardhat", "localhost"].includes(networkName)) {
47 | if (!fs.existsSync(newDeploymentPath)) fs.mkdirSync(newDeploymentPath);
48 | return fs.promises.writeFile(thisDeploymentFilePath, outputString);
49 | }
50 | })(),
51 | ]));
52 | };
53 | void main();
54 |
--------------------------------------------------------------------------------
/src/AddressHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity ^0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ========================== AddressHelper ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // ====================================================================
20 |
21 | import { console2 as console } from "forge-std/Test.sol";
22 | import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
23 |
24 | library AddressHelper {
25 | using Strings for *;
26 |
27 | function toEtherscanLink(address _address) public pure returns (string memory) {
28 | return string(abi.encodePacked("https://etherscan.io/address/", _address.toHexString()));
29 | }
30 |
31 | function etherscanLink(address _address) public pure returns (string memory) {
32 | return toEtherscanLink(_address);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/ArrayHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | library ArrayHelper {
5 | function concat(address[] memory _inputArray, address _newItem) internal pure returns (address[] memory _newArray) {
6 | uint256 _inputArrayLength = _inputArray.length;
7 | _newArray = new address[](_inputArrayLength + 1);
8 | for (uint256 i = 0; i < _inputArrayLength; i++) {
9 | _newArray[i] = _inputArray[i];
10 | }
11 | _newArray[_inputArrayLength] = _newItem;
12 | }
13 |
14 | function concat(function()[] memory _inputArray, function() _newItem) internal pure returns (function()[] memory _newArray) {
15 | uint256 _inputArrayLength = _inputArray.length;
16 | _newArray = new function()[](_inputArrayLength + 1);
17 | for (uint256 i = 0; i < _inputArrayLength; i++) {
18 | _newArray[i] = _inputArray[i];
19 | }
20 | _newArray[_inputArrayLength] = _newItem;
21 | }
22 |
23 | function concat(bool[] memory _inputArray, bool _newItem) internal pure returns (bool[] memory _newArray) {
24 | uint256 _inputArrayLength = _inputArray.length;
25 | _newArray = new bool[](_inputArrayLength + 1);
26 | for (uint256 i = 0; i < _inputArrayLength; i++) {
27 | _newArray[i] = _inputArray[i];
28 | }
29 | _newArray[_inputArrayLength] = _newItem;
30 | }
31 |
32 | function concat(uint128[] memory _inputArray, uint128 _newItem) internal pure returns (uint128[] memory _newArray) {
33 | uint256 _inputArrayLength = _inputArray.length;
34 | _newArray = new uint128[](_inputArrayLength + 1);
35 | for (uint256 i = 0; i < _inputArrayLength; i++) {
36 | _newArray[i] = _inputArray[i];
37 | }
38 | _newArray[_inputArrayLength] = _newItem;
39 | }
40 |
41 | function concat(uint32[] memory _inputArray, uint32 _newItem) internal pure returns (uint32[] memory _newArray) {
42 | uint256 _inputArrayLength = _inputArray.length;
43 | _newArray = new uint32[](_inputArrayLength + 1);
44 | for (uint256 i = 0; i < _inputArrayLength; i++) {
45 | _newArray[i] = _inputArray[i];
46 | }
47 | _newArray[_inputArrayLength] = _newItem;
48 | }
49 |
50 | function concat(bytes32[] memory _inputArray, bytes32 _newItem) internal pure returns (bytes32[] memory _newArray) {
51 | uint256 _inputArrayLength = _inputArray.length;
52 | _newArray = new bytes32[](_inputArrayLength + 1);
53 | for (uint256 i = 0; i < _inputArrayLength; i++) {
54 | _newArray[i] = _inputArray[i];
55 | }
56 | _newArray[_inputArrayLength] = _newItem;
57 | }
58 |
59 | function concat(
60 | bytes[] memory _inputArray,
61 | bytes memory _newItem
62 | ) internal pure returns (bytes[] memory _newArray) {
63 | uint256 _inputArrayLength = _inputArray.length;
64 | _newArray = new bytes[](_inputArrayLength + 1);
65 | for (uint256 i = 0; i < _inputArrayLength; i++) {
66 | _newArray[i] = _inputArray[i];
67 | }
68 | _newArray[_inputArrayLength] = _newItem;
69 | }
70 |
71 | function concat(uint256[] memory _inputArray, uint256 _newItem) internal pure returns (uint256[] memory _newArray) {
72 | uint256 _inputArrayLength = _inputArray.length;
73 | _newArray = new uint256[](_inputArrayLength + 1);
74 | for (uint256 i = 0; i < _inputArrayLength; i++) {
75 | _newArray[i] = _inputArray[i];
76 | }
77 | _newArray[_inputArrayLength] = _newItem;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/BaseScript.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { Script } from "forge-std/Script.sol";
5 | import { console2 as console } from "forge-std/Test.sol";
6 | import "@openzeppelin/contracts/utils/Strings.sol";
7 |
8 | abstract contract BaseScript is Script {
9 | using Strings for *;
10 |
11 | address internal deployer;
12 | uint256 internal privateKey;
13 |
14 | function setUp() public virtual {
15 | privateKey = vm.envUint("PK");
16 | deployer = vm.rememberKey(privateKey);
17 | }
18 |
19 | modifier broadcaster() {
20 | vm.startBroadcast(deployer);
21 | _;
22 | vm.stopBroadcast();
23 | }
24 |
25 | struct DeployReturn {
26 | address _address;
27 | bytes constructorParams;
28 | string contractName;
29 | }
30 |
31 | function _updateEnv(address, bytes memory, string memory) internal pure {
32 | console.log("_updateEnv is deprecated");
33 | }
34 |
35 | function deploy(
36 | function() returns (address, bytes memory, string memory) _deployFunction
37 | ) internal broadcaster returns (address _address, bytes memory _constructorParams, string memory _contractName) {
38 | (_address, _constructorParams, _contractName) = _deployFunction();
39 | console.log("_constructorParams:");
40 | console.logBytes(_constructorParams);
41 | console.log(_contractName, "deployed to _address:", _address);
42 | _updateEnv(_address, _constructorParams, _contractName);
43 | }
44 |
45 | function deploy(
46 | function() returns (DeployReturn memory) _deployFunction
47 | ) internal broadcaster returns (DeployReturn memory _return) {
48 | _return = _deployFunction();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/BytesHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
5 |
6 | library BytesHelper {
7 | function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
8 | return BytesLib.concat(_preBytes, _postBytes);
9 | }
10 |
11 | function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
12 | return BytesLib.concatStorage(_preBytes, _postBytes);
13 | }
14 |
15 | function slice(bytes memory _bytes, uint256 _start, uint256 _end) internal pure returns (bytes memory) {
16 | return BytesLib.slice(_bytes, _start, _end - _start);
17 | }
18 |
19 | function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
20 | return BytesLib.toAddress(_bytes, _start);
21 | }
22 |
23 | function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
24 | return BytesLib.toUint256(_bytes, _start);
25 | }
26 |
27 | function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
28 | return BytesLib.toBytes32(_bytes, _start);
29 | }
30 |
31 | function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
32 | return BytesLib.equal(_preBytes, _postBytes);
33 | }
34 |
35 | function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
36 | return BytesLib.equalStorage(_preBytes, _postBytes);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/FraxTest.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { console2 as console, StdAssertions, StdChains, StdCheats, stdError, StdInvariant, stdJson, stdMath, StdStorage, stdStorage, StdUtils, Vm, StdStyle, TestBase, Test } from "forge-std/Test.sol";
5 | import { VmHelper } from "./VmHelper.sol";
6 | import { Strings } from "./StringsHelper.sol";
7 |
8 | abstract contract FraxTest is VmHelper, Test {
9 | /// @notice Differential State Storage
10 | uint256[] internal snapShotIds;
11 | uint256 currentSnapShotId;
12 | function()[] internal setupFunctions;
13 |
14 | /// @notice EIP-1967 Slots
15 | bytes32 internal IMPLEMENTATION_SLOT = bytes32(uint256(keccak256("eip1967.proxy.implementation")) - 1);
16 | bytes32 internal ADMIN_SLOT = bytes32(uint256(keccak256("eip1967.proxy.admin")) - 1);
17 |
18 | // ========================================================================
19 | // ~~~~~~~~~~~~~~~~~~ Different State Testing Helpers ~~~~~~~~~~~~~~~~~~~~~
20 | // ========================================================================
21 |
22 | modifier useMultipleSetupFunctions() {
23 | if (snapShotIds.length == 0) _;
24 | for (uint256 i = 0; i < snapShotIds.length; i++) {
25 | uint256 _originalSnapshotId = vm.snapshot();
26 | // currentSnapShotId = snapShotIds[i];
27 | if (!vm.revertTo(snapShotIds[i])) {
28 | revert VmDidNotRevert(snapShotIds[i]);
29 | }
30 | _;
31 | vm.clearMockedCalls();
32 | vm.revertTo(_originalSnapshotId);
33 | }
34 | }
35 |
36 | function addSetupFunctions(function()[] memory _setupFunctions) internal {
37 | for (uint256 i = 0; i < _setupFunctions.length; i++) {
38 | _setupFunctions[i]();
39 | snapShotIds.push(vm.snapshot());
40 | vm.clearMockedCalls();
41 | }
42 | }
43 |
44 | // ========================================================================
45 | // ~~~~~~~~~~~~~~~~~~~~~~~ EIP-1967 Proxy Helpers ~~~~~~~~~~~~~~~~~~~~~~~~~
46 | // ========================================================================
47 |
48 | /// @notice Helper function to efficiently return the address type located at the implementation
49 | /// and admin slot on an EIP-1967 Proxy
50 | /// @param _proxyToCheck The proxy to fetch the implementation and admin of
51 | /// @return implementation The Implmentation of the `_proxyToCheck`
52 | /// @return admin The Admin of the `_proxyToCheck`
53 | function get1967ProxyImplAndAdmin(
54 | address _proxyToCheck
55 | ) internal view returns (address implementation, address admin) {
56 | implementation = address(uint160(uint(vm.load(_proxyToCheck, IMPLEMENTATION_SLOT))));
57 | admin = address(uint160(uint(vm.load(_proxyToCheck, ADMIN_SLOT))));
58 | }
59 |
60 | /// @notice Variant of the above function but the returns will be logged to the console
61 | /// @param _proxyToCheck The proxy to fetch the implementation and admin of
62 | /// @return implementation The Implmentation of the `_proxyToCheck`
63 | /// @return admin The Admin of the `_proxyToCheck`
64 | function get1967ProxyImplAndAdminWithLog(
65 | address _proxyToCheck
66 | ) internal view returns (address implementation, address admin) {
67 | (implementation, admin) = get1967ProxyImplAndAdmin(_proxyToCheck);
68 | console.log(" get1967ProxyImplAndAdminWithLog: Implementation - ", implementation);
69 | console.log(" get1967ProxyImplAndAdminWithLog: ProxyAdmin - ", admin);
70 | }
71 |
72 | // ========================================================================
73 | // ~~~~~~~~~~~~~~~~~~~~~~~ Storage Slot Helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~
74 | // ========================================================================
75 |
76 | /// @notice Helper function to dump the storage slots of a contract to the console
77 | /// @param target The target contract whose state we wish to view
78 | /// @param slotsToDump The # of lower storage slots we want to log
79 | function dumpStorageLayout(address target, uint256 slotsToDump) internal view {
80 | console.log("===================================");
81 | console.log("Storage dump for: ", target);
82 | console.log("===================================");
83 | for (uint i; i <= slotsToDump; i++) {
84 | bytes32 slot = vm.load(target, bytes32(uint256(i)));
85 | string memory exp = Strings.toHexString(uint256(slot), 32);
86 | console.log("slot", i, ":", exp);
87 | }
88 | }
89 |
90 | /// @notice Helper function for unpacking low level storage slots
91 | /// @param dataToUnpack The bytes32|uint256 of the slot to unpack
92 | /// @param offset The bits to remove st. the target bits are LSB
93 | /// @param lenOfTarget The length target result in bits
94 | /// @return result The target bits expressed as a uint256
95 | function unpackBits(
96 | uint256 dataToUnpack,
97 | uint256 offset,
98 | uint256 lenOfTarget
99 | ) internal pure returns (uint256 result) {
100 | uint256 mask = (1 << lenOfTarget) - 1;
101 | result = (dataToUnpack >> offset) & mask;
102 | }
103 |
104 | function unpackBits(
105 | bytes32 dataToUnpack,
106 | uint256 offset,
107 | uint256 lenOfTarget
108 | ) internal pure returns (uint256 result) {
109 | uint256 mask = (1 << lenOfTarget) - 1;
110 | result = (uint256(dataToUnpack) >> offset) & mask;
111 | }
112 |
113 | function unpackBitsAndLogUint(
114 | uint256 dataToUnpack,
115 | uint256 offset,
116 | uint256 lenOfTarget
117 | ) internal pure returns (uint256 result) {
118 | result = unpackBits(dataToUnpack, offset, lenOfTarget);
119 | console.log(result);
120 | }
121 |
122 | function unpackBitsAndLogUint(
123 | bytes32 dataToUnpack,
124 | uint256 offset,
125 | uint256 lenOfTarget
126 | ) internal pure returns (uint256 result) {
127 | result = unpackBits(dataToUnpack, offset, lenOfTarget);
128 | console.log(result);
129 | }
130 |
131 | error VmDidNotRevert(uint256 _snapshotId);
132 | }
133 |
--------------------------------------------------------------------------------
/src/FrxTransparentProxy.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { TransparentUpgradeableProxy } from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
5 |
6 | // ====================================================================
7 | // | ______ _______ |
8 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
9 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
10 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
11 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
12 | // | |
13 | // ====================================================================
14 | // ====================== FrxTransparentProxy =========================
15 | // ====================================================================
16 |
17 | contract FrxTransparentProxy is TransparentUpgradeableProxy {
18 | constructor(
19 | address _logic,
20 | address _initialAdmin,
21 | bytes memory _data
22 | ) TransparentUpgradeableProxy(_logic, _initialAdmin, _data) {}
23 |
24 | // ================================================================
25 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~ Extension ~~~~~~~~~~~~~~~~~~~~~~~~~~
26 | // ================================================================
27 |
28 | /// @notice Low level function to read arbitrary slots from the proxy
29 | /// @param slot The slot to read
30 | /// @return data The bytes32 data that is stored on that slot
31 | /// @dev Ensure that `0x53e1edcb` does not result in selector clash on
32 | /// The implementation contract
33 | function readArbitrary(bytes32 slot) public view returns (bytes32 data) {
34 | assembly {
35 | data := sload(slot)
36 | }
37 | }
38 |
39 | /// @notice Silence compiler warnings
40 | receive() external payable {
41 | _fallback();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Logger.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ============================= Logger ===============================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // ====================================================================
20 |
21 | import { console2 as console } from "forge-std/Test.sol";
22 | import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
23 | import { NumberFormat } from "./NumberFormat.sol";
24 | import { AddressHelper } from "./AddressHelper.sol";
25 |
26 | library Logger {
27 | using Strings for *;
28 | using NumberFormat for *;
29 | using AddressHelper for *;
30 |
31 | uint64 internal constant FIFTY_BPS = 158_247_046;
32 | uint64 internal constant ONE_PERCENT = FIFTY_BPS * 2;
33 | uint64 internal constant ONE_BPS = FIFTY_BPS / 50;
34 |
35 | function logRate(string memory _string, uint256 _rate) public pure {
36 | console.log(
37 | string(abi.encodePacked(_string, " BPS: ", (_rate / ONE_BPS).toString(), " (raw: ", _rate.toString(), ")"))
38 | );
39 | }
40 |
41 | function rate(string memory _string, uint256 _rate) public pure {
42 | logRate(_string, _rate);
43 | }
44 |
45 | function logDecimal(string memory _string, uint256 _value, uint256 _precision) public pure {
46 | string memory _valueString = _value.toDecimal(_precision);
47 | console.log(string(abi.encodePacked(_string, " ", _valueString, " (raw: ", _value.toString(), ")")));
48 | }
49 |
50 | function decimal(string memory _string, uint256 _value, uint256 _precision) public pure {
51 | logDecimal(_string, _value, _precision);
52 | }
53 |
54 | function decimal(string memory _string, uint256 _value) public pure {
55 | logDecimal(_string, _value, 1e18);
56 | }
57 |
58 | function logPercent(string memory _string, uint256 _percent, uint256 _precision) public pure {
59 | string memory _valueString = (_percent * 100).toDecimal(_precision);
60 | console.log(string(abi.encodePacked(_string, " ", _valueString, "%", " (raw: ", _percent.toString(), ")")));
61 | }
62 |
63 | function percent(string memory _string, uint256 _percent, uint256 _precision) public pure {
64 | logPercent(_string, _percent, _precision);
65 | }
66 |
67 | function percent(string memory _string, uint256 _percent) public pure {
68 | logPercent(_string, _percent, 1e18);
69 | }
70 |
71 | function logScientific(string memory _string, uint256 _value) public pure {
72 | string memory _valueString = _value.toScientific();
73 | console.log(string(abi.encodePacked(_string, " ", _valueString, " (raw: ", _value.toString(), ")")));
74 | }
75 |
76 | function scientific(string memory _string, uint256 _value) public pure {
77 | logScientific(_string, _value);
78 | }
79 |
80 | function addressWithEtherscanLink(string memory _string, address _address) public pure {
81 | console.log(
82 | string(abi.encodePacked(_string, " ", _address.toHexString(), " (", _address.toEtherscanLink(), ")"))
83 | );
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/NumberFormat.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { console2 as console } from "forge-std/Test.sol";
5 | import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
6 | import { StringsHelper } from "./StringsHelper.sol";
7 |
8 | // ====================================================================
9 | // | ______ _______ |
10 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
11 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
12 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
13 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
14 | // | |
15 | // ====================================================================
16 | // ========================== NumberFormat ============================
17 | // ====================================================================
18 | // Frax Finance: https://github.com/FraxFinance
19 |
20 | // Primary Author
21 | // Drake Evans: https://github.com/DrakeEvans
22 |
23 | // ====================================================================
24 |
25 | library NumberFormat {
26 | using Strings for *;
27 | using StringsHelper for *;
28 |
29 | function toDecimal(uint256 _value, uint256 _precision) public pure returns (string memory) {
30 | uint256 _decimals = bytes(Strings.toString(_precision)).length - 1;
31 | uint256 _integer = _value >= _precision ? _value / _precision : 0;
32 | string memory _decimalString = (_value - (_integer * _precision)).toString().padLeft("0", _decimals);
33 | return string(abi.encodePacked(_integer.toString(), ".", _decimalString));
34 | }
35 |
36 | function toScientific(uint256 _value) public pure returns (string memory) {
37 | uint256 _decimals = bytes(Strings.toString(_value)).length - 1;
38 | uint256 _precision = 10 ** _decimals;
39 | uint256 _integer = _value >= _precision ? _value / _precision : 0;
40 | string memory _decimalString = (_value - (_integer * _precision)).toString().padLeft("0", _decimals);
41 | bytes memory _decimalBytes = bytes(_decimalString);
42 | // find index of first non-zero digit starting from the right
43 | uint256 _firstNonZeroIndex;
44 | for (uint256 i = _decimalBytes.length - 1; i > 0; i--) {
45 | if (_decimalBytes[i] != "0") {
46 | _firstNonZeroIndex = i;
47 | break;
48 | }
49 | }
50 | if (_firstNonZeroIndex == 0) {
51 | return string(abi.encodePacked(_integer.toString(), "e", _decimals.toString()));
52 | } else {
53 | _decimalString = _decimalString.slice(0, _firstNonZeroIndex + 1);
54 | return string(abi.encodePacked(_integer.toString(), ".", _decimalString, "e", _decimals.toString()));
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/StringsHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity ^0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ========================== StringsHelper ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // ====================================================================
20 |
21 | import { console2 as console } from "forge-std/Test.sol";
22 | import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
23 |
24 | library StringsHelper {
25 | using Strings for *;
26 |
27 | function padLeft(string memory _string, string memory _pad, uint256 _length) public pure returns (string memory) {
28 | while (bytes(_string).length < _length) {
29 | _string = string(abi.encodePacked(_pad, _string));
30 | }
31 | return _string;
32 | }
33 |
34 | function padRight(string memory _string, string memory _pad, uint256 _length) public pure returns (string memory) {
35 | while (bytes(_string).length < _length) {
36 | _string = string(abi.encodePacked(_string, _pad));
37 | }
38 | return _string;
39 | }
40 |
41 | function slice(string memory _string, uint256 _start, uint256 _end) public pure returns (string memory) {
42 | bytes memory _stringBytes = bytes(_string);
43 | bytes memory _result = new bytes(_end - _start);
44 | for (uint256 i = _start; i < _end; i++) {
45 | _result[i - _start] = _stringBytes[i];
46 | }
47 | return string(_result);
48 | }
49 |
50 | function trim(string memory _string) public pure returns (string memory) {
51 | bytes memory _stringBytes = bytes(_string);
52 | uint256 _start = 0;
53 | uint256 _end = _stringBytes.length - 1;
54 | for (uint256 i = 0; i < _stringBytes.length; i++) {
55 | if (_stringBytes[i] != " ") {
56 | _start = i;
57 | break;
58 | }
59 | }
60 | for (uint256 i = _stringBytes.length - 1; i >= 0; i--) {
61 | if (_stringBytes[i] != " ") {
62 | _end = i;
63 | break;
64 | }
65 | }
66 | return slice(_string, _start, _end + 1);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/TestHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { Test } from "forge-std/Test.sol";
5 |
6 | contract TestHelper is Test {
7 | // helper to move forward one block
8 | function mineOneBlock() public returns (uint256 _timeElapsed, uint256 _blocksElapsed) {
9 | _timeElapsed = 12;
10 | _blocksElapsed = 1;
11 | vm.warp(block.timestamp + _timeElapsed);
12 | vm.roll(block.number + _blocksElapsed);
13 | }
14 |
15 | // helper to move forward multiple blocks
16 | function mineBlocks(uint256 _blocks) public returns (uint256 _timeElapsed, uint256 _blocksElapsed) {
17 | _timeElapsed = (12 * _blocks);
18 | _blocksElapsed = _blocks;
19 | vm.warp(block.timestamp + _timeElapsed);
20 | vm.roll(block.number + _blocksElapsed);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/VmHelper.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.8.0;
2 |
3 | import { CommonBase } from "forge-std/Base.sol";
4 |
5 | contract VmHelper is CommonBase {
6 | struct MineBlocksResult {
7 | uint256 timeElapsed;
8 | uint256 blocksElapsed;
9 | uint256 currentTimestamp;
10 | uint256 currentBlockNumber;
11 | }
12 |
13 | function mineOneBlock() public returns (MineBlocksResult memory result) {
14 | uint256 timeElapsed = 12;
15 | uint256 blocksElapsed = 1;
16 | vm.warp(block.timestamp + timeElapsed);
17 | vm.roll(block.number + blocksElapsed);
18 | result.timeElapsed = timeElapsed;
19 | result.blocksElapsed = blocksElapsed;
20 | result.currentTimestamp = block.timestamp;
21 | result.currentBlockNumber = block.number;
22 | }
23 |
24 | // helper to move forward multiple blocks
25 | function mineBlocks(uint256 _blocks) public returns (MineBlocksResult memory result) {
26 | uint256 timeElapsed = (12 * _blocks);
27 | uint256 blocksElapsed = _blocks;
28 | vm.warp(block.timestamp + timeElapsed);
29 | vm.roll(block.number + blocksElapsed);
30 |
31 | result.timeElapsed = timeElapsed;
32 | result.blocksElapsed = blocksElapsed;
33 | result.currentTimestamp = block.timestamp;
34 | result.currentBlockNumber = block.number;
35 | }
36 |
37 | function mineBlocksBySecond(uint256 secondsElapsed) public returns (MineBlocksResult memory result) {
38 | uint256 timeElapsed = secondsElapsed;
39 | uint256 blocksElapsed = secondsElapsed / 12;
40 | vm.warp(block.timestamp + timeElapsed);
41 | vm.roll(block.number + blocksElapsed);
42 |
43 | result.timeElapsed = timeElapsed;
44 | result.blocksElapsed = blocksElapsed;
45 | result.currentTimestamp = block.timestamp;
46 | result.currentBlockNumber = block.number;
47 | }
48 |
49 | function mineBlocksToTimestamp(uint256 _timestamp) public returns (MineBlocksResult memory result) {
50 | uint256 timeElapsed = _timestamp - block.timestamp;
51 | uint256 blocksElapsed = timeElapsed / 12;
52 | vm.warp(_timestamp);
53 | vm.roll(block.number + blocksElapsed);
54 |
55 | result.timeElapsed = timeElapsed;
56 | result.blocksElapsed = blocksElapsed;
57 | result.currentTimestamp = block.timestamp;
58 | result.currentBlockNumber = block.number;
59 | }
60 |
61 | function labelAndDeal(address _address, string memory _label) public returns (address payable) {
62 | vm.label(_address, _label);
63 | vm.deal(_address, 1_000_000_000);
64 | return payable(_address);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/access-control/v1/Timelock2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ========================== Timelock2Step ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // Reviewers
20 | // Dennis: https://github.com/denett
21 |
22 | // ====================================================================
23 |
24 | /// @title Timelock2Step
25 | /// @author Drake Evans (Frax Finance) https://github.com/drakeevans
26 | /// @dev Inspired by the OpenZeppelin's Ownable2Step contract
27 | /// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address
28 | abstract contract Timelock2Step {
29 | /// @notice The pending timelock address
30 | address public pendingTimelockAddress;
31 |
32 | /// @notice The current timelock address
33 | address public timelockAddress;
34 |
35 | constructor() {
36 | timelockAddress = msg.sender;
37 | }
38 |
39 | /// @notice Emitted when timelock is transferred
40 | error OnlyTimelock();
41 |
42 | /// @notice Emitted when pending timelock is transferred
43 | error OnlyPendingTimelock();
44 |
45 | /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
46 | /// @param previousTimelock The address of the previous timelock
47 | /// @param newTimelock The address of the new timelock
48 | event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
49 |
50 | /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
51 | /// @param previousTimelock The address of the previous timelock
52 | /// @param newTimelock The address of the new timelock
53 | event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
54 |
55 | /// @notice The ```_isSenderTimelock``` function checks if msg.sender is current timelock address
56 | /// @return Whether or not msg.sender is current timelock address
57 | function _isSenderTimelock() internal view returns (bool) {
58 | return msg.sender == timelockAddress;
59 | }
60 |
61 | /// @notice The ```_requireTimelock``` function reverts if msg.sender is not current timelock address
62 | function _requireTimelock() internal view {
63 | if (msg.sender != timelockAddress) revert OnlyTimelock();
64 | }
65 |
66 | /// @notice The ```_isSenderPendingTimelock``` function checks if msg.sender is pending timelock address
67 | /// @return Whether or not msg.sender is pending timelock address
68 | function _isSenderPendingTimelock() internal view returns (bool) {
69 | return msg.sender == pendingTimelockAddress;
70 | }
71 |
72 | /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
73 | function _requirePendingTimelock() internal view {
74 | if (msg.sender != pendingTimelockAddress) revert OnlyPendingTimelock();
75 | }
76 |
77 | /// @notice The ```_transferTimelock``` function initiates the timelock transfer
78 | /// @dev This function is to be implemented by a public function
79 | /// @param _newTimelock The address of the nominated (pending) timelock
80 | function _transferTimelock(address _newTimelock) internal {
81 | pendingTimelockAddress = _newTimelock;
82 | emit TimelockTransferStarted(timelockAddress, _newTimelock);
83 | }
84 |
85 | /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
86 | /// @dev This function is to be implemented by a public function
87 | function _acceptTransferTimelock() internal {
88 | pendingTimelockAddress = address(0);
89 | _setTimelock(msg.sender);
90 | }
91 |
92 | /// @notice The ```_setTimelock``` function sets the timelock address
93 | /// @dev This function is to be implemented by a public function
94 | /// @param _newTimelock The address of the new timelock
95 | function _setTimelock(address _newTimelock) internal {
96 | emit TimelockTransferred(timelockAddress, _newTimelock);
97 | timelockAddress = _newTimelock;
98 | }
99 |
100 | /// @notice The ```transferTimelock``` function initiates the timelock transfer
101 | /// @dev Must be called by the current timelock
102 | /// @param _newTimelock The address of the nominated (pending) timelock
103 | function transferTimelock(address _newTimelock) external virtual {
104 | _requireTimelock();
105 | _transferTimelock(_newTimelock);
106 | }
107 |
108 | /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
109 | /// @dev Must be called by the pending timelock
110 | function acceptTransferTimelock() external virtual {
111 | _requirePendingTimelock();
112 | _acceptTransferTimelock();
113 | }
114 |
115 | /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
116 | /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
117 | function renounceTimelock() external virtual {
118 | _requireTimelock();
119 | _requirePendingTimelock();
120 | _transferTimelock(address(0));
121 | _setTimelock(address(0));
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/access-control/v1/interfaces/ITimelock2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity >=0.8.0;
3 |
4 | interface ITimelock2Step {
5 | event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
6 | event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
7 |
8 | function acceptTransferTimelock() external;
9 |
10 | function pendingTimelockAddress() external view returns (address);
11 |
12 | function renounceTimelock() external;
13 |
14 | function timelockAddress() external view returns (address);
15 |
16 | function transferTimelock(address _newTimelock) external;
17 | }
18 |
--------------------------------------------------------------------------------
/src/access-control/v2/Operator2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ========================== Operator2Step ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // Reviewers
20 | // Dennis: https://github.com/denett
21 |
22 | // ====================================================================
23 |
24 | import { OperatorRole } from "./OperatorRole.sol";
25 |
26 | /// @title Operator2Step
27 | /// @author Drake Evans (Frax Finance) https://github.com/drakeevans
28 | /// @dev Inspired by OpenZeppelin's Ownable2Step contract
29 | /// @notice An abstract contract which contains 2-step transfer and renounce logic for a operator address
30 | abstract contract OperatorRole2Step is OperatorRole {
31 | /// @notice The pending operator address
32 | address public pendingOperatorAddress;
33 |
34 | constructor(address _operatorAddress) OperatorRole(_operatorAddress) {}
35 |
36 | // ============================================================================================
37 | // Functions: External Functions
38 | // ============================================================================================
39 |
40 | /// @notice The ```transferOperator``` function initiates the operator transfer
41 | /// @dev Must be called by the current operator
42 | /// @param _newOperator The address of the nominated (pending) operator
43 | function transferOperator(address _newOperator) external virtual {
44 | _requireSenderIsOperator();
45 | _transferOperator(_newOperator);
46 | }
47 |
48 | /// @notice The ```acceptTransferOperator``` function completes the operator transfer
49 | /// @dev Must be called by the pending operator
50 | function acceptTransferOperator() external virtual {
51 | _requireSenderIsPendingOperator();
52 | _acceptTransferOperator();
53 | }
54 |
55 | /// @notice The ```renounceOperator``` function renounces the operator after setting pending operator to current operator
56 | /// @dev Pending operator must be set to current operator before renouncing, creating a 2-step renounce process
57 | function renounceOperator() external virtual {
58 | _requireSenderIsOperator();
59 | _requireSenderIsPendingOperator();
60 | _transferOperator(address(0));
61 | _setOperator(address(0));
62 | }
63 |
64 | // ============================================================================================
65 | // Functions: Internal Actions
66 | // ============================================================================================
67 |
68 | /// @notice The ```OperatorTransferStarted``` event is emitted when the operator transfer is initiated
69 | /// @param previousOperator The address of the previous operator
70 | /// @param newOperator The address of the new operator
71 | event OperatorTransferStarted(address indexed previousOperator, address indexed newOperator);
72 |
73 | /// @notice The ```_transferOperator``` function initiates the operator transfer
74 | /// @dev This function is to be implemented by a public function
75 | /// @param _newOperator The address of the nominated (pending) operator
76 | function _transferOperator(address _newOperator) internal {
77 | pendingOperatorAddress = _newOperator;
78 | emit OperatorTransferStarted(operatorAddress, _newOperator);
79 | }
80 |
81 | /// @notice The ```_acceptTransferOperator``` function completes the operator transfer
82 | /// @dev This function is to be implemented by a public function
83 | function _acceptTransferOperator() internal {
84 | pendingOperatorAddress = address(0);
85 | _setOperator(msg.sender);
86 | }
87 |
88 | // ============================================================================================
89 | // Functions: Internal Checks
90 | // ============================================================================================
91 |
92 | /// @notice The ```_isPendingOperator``` function checks if the _address is pending operator address
93 | /// @dev This function is to be implemented by a public function
94 | /// @param _address The address to check against the pending operator
95 | /// @return Whether or not _address is pending operator address
96 | function _isPendingOperator(address _address) internal view returns (bool) {
97 | return _address == pendingOperatorAddress;
98 | }
99 |
100 | /// @notice The ```_requireIsPendingOperator``` function reverts if the _address is not pending operator address
101 | /// @dev This function is to be implemented by a public function
102 | /// @param _address The address to check against the pending operator
103 | function _requireIsPendingOperator(address _address) internal view {
104 | if (!_isPendingOperator(_address)) revert SenderIsNotPendingOperator();
105 | }
106 |
107 | /// @notice The ```_requirePendingOperator``` function reverts if msg.sender is not pending operator address
108 | /// @dev This function is to be implemented by a public function
109 | function _requireSenderIsPendingOperator() internal view {
110 | _requireIsPendingOperator(msg.sender);
111 | }
112 |
113 | // ============================================================================================
114 | // Functions: Errors
115 | // ============================================================================================
116 |
117 | /// @notice Emitted when operator is transferred
118 | error SenderIsNotOperator();
119 |
120 | /// @notice Emitted when pending operator is transferred
121 | error SenderIsNotPendingOperator();
122 | }
123 |
--------------------------------------------------------------------------------
/src/access-control/v2/OperatorRole.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // =========================== OperatorRole ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // Reviewers
20 | // Dennis: https://github.com/denett
21 | // Travis Moore: https://github.com/FortisFortuna
22 |
23 | // ====================================================================
24 |
25 | abstract contract OperatorRole {
26 | // ============================================================================================
27 | // Storage & Constructor
28 | // ============================================================================================
29 |
30 | /// @notice The current operator address
31 | address public operatorAddress;
32 |
33 | constructor(address _operatorAddress) {
34 | operatorAddress = _operatorAddress;
35 | }
36 |
37 | // ============================================================================================
38 | // Functions: Internal Actions
39 | // ============================================================================================
40 |
41 | /// @notice The ```OperatorTransferred``` event is emitted when the operator transfer is completed
42 | /// @param previousOperator The address of the previous operator
43 | /// @param newOperator The address of the new operator
44 | event OperatorTransferred(address indexed previousOperator, address indexed newOperator);
45 |
46 | /// @notice The ```_setOperator``` function sets the operator address
47 | /// @dev This function is to be implemented by a public function
48 | /// @param _newOperator The address of the new operator
49 | function _setOperator(address _newOperator) internal {
50 | emit OperatorTransferred(operatorAddress, _newOperator);
51 | operatorAddress = _newOperator;
52 | }
53 |
54 | // ============================================================================================
55 | // Functions: Internal Checks
56 | // ============================================================================================
57 |
58 | /// @notice The ```_isOperator``` function checks if _address is current operator address
59 | /// @param _address The address to check against the operator
60 | /// @return Whether or not msg.sender is current operator address
61 | function _isOperator(address _address) internal view returns (bool) {
62 | return _address == operatorAddress;
63 | }
64 |
65 | /// @notice The ```AddressIsNotOperator``` error is used for validation of the operatorAddress
66 | /// @param operatorAddress The expected operatorAddress
67 | /// @param actualAddress The actual operatorAddress
68 | error AddressIsNotOperator(address operatorAddress, address actualAddress);
69 |
70 | /// @notice The ```_requireIsOperator``` function reverts if _address is not current operator address
71 | /// @param _address The address to check against the operator
72 | function _requireIsOperator(address _address) internal view {
73 | if (!_isOperator(_address)) revert AddressIsNotOperator(operatorAddress, _address);
74 | }
75 |
76 | /// @notice The ```_requireSenderIsOperator``` function reverts if msg.sender is not current operator address
77 | /// @dev This function is to be implemented by a public function
78 | function _requireSenderIsOperator() internal view {
79 | _requireIsOperator(msg.sender);
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/access-control/v2/PublicReentrancyGuard.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
3 |
4 | // NOTE: This file has been modified from the original to make the _status an internal item so that it can be exposed by consumers.
5 | // This allows us to prevent global reentrancy across different
6 |
7 | pragma solidity ^0.8.0;
8 |
9 | /**
10 | * @dev Contract module that helps prevent reentrant calls to a function.
11 | *
12 | * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
13 | * available, which can be applied to functions to make sure there are no nested
14 | * (reentrant) calls to them.
15 | *
16 | * Note that because there is a single `nonReentrant` guard, functions marked as
17 | * `nonReentrant` may not call one another. This can be worked around by making
18 | * those functions `private`, and then adding `external` `nonReentrant` entry
19 | * points to them.
20 | *
21 | * TIP: If you would like to learn more about reentrancy and alternative ways
22 | * to protect against it, check out our blog post
23 | * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
24 | */
25 | abstract contract PublicReentrancyGuard {
26 | // Booleans are more expensive than uint256 or any type that takes up a full
27 | // word because each write operation emits an extra SLOAD to first read the
28 | // slot's contents, replace the bits taken up by the boolean, and then write
29 | // back. This is the compiler's defense against contract upgrades and
30 | // pointer aliasing, and it cannot be disabled.
31 |
32 | // The values being non-zero value makes deployment a bit more expensive,
33 | // but in exchange the refund on every call to nonReentrant will be lower in
34 | // amount. Since refunds are capped to a percentage of the total
35 | // transaction's gas, it is best to keep them low in cases like this one, to
36 | // increase the likelihood of the full refund coming into effect.
37 | uint256 private constant _NOT_ENTERED = 1;
38 | uint256 private constant _ENTERED = 2;
39 |
40 | uint256 internal _status;
41 |
42 | constructor() {
43 | _status = _NOT_ENTERED;
44 | }
45 |
46 | /**
47 | * @dev Prevents a contract from calling itself, directly or indirectly.
48 | * Calling a `nonReentrant` function from another `nonReentrant`
49 | * function is not supported. It is possible to prevent this from happening
50 | * by making the `nonReentrant` function external, and making it call a
51 | * `private` function that does the actual work.
52 | */
53 | modifier nonReentrant() {
54 | _nonReentrantBefore();
55 | _;
56 | _nonReentrantAfter();
57 | }
58 |
59 | function _nonReentrantBefore() private {
60 | // On the first call to nonReentrant, _status will be _NOT_ENTERED
61 | require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
62 |
63 | // Any calls to nonReentrant after this point will fail
64 | _status = _ENTERED;
65 | }
66 |
67 | function _nonReentrantAfter() private {
68 | // By storing the original value once again, a refund is triggered (see
69 | // https://eips.ethereum.org/EIPS/eip-2200)
70 | _status = _NOT_ENTERED;
71 | }
72 |
73 | /**
74 | * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
75 | * `nonReentrant` function in the call stack.
76 | */
77 | function _reentrancyGuardEntered() internal view returns (bool) {
78 | return _status == _ENTERED;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/access-control/v2/Timelock2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | // ====================================================================
5 | // | ______ _______ |
6 | // | / _____________ __ __ / ____(_____ ____ _____ ________ |
7 | // | / /_ / ___/ __ `| |/_/ / /_ / / __ \/ __ `/ __ \/ ___/ _ \ |
8 | // | / __/ / / / /_/ _> < / __/ / / / / / /_/ / / / / /__/ __/ |
9 | // | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
10 | // | |
11 | // ====================================================================
12 | // ========================== Timelock2Step ===========================
13 | // ====================================================================
14 | // Frax Finance: https://github.com/FraxFinance
15 |
16 | // Primary Author
17 | // Drake Evans: https://github.com/DrakeEvans
18 |
19 | // Reviewers
20 | // Dennis: https://github.com/denett
21 |
22 | // ====================================================================
23 |
24 | /// @title Timelock2Step
25 | /// @author Drake Evans (Frax Finance) https://github.com/drakeevans
26 | /// @dev Inspired by OpenZeppelin's Ownable2Step contract
27 | /// @notice An abstract contract which contains 2-step transfer and renounce logic for a timelock address
28 | abstract contract Timelock2Step {
29 | /// @notice The pending timelock address
30 | address public pendingTimelockAddress;
31 |
32 | /// @notice The current timelock address
33 | address public timelockAddress;
34 |
35 | constructor(address _timelockAddress) {
36 | timelockAddress = _timelockAddress;
37 | }
38 |
39 | // ============================================================================================
40 | // Functions: External Functions
41 | // ============================================================================================
42 |
43 | /// @notice The ```transferTimelock``` function initiates the timelock transfer
44 | /// @dev Must be called by the current timelock
45 | /// @param _newTimelock The address of the nominated (pending) timelock
46 | function transferTimelock(address _newTimelock) external virtual {
47 | _requireSenderIsTimelock();
48 | _transferTimelock(_newTimelock);
49 | }
50 |
51 | /// @notice The ```acceptTransferTimelock``` function completes the timelock transfer
52 | /// @dev Must be called by the pending timelock
53 | function acceptTransferTimelock() external virtual {
54 | _requireSenderIsPendingTimelock();
55 | _acceptTransferTimelock();
56 | }
57 |
58 | /// @notice The ```renounceTimelock``` function renounces the timelock after setting pending timelock to current timelock
59 | /// @dev Pending timelock must be set to current timelock before renouncing, creating a 2-step renounce process
60 | function renounceTimelock() external virtual {
61 | _requireSenderIsTimelock();
62 | _requireSenderIsPendingTimelock();
63 | _transferTimelock(address(0));
64 | _setTimelock(address(0));
65 | }
66 |
67 | // ============================================================================================
68 | // Functions: Internal Actions
69 | // ============================================================================================
70 |
71 | /// @notice The ```_transferTimelock``` function initiates the timelock transfer
72 | /// @dev This function is to be implemented by a public function
73 | /// @param _newTimelock The address of the nominated (pending) timelock
74 | function _transferTimelock(address _newTimelock) internal {
75 | pendingTimelockAddress = _newTimelock;
76 | emit TimelockTransferStarted(timelockAddress, _newTimelock);
77 | }
78 |
79 | /// @notice The ```_acceptTransferTimelock``` function completes the timelock transfer
80 | /// @dev This function is to be implemented by a public function
81 | function _acceptTransferTimelock() internal {
82 | pendingTimelockAddress = address(0);
83 | _setTimelock(msg.sender);
84 | }
85 |
86 | /// @notice The ```_setTimelock``` function sets the timelock address
87 | /// @dev This function is to be implemented by a public function
88 | /// @param _newTimelock The address of the new timelock
89 | function _setTimelock(address _newTimelock) internal {
90 | emit TimelockTransferred(timelockAddress, _newTimelock);
91 | timelockAddress = _newTimelock;
92 | }
93 |
94 | // ============================================================================================
95 | // Functions: Internal Checks
96 | // ============================================================================================
97 |
98 | /// @notice The ```_isTimelock``` function checks if _address is current timelock address
99 | /// @param _address The address to check against the timelock
100 | /// @return Whether or not msg.sender is current timelock address
101 | function _isTimelock(address _address) internal view returns (bool) {
102 | return _address == timelockAddress;
103 | }
104 |
105 | /// @notice The ```_requireIsTimelock``` function reverts if _address is not current timelock address
106 | /// @param _address The address to check against the timelock
107 | function _requireIsTimelock(address _address) internal view {
108 | if (!_isTimelock(_address)) revert AddressIsNotTimelock(timelockAddress, _address);
109 | }
110 |
111 | /// @notice The ```_requireSenderIsTimelock``` function reverts if msg.sender is not current timelock address
112 | /// @dev This function is to be implemented by a public function
113 | function _requireSenderIsTimelock() internal view {
114 | _requireIsTimelock(msg.sender);
115 | }
116 |
117 | /// @notice The ```_isPendingTimelock``` function checks if the _address is pending timelock address
118 | /// @dev This function is to be implemented by a public function
119 | /// @param _address The address to check against the pending timelock
120 | /// @return Whether or not _address is pending timelock address
121 | function _isPendingTimelock(address _address) internal view returns (bool) {
122 | return _address == pendingTimelockAddress;
123 | }
124 |
125 | /// @notice The ```_requireIsPendingTimelock``` function reverts if the _address is not pending timelock address
126 | /// @dev This function is to be implemented by a public function
127 | /// @param _address The address to check against the pending timelock
128 | function _requireIsPendingTimelock(address _address) internal view {
129 | if (!_isPendingTimelock(_address)) revert AddressIsNotPendingTimelock(pendingTimelockAddress, _address);
130 | }
131 |
132 | /// @notice The ```_requirePendingTimelock``` function reverts if msg.sender is not pending timelock address
133 | /// @dev This function is to be implemented by a public function
134 | function _requireSenderIsPendingTimelock() internal view {
135 | _requireIsPendingTimelock(msg.sender);
136 | }
137 |
138 | // ============================================================================================
139 | // Functions: Events
140 | // ============================================================================================
141 |
142 | /// @notice The ```TimelockTransferStarted``` event is emitted when the timelock transfer is initiated
143 | /// @param previousTimelock The address of the previous timelock
144 | /// @param newTimelock The address of the new timelock
145 | event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
146 |
147 | /// @notice The ```TimelockTransferred``` event is emitted when the timelock transfer is completed
148 | /// @param previousTimelock The address of the previous timelock
149 | /// @param newTimelock The address of the new timelock
150 | event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
151 |
152 | // ============================================================================================
153 | // Functions: Errors
154 | // ============================================================================================
155 |
156 | /// @notice Emitted when timelock is transferred
157 | error AddressIsNotTimelock(address timelockAddress, address actualAddress);
158 |
159 | /// @notice Emitted when pending timelock is transferred
160 | error AddressIsNotPendingTimelock(address pendingTimelockAddress, address actualAddress);
161 | }
162 |
--------------------------------------------------------------------------------
/src/access-control/v2/interfaces/IOperator2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity >=0.8.0;
3 |
4 | interface IOperator2Step {
5 | event OperatorTransferStarted(address indexed previousOperator, address indexed newOperator);
6 | event OperatorTransferred(address indexed previousOperator, address indexed newOperator);
7 |
8 | function acceptTransferOperator() external;
9 |
10 | function operatorAddress() external view returns (address);
11 |
12 | function pendingOperatorAddress() external view returns (address);
13 |
14 | function renounceOperator() external;
15 |
16 | function transferOperator(address _newOperator) external;
17 | }
18 |
--------------------------------------------------------------------------------
/src/access-control/v2/interfaces/IOperatorRole.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | interface IOperatorRole {
5 | event OperatorTransferred(address indexed previousOperator, address indexed newOperator);
6 |
7 | function operatorAddress() external view returns (address);
8 |
9 | function setOperator() external;
10 | }
11 |
--------------------------------------------------------------------------------
/src/access-control/v2/interfaces/ITimelock2Step.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity >=0.8.0;
3 |
4 | interface ITimelock2Step {
5 | event TimelockTransferStarted(address indexed previousTimelock, address indexed newTimelock);
6 | event TimelockTransferred(address indexed previousTimelock, address indexed newTimelock);
7 |
8 | function acceptTransferTimelock() external;
9 |
10 | function pendingTimelockAddress() external view returns (address);
11 |
12 | function renounceTimelock() external;
13 |
14 | function timelockAddress() external view returns (address);
15 |
16 | function transferTimelock(address _newTimelock) external;
17 | }
18 |
--------------------------------------------------------------------------------
/src/oracles/AggregatorV3InterfaceStructHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import { AggregatorV3Interface } from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
5 |
6 | library AggregatorV3InterfaceStructHelper {
7 | struct GetRoundDataReturn {
8 | uint80 roundId;
9 | int256 answer;
10 | uint256 startedAt;
11 | uint256 updatedAt;
12 | uint80 answeredInRound;
13 | }
14 |
15 | function __getRoundData(
16 | AggregatorV3Interface _aggregatorV3,
17 | uint80 _roundId
18 | ) internal view returns (GetRoundDataReturn memory _return) {
19 | (_return.roundId, _return.answer, _return.startedAt, _return.updatedAt, _return.answeredInRound) = _aggregatorV3
20 | .getRoundData(_roundId);
21 | }
22 |
23 | struct LatestRoundDataReturn {
24 | uint80 roundId;
25 | int256 answer;
26 | uint256 startedAt;
27 | uint256 updatedAt;
28 | uint80 answeredInRound;
29 | }
30 |
31 | function __latestRoundData(
32 | AggregatorV3Interface _aggregatorV3
33 | ) internal view returns (LatestRoundDataReturn memory _return) {
34 | (_return.roundId, _return.answer, _return.startedAt, _return.updatedAt, _return.answeredInRound) = _aggregatorV3
35 | .latestRoundData();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/oracles/OracleHelper.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
5 | import { Vm } from "forge-std/Test.sol";
6 | import { AggregatorV3InterfaceStructHelper } from "./AggregatorV3InterfaceStructHelper.sol";
7 |
8 | library OracleHelper {
9 | using AggregatorV3InterfaceStructHelper for AggregatorV3Interface;
10 |
11 | function setDecimals(AggregatorV3Interface _oracle, uint8 _decimals, Vm vm) public {
12 | vm.mockCall(
13 | address(_oracle),
14 | abi.encodeWithSelector(AggregatorV3Interface.decimals.selector),
15 | abi.encode(_decimals)
16 | );
17 | }
18 |
19 | /// @notice The ```setPrice``` function uses a numerator and denominator value to set a price using the number of decimals from the oracle itself
20 | /// @dev Remember the units here, quote per asset i.e. USD per ETH for the ETH/USD oracle
21 | /// @param _oracle The oracle to mock
22 | /// @param numerator The numerator of the price
23 | /// @param denominator The denominator of the price
24 | /// @param vm The vm from forge
25 | function setPrice(
26 | AggregatorV3Interface _oracle,
27 | uint256 numerator,
28 | uint256 denominator,
29 | uint256 _lastUpdatedAt,
30 | Vm vm
31 | ) public returns (int256 _price) {
32 | _price = int256((numerator * 10 ** _oracle.decimals()) / denominator);
33 | vm.mockCall(
34 | address(_oracle),
35 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
36 | abi.encode(uint80(0), _price, 0, _lastUpdatedAt, uint80(0))
37 | );
38 | }
39 |
40 | function setPrice(
41 | AggregatorV3Interface _oracle,
42 | uint256 price_,
43 | uint256 _lastUpdatedAt,
44 | Vm vm
45 | ) public returns (int256 _price) {
46 | _price = int256(price_);
47 | vm.mockCall(
48 | address(_oracle),
49 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
50 | abi.encode(uint80(0), _price, 0, _lastUpdatedAt, uint80(0))
51 | );
52 | }
53 |
54 | function setPrice(
55 | AggregatorV3Interface _oracle,
56 | int256 price_,
57 | uint256 _lastUpdatedAt,
58 | Vm vm
59 | ) public returns (int256 _price) {
60 | _price = int256(price_);
61 | vm.mockCall(
62 | address(_oracle),
63 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
64 | abi.encode(uint80(0), _price, 0, _lastUpdatedAt, uint80(0))
65 | );
66 | }
67 |
68 | function setPrice(AggregatorV3Interface _oracle, uint256 price_, Vm vm) public returns (int256 _price) {
69 | uint256 _updatedAt = _oracle.__latestRoundData().updatedAt;
70 | _price = int256(price_);
71 | vm.mockCall(
72 | address(_oracle),
73 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
74 | abi.encode(uint80(0), _price, 0, _updatedAt, uint80(0))
75 | );
76 | }
77 |
78 | function setPriceWithE18Param(
79 | AggregatorV3Interface _oracle,
80 | uint256 price_,
81 | Vm vm
82 | ) public returns (int256 returnPrice) {
83 | uint256 _updatedAt = _oracle.__latestRoundData().updatedAt;
84 | uint256 _decimals = _oracle.decimals();
85 | price_ = (price_ * 10 ** _decimals) / 1e18;
86 | returnPrice = int256(price_);
87 | vm.mockCall(
88 | address(_oracle),
89 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
90 | abi.encode(uint80(0), returnPrice, 0, _updatedAt, uint80(0))
91 | );
92 | }
93 |
94 | function setUpdatedAt(AggregatorV3Interface _oracle, uint256 _updatedAt, Vm vm) public returns (int256 _price) {
95 | _price = _oracle.__latestRoundData().answer;
96 | vm.mockCall(
97 | address(_oracle),
98 | abi.encodeWithSelector(AggregatorV3Interface.latestRoundData.selector),
99 | abi.encode(uint80(0), _price, 0, _updatedAt, uint80(0))
100 | );
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/test/LoggerTest.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 | import "../src/Logger.sol";
6 |
7 | contract LoggerTest is FraxTest {
8 | function testAddressWithLink() public pure {
9 | address _address = address(0);
10 | Logger.addressWithEtherscanLink("test", _address);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test/NumberFormatTest.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 | import "../src/NumberFormat.sol";
6 |
7 | contract NumberFormatTest is FraxTest {
8 | function testToScientific() public {
9 | uint256 _value = 123456789;
10 | string memory _expected = "1.23456789e8";
11 | string memory _actual = NumberFormat.toScientific(_value);
12 | assertEq(_expected, _actual);
13 | }
14 |
15 | function testToScientific2() public {
16 | uint256 _value = 1e18;
17 | string memory _expected = "1e18";
18 | string memory _actual = NumberFormat.toScientific(_value);
19 | assertEq(_expected, _actual);
20 | }
21 |
22 | function testToScientific3() public {
23 | uint256 _value = 1010;
24 | string memory _expected = "1.01e3";
25 | string memory _actual = NumberFormat.toScientific(_value);
26 | assertEq(_expected, _actual);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/test/TestArrayHelper.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 | import { ArrayHelper } from "../src/ArrayHelper.sol";
6 |
7 | contract TestArrayHelper is FraxTest {
8 | using ArrayHelper for *;
9 |
10 | function testConcat() public {
11 | address[] memory _myArray = new address[](3);
12 | _myArray = _myArray.concat(address(36));
13 | for (uint256 i = 0; i < _myArray.length; i++) {
14 | console.log(_myArray[i]);
15 | }
16 | assertEq(_myArray.length, 4);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/test/TestFrxProxy.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 | import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
6 | import { FrxTransparentProxy } from "src/FrxTransparentProxy.sol";
7 |
8 | contract TestFrxTransparentProxy is FraxTest {
9 | address instance;
10 | FrxTransparentProxy frxUsdProxy;
11 | IERC20 frxUsd;
12 |
13 | function setUp() public {
14 | vm.createSelectFork("https://rpc.frax.com", 16_557_873);
15 | vm.etch(
16 | address(0xC2A4), /// The Unicode character '¤' encoded in UTF-8 and represented as hex
17 | hex"11"
18 | );
19 | instance = address(new FrxTransparentProxy(address(0xC2A4), address(0xC2A4), hex""));
20 | vm.etch(0xFc00000000000000000000000000000000000001, instance.code);
21 | frxUsdProxy = FrxTransparentProxy(payable(0xFc00000000000000000000000000000000000001));
22 | frxUsd = IERC20(0xFc00000000000000000000000000000000000001);
23 | }
24 |
25 | function testReadImplementationSlot() public {
26 | bytes32 impl = frxUsdProxy.readArbitrary(IMPLEMENTATION_SLOT);
27 | assertEq({
28 | right: address(uint160(uint256(impl))),
29 | left: 0x00000aFb5e62fd81bC698E418dBfFE5094cB38E0,
30 | err: "// THEN: Implementation not as expected"
31 | });
32 | }
33 |
34 | function testReadAdminSlot() public {
35 | bytes32 admin = frxUsdProxy.readArbitrary(ADMIN_SLOT);
36 | console.logBytes32(admin);
37 | assertEq({
38 | right: address(uint160(uint256(admin))),
39 | left: 0xfC0000000000000000000000000000000000000a,
40 | err: "// THEN: Admin not as expected"
41 | });
42 | }
43 |
44 | function testReadBalanceData() public {
45 | /// Derive the balance slot
46 | bytes32 balanceSlot = keccak256(abi.encode(0x31562ae726AFEBe25417df01bEdC72EF489F45b3, 0));
47 | bytes32 balance = frxUsdProxy.readArbitrary(balanceSlot);
48 | assertEq({ right: uint256(balance), left: 879.253786510845295473e18, err: "// THEN: balance not as expected" });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/test/TestMultipleSetup.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 |
6 | contract TestMultipleSetup is FraxTest {
7 | uint256 public value;
8 | uint256 public runsPassed;
9 |
10 | function initializeValueOne() public {
11 | value = 25;
12 | }
13 |
14 | function initializeValueTwo() public {
15 | value = 5;
16 | }
17 |
18 | function initializeValueThree() public {
19 | value = 10;
20 | }
21 |
22 | function setUp() public {
23 | setupFunctions.push(initializeValueOne);
24 | setupFunctions.push(initializeValueTwo);
25 | setupFunctions.push(initializeValueThree);
26 | addSetupFunctions(setupFunctions);
27 | vm.makePersistent(address(this));
28 | }
29 |
30 | function revertIfNotFive(uint256 value) public {
31 | if (value != 5) revert();
32 | else revert("Run Passed");
33 | }
34 |
35 | /// @notice Should fail if value is not 5, should fail differently if
36 | /// value == 5
37 | function testAssertValue() public useMultipleSetupFunctions {
38 | if (value != 5) vm.expectRevert();
39 | else vm.expectRevert(bytes("Run Passed"));
40 | this.revertIfNotFive(value);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/TestSlotDump.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: ISC
2 | pragma solidity >=0.8.0;
3 |
4 | import "../src/FraxTest.sol";
5 |
6 | contract TestSlotDump is FraxTest {
7 | address instance;
8 |
9 | function testDumpSlots() public {
10 | instance = address(new Charlie());
11 | dumpStorageLayout(instance, 15);
12 | }
13 |
14 | function testUnpackSlotBytes() public {
15 | instance = address(new Charlie());
16 | dumpStorageLayout(instance, 15);
17 |
18 | bytes32 packedSlot = vm.load(address(instance), bytes32(uint(9)));
19 | uint256 unpacked1 = unpackBitsAndLogUint(packedSlot, 0, 96);
20 | uint256 unpacked2 = unpackBitsAndLogUint(packedSlot, 96, 160);
21 |
22 | /// @notice `unpacked1` is `uint96` expressed as `uint256`
23 | assertEq(22222222222222222222, unpacked1);
24 | assertEq(22222222222222222222, uint96(unpacked1));
25 |
26 | /// @notice `unpacked2` is `address` expressed as `uint256`
27 | assertEq(uint256(uint160(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)), unpacked2);
28 | assertEq(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, address(uint160(unpacked2)));
29 | }
30 |
31 | function testUnpackSlotUint() public {
32 | instance = address(new Charlie());
33 | dumpStorageLayout(instance, 15);
34 |
35 | uint256 packedSlot = uint256(vm.load(address(instance), bytes32(uint(9))));
36 | uint256 unpacked1 = unpackBitsAndLogUint(packedSlot, 0, 96);
37 | uint256 unpacked2 = unpackBitsAndLogUint(packedSlot, 96, 160);
38 |
39 | /// @notice `unpacked1` is `uint96` expressed as `uint256`
40 | assertEq(22222222222222222222, unpacked1);
41 | assertEq(22222222222222222222, uint96(unpacked1));
42 |
43 | /// @notice `unpacked2` is `address` expressed as `uint256`
44 | assertEq(uint256(uint160(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)), unpacked2);
45 | assertEq(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE, address(uint160(unpacked2)));
46 | }
47 | }
48 |
49 | // ================== Helpers ==================
50 |
51 | contract Alpha {
52 | address owner = address(0xC0ffee);
53 | address pendingOwner;
54 | }
55 |
56 | contract Bravo is Alpha {
57 | bytes32 someValue = bytes32(type(uint).max);
58 | uint256[5] gap;
59 | bytes32 someOtherValue = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA;
60 | }
61 |
62 | contract Charlie is Bravo {
63 | uint96 packed1 = 22222222222222222222;
64 | address packed2 = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
65 | }
66 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration": true,
4 | "declarationMap": true,
5 | "emitDecoratorMetadata": true,
6 | "esModuleInterop": true,
7 | "experimentalDecorators": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "lib": ["ESNext"],
10 | "module": "commonjs",
11 | "moduleResolution": "node",
12 | "noImplicitAny": false,
13 | "removeComments": false,
14 | "resolveJsonModule": true,
15 | "sourceMap": true,
16 | "strict": false,
17 | "target": "ESNext",
18 | "outDir": "dist"
19 | },
20 | "exclude": ["node_modules"],
21 | "include": ["script/**/*"]
22 | }
23 |
--------------------------------------------------------------------------------