From 8e5395ef7ad903fdde779c44de089f8ddd0e8b25 Mon Sep 17 00:00:00 2001 From: Evan Date: Wed, 1 Apr 2026 17:22:55 +0800 Subject: [PATCH 01/21] lock node dependecies --- .gitignore | 1 - README.md | 2 +- package-lock.json | 241 +++ package.json | 9 +- soldeer.lock | 52 + yarn-error.log | 4002 --------------------------------------------- 6 files changed, 299 insertions(+), 4008 deletions(-) create mode 100644 package-lock.json create mode 100644 soldeer.lock delete mode 100644 yarn-error.log diff --git a/.gitignore b/.gitignore index f8b2cb8c..a380d1f2 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,4 @@ ignition/deployments/chain-31337 # Soldeer /dependencies -soldeer.lock .DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 504bdc67..1d7e2f25 100644 --- a/README.md +++ b/README.md @@ -76,5 +76,5 @@ Add configurations to your .vscode/settings.json ``` ```shell -$ yarn +$ npm ci ``` diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..b70fab64 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,241 @@ +{ + "name": "termmax-contract", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "MIT", + "devDependencies": { + "prettier": "3.5.3", + "prettier-plugin-solidity": "1.4.3", + "ts-node": "10.9.2", + "typescript": "5.8.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.20.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.21", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/prettier": { + "version": "3.5.3", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "version": "1.4.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.20.1", + "semver": "^7.7.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json index de7a7937..a705fc50 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { "license": "MIT", + "packageManager": "npm@10.9.2", "devDependencies": { - "prettier": "^3.3.3", - "prettier-plugin-solidity": "^1.4.1", - "ts-node": ">=8.0.0", - "typescript": ">=4.5.0" + "prettier": "3.5.3", + "prettier-plugin-solidity": "1.4.3", + "ts-node": "10.9.2", + "typescript": "5.8.3" } } diff --git a/soldeer.lock b/soldeer.lock new file mode 100644 index 00000000..7f7a8bcf --- /dev/null +++ b/soldeer.lock @@ -0,0 +1,52 @@ +[[dependencies]] +name = "@chainlink-contracts" +version = "v1.12.0" +git = "https://github.com/smartcontractkit/chainlink.git" +rev = "b57617ed2249ac711db75e5bef5a0a78bf10b2aa" + +[[dependencies]] +name = "@openzeppelin-contracts" +version = "5.2.0" +url = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts/5_2_0_11-01-2025_09:30:20_contracts.zip" +checksum = "6dbd0440446b2ed16ca25e9f1af08fc0c5c1e73e71fee86ae8a00daa774e3817" +integrity = "4cb7f3777f67fdf4b7d0e2f94d2f93f198b2e5dce718b7062ac7c2c83e1183bd" + +[[dependencies]] +name = "@openzeppelin-contracts-upgradeable" +version = "5.2.0" +url = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts-upgradeable/5_2_0_11-01-2025_09:30:25_contracts-upgradeable.zip" +checksum = "25d9cf22b6f4d8da7975f24234eefbf6c71348464ea74c8fdd481be3811767f5" +integrity = "498747bedc3f757976da0b6125d26a63e79bb2b4dbabd8ecd2547e809a2fa27e" + +[[dependencies]] +name = "@uniswap-v3-core" +version = "1.0.2-solc-0.8-simulate" +url = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v3-core/1_0_2-solc-0_8-simulate_22-01-2024_13:19:54_v3-core.zip" +checksum = "68949c67a4f22044e4c8dc716362b6d79b07e8990e720bec9b116f54b233ef57" +integrity = "697a089ffe197580b6cfe07f0c4dd8a35da0836fd1d9e522f73efda4b7314e01" + +[[dependencies]] +name = "@uniswap-v3-periphery" +version = "1.4.4" +url = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v3-periphery/1_4_4_22-01-2024_13:20:51_v3-periphery.zip" +checksum = "f1ce151585a084bb3ec6fb9cbce4520924d41398c3ce8979169de6f7f70d6a81" +integrity = "e101a06117b3274cd21a3032fa9a55446e842dc0e0e1b0b25008e094a446c453" + +[[dependencies]] +name = "forge-std" +version = "1.9.6" +url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/1_9_6_01-02-2025_20:49:10_forge-std-1.9.zip" +checksum = "55f341818321b3f925161a72fd0dcd62e4a0a4b66785a7a932bf2bfaf96fb9d1" +integrity = "e9ecdc364d152157431e5df5aa041ffddbe9bb1c1ad81634b1e72df9e23814e8" + +[[dependencies]] +name = "metamorpho" +version = "1.0.0" +git = "https://github.com/morpho-org/metamorpho.git" +rev = "00da9ad27da8051bce663eeac02f3b9c0c0aa8d8" + +[[dependencies]] +name = "pendle-core-v2" +version = "1.0.0" +git = "https://github.com/pendle-finance/pendle-core-v2-public.git" +rev = "d3dafee28062c7ee14bc2471fa0d6b4a4bc2569f" diff --git a/yarn-error.log b/yarn-error.log deleted file mode 100644 index 7f9e8be9..00000000 --- a/yarn-error.log +++ /dev/null @@ -1,4002 +0,0 @@ -Arguments: - /usr/local/node18/bin/node /usr/local/node18/bin/yarn add @chainlink/contracts --dev - -PATH: - /home/evan/.local/share/solana/install/active_release/bin:/usr/local/node18/bin:/home/evan/.local/share/solana/install/active_release/bin:/home/evan/.cargo/bin:/home/evan/.nvm/versions/node/v18.18.2/bin:/usr/local/node18/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin:/usr/local/go/bin:/home/evan/Desktop/bitcoin/bin:/home/evan/.zokrates/bin:/home/evan/.local/bin:/usr/local/go/bin:/home/evan/Desktop/bitcoin/bin:/home/evan/.zokrates/bin:/home/evan/.local/bin:/home/evan/.local/bin:/home/evan/.foundry/bin - -Yarn version: - 1.22.19 - -Node version: - 18.16.0 - -Platform: - linux x64 - -Trace: - Error: connect ECONNREFUSED 104.16.28.34:443 - at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16) - -npm manifest: - { - "devDependencies": { - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-ignition": "^0.15.0", - "@nomicfoundation/hardhat-ignition-ethers": "^0.15.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-toolbox": "^5.0.0", - "@nomicfoundation/hardhat-verify": "^2.0.0", - "@openzeppelin/contracts": "^5.0.2", - "@openzeppelin/contracts-upgradeable": "^5.0.2", - "@typechain/ethers-v6": "^0.5.0", - "@typechain/hardhat": "^9.0.0", - "@types/chai": "^4.2.0", - "@types/mocha": ">=9.1.0", - "@types/node": ">=18.0.0", - "chai": "^4.2.0", - "dotenv": "^16.4.5", - "ethers": "^6.4.0", - "hardhat": "^2.22.11", - "hardhat-gas-reporter": "^1.0.8", - "prettier": "^3.3.3", - "prettier-plugin-solidity": "^1.4.1", - "solidity-coverage": "^0.8.0", - "ts-node": ">=8.0.0", - "typechain": "^8.3.0", - "typescript": ">=4.5.0" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@adraffy/ens-normalize@1.10.1": - version "1.10.1" - resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz" - integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== - - "@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== - dependencies: - "@jridgewell/trace-mapping" "0.3.9" - - "@ethereumjs/rlp@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz" - integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== - - "@ethereumjs/util@^8.1.0": - version "8.1.0" - resolved "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz" - integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== - dependencies: - "@ethereumjs/rlp" "^4.0.1" - ethereum-cryptography "^2.0.0" - micro-ftch "^0.3.1" - - "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.7.0", "@ethersproject/abi@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - - "@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - - "@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - - "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.7.0", "@ethersproject/address@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - - "@ethersproject/address@5.6.1": - version "5.6.1" - resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.1.tgz" - integrity sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q== - dependencies: - "@ethersproject/bignumber" "^5.6.2" - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.1" - - "@ethersproject/base64@^5.7.0", "@ethersproject/base64@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - - "@ethersproject/basex@^5.7.0", "@ethersproject/basex@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - - "@ethersproject/bignumber@^5.6.2", "@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - - "@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/constants@^5.7.0", "@ethersproject/constants@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - - "@ethersproject/contracts@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - - "@ethersproject/hash@^5.7.0", "@ethersproject/hash@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - - "@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - - "@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - - "@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - js-sha3 "0.8.0" - - "@ethersproject/logger@^5.6.0", "@ethersproject/logger@^5.7.0", "@ethersproject/logger@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - - "@ethersproject/networks@^5.7.0", "@ethersproject/networks@5.7.1": - version "5.7.1" - resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - - "@ethersproject/properties@^5.7.0", "@ethersproject/properties@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/providers@5.7.2": - version "5.7.2" - resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - - "@ethersproject/random@^5.7.0", "@ethersproject/random@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/rlp@^5.6.1", "@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - - "@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - - "@ethersproject/solidity@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - - "@ethersproject/strings@^5.7.0", "@ethersproject/strings@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - - "@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - - "@ethersproject/wallet@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - - "@ethersproject/web@^5.7.0", "@ethersproject/web@5.7.1": - version "5.7.1" - resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - - "@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - - "@fastify/busboy@^2.0.0": - version "2.1.1" - resolved "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz" - integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== - - "@jridgewell/resolve-uri@^3.0.3": - version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" - integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== - - "@jridgewell/sourcemap-codec@^1.4.10": - version "1.5.0" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz" - integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== - - "@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - - "@metamask/eth-sig-util@^4.0.0": - version "4.0.1" - resolved "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz" - integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== - dependencies: - ethereumjs-abi "^0.6.8" - ethereumjs-util "^6.2.1" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - - "@noble/curves@~1.4.0", "@noble/curves@1.4.2": - version "1.4.2" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz" - integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== - dependencies: - "@noble/hashes" "1.4.0" - - "@noble/curves@1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz" - integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== - dependencies: - "@noble/hashes" "1.3.2" - - "@noble/hashes@^1.4.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz" - integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== - - "@noble/hashes@~1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== - - "@noble/hashes@~1.4.0", "@noble/hashes@1.4.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz" - integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== - - "@noble/hashes@1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== - - "@noble/hashes@1.3.2": - version "1.3.2" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== - - "@noble/secp256k1@~1.7.0", "@noble/secp256k1@1.7.1": - version "1.7.1" - resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" - integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== - - "@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - - "@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": - version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - - "@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - - "@nomicfoundation/edr-darwin-arm64@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz" - integrity sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A== - - "@nomicfoundation/edr-darwin-x64@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz" - integrity sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg== - - "@nomicfoundation/edr-linux-arm64-gnu@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz" - integrity sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA== - - "@nomicfoundation/edr-linux-arm64-musl@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz" - integrity sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg== - - "@nomicfoundation/edr-linux-x64-gnu@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz" - integrity sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A== - - "@nomicfoundation/edr-linux-x64-musl@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz" - integrity sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA== - - "@nomicfoundation/edr-win32-x64-msvc@0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz" - integrity sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w== - - "@nomicfoundation/edr@^0.5.2": - version "0.5.2" - resolved "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.5.2.tgz" - integrity sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw== - dependencies: - "@nomicfoundation/edr-darwin-arm64" "0.5.2" - "@nomicfoundation/edr-darwin-x64" "0.5.2" - "@nomicfoundation/edr-linux-arm64-gnu" "0.5.2" - "@nomicfoundation/edr-linux-arm64-musl" "0.5.2" - "@nomicfoundation/edr-linux-x64-gnu" "0.5.2" - "@nomicfoundation/edr-linux-x64-musl" "0.5.2" - "@nomicfoundation/edr-win32-x64-msvc" "0.5.2" - - "@nomicfoundation/ethereumjs-common@4.0.4": - version "4.0.4" - resolved "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz" - integrity sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg== - dependencies: - "@nomicfoundation/ethereumjs-util" "9.0.4" - - "@nomicfoundation/ethereumjs-rlp@5.0.4": - version "5.0.4" - resolved "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz" - integrity sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw== - - "@nomicfoundation/ethereumjs-tx@5.0.4": - version "5.0.4" - resolved "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz" - integrity sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw== - dependencies: - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - ethereum-cryptography "0.1.3" - - "@nomicfoundation/ethereumjs-util@9.0.4": - version "9.0.4" - resolved "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz" - integrity sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q== - dependencies: - "@nomicfoundation/ethereumjs-rlp" "5.0.4" - ethereum-cryptography "0.1.3" - - "@nomicfoundation/hardhat-chai-matchers@^2.0.0": - version "2.0.8" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz" - integrity sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg== - dependencies: - "@types/chai-as-promised" "^7.1.3" - chai-as-promised "^7.1.1" - deep-eql "^4.0.1" - ordinal "^1.0.3" - - "@nomicfoundation/hardhat-ethers@^3.0.0", "@nomicfoundation/hardhat-ethers@^3.0.4": - version "3.0.8" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz" - integrity sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA== - dependencies: - debug "^4.1.1" - lodash.isequal "^4.5.0" - - "@nomicfoundation/hardhat-ignition-ethers@^0.15.0": - version "0.15.5" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.5.tgz" - integrity sha512-W6s1QN9CFxzSVZS6w9Jcj3WLaK32z2FP5MxNU2OKY1Fn9ZzLr+miXbUbWYuRHl6dxrrl6sE8cv33Cybv19pmCg== - - "@nomicfoundation/hardhat-ignition@^0.15.0", "@nomicfoundation/hardhat-ignition@^0.15.5": - version "0.15.5" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.5.tgz" - integrity sha512-Y5nhFXFqt4owA6Ooag8ZBFDF2RAZElMXViknVIsi3m45pbQimS50ti6FU8HxfRkDnBARa40CIn7UGV0hrelzDw== - dependencies: - "@nomicfoundation/ignition-core" "^0.15.5" - "@nomicfoundation/ignition-ui" "^0.15.5" - chalk "^4.0.0" - debug "^4.3.2" - fs-extra "^10.0.0" - prompts "^2.4.2" - - "@nomicfoundation/hardhat-network-helpers@^1.0.0": - version "1.0.12" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz" - integrity sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA== - dependencies: - ethereumjs-util "^7.1.4" - - "@nomicfoundation/hardhat-toolbox@^5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-5.0.0.tgz" - integrity sha512-FnUtUC5PsakCbwiVNsqlXVIWG5JIb5CEZoSXbJUsEBun22Bivx2jhF1/q9iQbzuaGpJKFQyOhemPB2+XlEE6pQ== - - "@nomicfoundation/hardhat-verify@^2.0.0", "@nomicfoundation/hardhat-verify@^2.0.1": - version "2.0.11" - resolved "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.11.tgz" - integrity sha512-lGIo4dNjVQFdsiEgZp3KP6ntLiF7xJEJsbNHfSyIiFCyI0Yv0518ElsFtMC5uCuHEChiBBMrib9jWQvHHT+X3Q== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@ethersproject/address" "^5.0.2" - cbor "^8.1.0" - chalk "^2.4.2" - debug "^4.1.1" - lodash.clonedeep "^4.5.0" - semver "^6.3.0" - table "^6.8.0" - undici "^5.14.0" - - "@nomicfoundation/ignition-core@^0.15.5": - version "0.15.5" - resolved "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.5.tgz" - integrity sha512-FgvuoIXhakRSP524JzNQ4BviyzBBKpsFaOWubPZ4XACLT4/7vGqlJ/7DIn0D2NL2anQ2qs98/BNBY9WccXUX1Q== - dependencies: - "@ethersproject/address" "5.6.1" - "@nomicfoundation/solidity-analyzer" "^0.1.1" - cbor "^9.0.0" - debug "^4.3.2" - ethers "^6.7.0" - fs-extra "^10.0.0" - immer "10.0.2" - lodash "4.17.21" - ndjson "2.0.0" - - "@nomicfoundation/ignition-ui@^0.15.5": - version "0.15.5" - resolved "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.5.tgz" - integrity sha512-ZcE4rIn10qKahR4OqS8rl8NM2Fbg2QYiBXgMgj74ZI0++LlCcZgB5HyaBbX+lsnKHjTXtjYD3b+2mtg7jFbAMQ== - - "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz" - integrity sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw== - - "@nomicfoundation/solidity-analyzer-darwin-x64@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.2.tgz" - integrity sha512-fZNmVztrSXC03e9RONBT+CiksSeYcxI1wlzqyr0L7hsQlK1fzV+f04g2JtQ1c/Fe74ZwdV6aQBdd6Uwl1052sw== - - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.2.tgz" - integrity sha512-3d54oc+9ZVBuB6nbp8wHylk4xh0N0Gc+bk+/uJae+rUgbOBwQSfuGIbAZt1wBXs5REkSmynEGcqx6DutoK0tPA== - - "@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.2.tgz" - integrity sha512-iDJfR2qf55vgsg7BtJa7iPiFAsYf2d0Tv/0B+vhtnI16+wfQeTbP7teookbGvAo0eJo7aLLm0xfS/GTkvHIucA== - - "@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.2.tgz" - integrity sha512-9dlHMAt5/2cpWyuJ9fQNOUXFB/vgSFORg1jpjX1Mh9hJ/MfZXlDdHQ+DpFCs32Zk5pxRBb07yGvSHk9/fezL+g== - - "@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.2.tgz" - integrity sha512-GzzVeeJob3lfrSlDKQw2bRJ8rBf6mEYaWY+gW0JnTDHINA0s2gPR4km5RLIj1xeZZOYz4zRw+AEeYgLRqB2NXg== - - "@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.2.tgz" - integrity sha512-Fdjli4DCcFHb4Zgsz0uEJXZ2K7VEO+w5KVv7HmT7WO10iODdU9csC2az4jrhEsRtiR9Gfd74FlG0NYlw1BMdyA== - - "@nomicfoundation/solidity-analyzer@^0.1.0", "@nomicfoundation/solidity-analyzer@^0.1.1": - version "0.1.2" - resolved "https://registry.npmjs.org/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.2.tgz" - integrity sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA== - optionalDependencies: - "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.2" - "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.2" - "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.2" - "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.2" - "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.2" - "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.2" - "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.2" - - "@openzeppelin/contracts-upgradeable@^5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz" - integrity sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ== - - "@openzeppelin/contracts@^5.0.2", "@openzeppelin/contracts@5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.2.tgz" - integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== - - "@scure/base@~1.1.0", "@scure/base@~1.1.6": - version "1.1.9" - resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz" - integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== - - "@scure/bip32@1.1.5": - version "1.1.5" - resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz" - integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== - dependencies: - "@noble/hashes" "~1.2.0" - "@noble/secp256k1" "~1.7.0" - "@scure/base" "~1.1.0" - - "@scure/bip32@1.4.0": - version "1.4.0" - resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz" - integrity sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg== - dependencies: - "@noble/curves" "~1.4.0" - "@noble/hashes" "~1.4.0" - "@scure/base" "~1.1.6" - - "@scure/bip39@1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz" - integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== - dependencies: - "@noble/hashes" "~1.2.0" - "@scure/base" "~1.1.0" - - "@scure/bip39@1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz" - integrity sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ== - dependencies: - "@noble/hashes" "~1.4.0" - "@scure/base" "~1.1.6" - - "@sentry/core@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz" - integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/minimal" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - - "@sentry/hub@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz" - integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== - dependencies: - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - - "@sentry/minimal@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz" - integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/types" "5.30.0" - tslib "^1.9.3" - - "@sentry/node@^5.18.1": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz" - integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== - dependencies: - "@sentry/core" "5.30.0" - "@sentry/hub" "5.30.0" - "@sentry/tracing" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - cookie "^0.4.1" - https-proxy-agent "^5.0.0" - lru_map "^0.3.3" - tslib "^1.9.3" - - "@sentry/tracing@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz" - integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== - dependencies: - "@sentry/hub" "5.30.0" - "@sentry/minimal" "5.30.0" - "@sentry/types" "5.30.0" - "@sentry/utils" "5.30.0" - tslib "^1.9.3" - - "@sentry/types@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz" - integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== - - "@sentry/utils@5.30.0": - version "5.30.0" - resolved "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz" - integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== - dependencies: - "@sentry/types" "5.30.0" - tslib "^1.9.3" - - "@solidity-parser/parser@^0.14.0": - version "0.14.5" - resolved "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz" - integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== - dependencies: - antlr4ts "^0.5.0-alpha.4" - - "@solidity-parser/parser@^0.18.0": - version "0.18.0" - resolved "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz" - integrity sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA== - - "@tsconfig/node10@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" - integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== - - "@tsconfig/node12@^1.0.7": - version "1.0.11" - resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" - integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== - - "@tsconfig/node14@^1.0.0": - version "1.0.3" - resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" - integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== - - "@tsconfig/node16@^1.0.2": - version "1.0.4" - resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" - integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== - - "@typechain/ethers-v6@^0.5.0", "@typechain/ethers-v6@^0.5.1": - version "0.5.1" - resolved "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz" - integrity sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA== - dependencies: - lodash "^4.17.15" - ts-essentials "^7.0.1" - - "@typechain/hardhat@^9.0.0": - version "9.1.0" - resolved "https://registry.npmjs.org/@typechain/hardhat/-/hardhat-9.1.0.tgz" - integrity sha512-mtaUlzLlkqTlfPwB3FORdejqBskSnh+Jl8AIJGjXNAQfRQ4ofHADPl1+oU7Z3pAJzmZbUXII8MhOLQltcHgKnA== - dependencies: - fs-extra "^9.1.0" - - "@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - - "@types/bn.js@^5.1.0": - version "5.1.6" - resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz" - integrity sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w== - dependencies: - "@types/node" "*" - - "@types/chai-as-promised@^7.1.3": - version "7.1.8" - resolved "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz" - integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== - dependencies: - "@types/chai" "*" - - "@types/chai@*", "@types/chai@^4.2.0": - version "4.3.19" - resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz" - integrity sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw== - - "@types/concat-stream@^1.6.0": - version "1.6.1" - resolved "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz" - integrity sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA== - dependencies: - "@types/node" "*" - - "@types/form-data@0.0.33": - version "0.0.33" - resolved "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz" - integrity sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw== - dependencies: - "@types/node" "*" - - "@types/glob@^7.1.1": - version "7.2.0" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" - integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - - "@types/lru-cache@^5.1.0": - version "5.1.1" - resolved "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz" - integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== - - "@types/minimatch@*": - version "5.1.2" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" - integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== - - "@types/mocha@>=9.1.0": - version "10.0.8" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz" - integrity sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw== - - "@types/node@*", "@types/node@>=18.0.0": - version "22.5.5" - resolved "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz" - integrity sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA== - dependencies: - undici-types "~6.19.2" - - "@types/node@^10.0.3": - version "10.17.60" - resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz" - integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== - - "@types/node@^8.0.0": - version "8.10.66" - resolved "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz" - integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== - - "@types/node@18.15.13": - version "18.15.13" - resolved "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz" - integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== - - "@types/pbkdf2@^3.0.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz" - integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== - dependencies: - "@types/node" "*" - - "@types/prettier@^2.1.1": - version "2.7.3" - resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== - - "@types/qs@^6.2.31": - version "6.9.16" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz" - integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== - - "@types/secp256k1@^4.0.1": - version "4.0.6" - resolved "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz" - integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== - dependencies: - "@types/node" "*" - - abbrev@1: - version "1.1.1" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - - abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" - integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== - - acorn-walk@^8.1.1: - version "8.3.4" - resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== - dependencies: - acorn "^8.11.0" - - acorn@^8.11.0, acorn@^8.4.1: - version "8.12.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - - adm-zip@^0.4.16: - version "0.4.16" - resolved "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz" - integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== - - aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - - aes-js@4.0.0-beta.5: - version "4.0.0-beta.5" - resolved "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz" - integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== - - agent-base@6: - version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - - aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - - ajv@^8.0.1: - version "8.17.1" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz" - integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== - dependencies: - fast-deep-equal "^3.1.3" - fast-uri "^3.0.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - - amdefine@>=0.0.4: - version "1.0.1" - resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz" - integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg== - - ansi-align@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz" - integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== - dependencies: - string-width "^4.1.0" - - ansi-colors@^4.1.1, ansi-colors@^4.1.3: - version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - - ansi-escapes@^4.3.0: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - - ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - - ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - - ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - - ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - - antlr4ts@^0.5.0-alpha.4: - version "0.5.0-alpha.4" - resolved "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz" - integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== - - anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - - arg@^4.1.0: - version "4.1.3" - resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - - argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - - argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - - array-back@^3.0.1, array-back@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz" - integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== - - array-back@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - - array-back@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz" - integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== - - array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - - array-uniq@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" - integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== - - asap@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz" - integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== - - assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - - astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - - async@1.x: - version "1.5.2" - resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz" - integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== - - asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - - at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - - axios@^1.5.1: - version "1.7.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz" - integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - - balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - - base-x@^3.0.2: - version "3.0.10" - resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz" - integrity sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ== - dependencies: - safe-buffer "^5.0.1" - - bech32@1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - - binary-extensions@^2.0.0: - version "2.3.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" - integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== - - blakejs@^1.1.0: - version "1.2.1" - resolved "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - - bn.js@^4.11.0: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - - bn.js@^4.11.8: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - - bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - - bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - - bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz" - integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== - - boxen@^5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz" - integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== - dependencies: - ansi-align "^3.0.0" - camelcase "^6.2.0" - chalk "^4.1.0" - cli-boxes "^2.2.1" - string-width "^4.2.2" - type-fest "^0.20.2" - widest-line "^3.1.0" - wrap-ansi "^7.0.0" - - brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - - brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - - braces@^3.0.3, braces@~3.0.2: - version "3.0.3" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" - integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== - dependencies: - fill-range "^7.1.1" - - brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - - browser-stdout@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - - browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - - bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== - dependencies: - base-x "^3.0.2" - - bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - - buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - - buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - - bytes@3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - - call-bind@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - - camelcase@^6.0.0, camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - - caseless@^0.12.0, caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== - - cbor@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz" - integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== - dependencies: - nofilter "^3.1.0" - - cbor@^9.0.0: - version "9.0.2" - resolved "https://registry.npmjs.org/cbor/-/cbor-9.0.2.tgz" - integrity sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ== - dependencies: - nofilter "^3.1.0" - - chai-as-promised@^7.1.1: - version "7.1.2" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz" - integrity sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw== - dependencies: - check-error "^1.0.2" - - chai@^4.2.0, "chai@>= 2.1.2 < 6": - version "4.5.0" - resolved "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz" - integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.1.0" - - chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - - chalk@^4.0.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - "charenc@>= 0.0.1": - version "0.0.2" - resolved "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz" - integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== - - check-error@^1.0.2, check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" - - chokidar@^3.5.3: - version "3.6.0" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - - chokidar@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz" - integrity sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA== - dependencies: - readdirp "^4.0.1" - - ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - - cli-boxes@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz" - integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== - - cli-table3@^0.5.0: - version "0.5.1" - resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz" - integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== - dependencies: - object-assign "^4.1.0" - string-width "^2.1.1" - optionalDependencies: - colors "^1.1.2" - - cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - - color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - - color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - - color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - - color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - - colors@^1.1.2, colors@1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - - combined-stream@^1.0.6, combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - - command-exists@^1.2.8: - version "1.2.9" - resolved "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz" - integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== - - command-line-args@^5.1.1: - version "5.2.1" - resolved "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz" - integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== - dependencies: - array-back "^3.1.0" - find-replace "^3.0.0" - lodash.camelcase "^4.3.0" - typical "^4.0.0" - - command-line-usage@^6.1.0: - version "6.1.3" - resolved "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz" - integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== - dependencies: - array-back "^4.0.2" - chalk "^2.4.2" - table-layout "^1.0.2" - typical "^5.2.0" - - commander@^8.1.0: - version "8.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - - concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - - concat-stream@^1.6.0, concat-stream@^1.6.2: - version "1.6.2" - resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - - cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - - core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - - create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - - "crypt@>= 0.0.1": - version "0.0.2" - resolved "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz" - integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== - - death@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/death/-/death-1.1.0.tgz" - integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== - - debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.5, debug@4: - version "4.3.7" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz" - integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== - dependencies: - ms "^2.1.3" - - decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - - deep-eql@^4.0.1, deep-eql@^4.1.3: - version "4.1.4" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz" - integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== - dependencies: - type-detect "^4.0.0" - - deep-extend@~0.6.0: - version "0.6.0" - resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - - deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - - define-data-property@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" - integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - gopd "^1.0.1" - - delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - - depd@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - - diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - - diff@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz" - integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== - - difflib@^0.2.4: - version "0.2.4" - resolved "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz" - integrity sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w== - dependencies: - heap ">= 0.2.0" - - dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - - dotenv@^16.4.5: - version "16.4.5" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" - integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== - - elliptic@^6.5.2, elliptic@^6.5.4: - version "6.5.7" - resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz" - integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - - elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - - emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - - enquirer@^2.3.0: - version "2.4.1" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" - integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== - dependencies: - ansi-colors "^4.1.1" - strip-ansi "^6.0.1" - - env-paths@^2.2.0: - version "2.2.1" - resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" - integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== - - es-define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" - integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== - dependencies: - get-intrinsic "^1.2.4" - - es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - - escalade@^3.1.1: - version "3.2.0" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" - integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== - - escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - - escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - - escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz" - integrity sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A== - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - - esprima@^2.7.1, esprima@2.7.x: - version "2.7.3" - resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz" - integrity sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A== - - esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - - estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" - integrity sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA== - - esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - - eth-gas-reporter@^0.2.25: - version "0.2.27" - resolved "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz" - integrity sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw== - dependencies: - "@solidity-parser/parser" "^0.14.0" - axios "^1.5.1" - cli-table3 "^0.5.0" - colors "1.4.0" - ethereum-cryptography "^1.0.3" - ethers "^5.7.2" - fs-readdir-recursive "^1.1.0" - lodash "^4.17.14" - markdown-table "^1.1.3" - mocha "^10.2.0" - req-cwd "^2.0.0" - sha1 "^1.1.1" - sync-request "^6.0.0" - - ethereum-bloom-filters@^1.0.6: - version "1.2.0" - resolved "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.2.0.tgz" - integrity sha512-28hyiE7HVsWubqhpVLVmZXFd4ITeHi+BUu05o9isf0GUpMtzBUi+8/gFrGaGYzvGAJQmJ3JKj77Mk9G98T84rA== - dependencies: - "@noble/hashes" "^1.4.0" - - ethereum-cryptography@^0.1.3, ethereum-cryptography@0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - - ethereum-cryptography@^1.0.3: - version "1.2.0" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz" - integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== - dependencies: - "@noble/hashes" "1.2.0" - "@noble/secp256k1" "1.7.1" - "@scure/bip32" "1.1.5" - "@scure/bip39" "1.1.1" - - ethereum-cryptography@^2.0.0: - version "2.2.1" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz" - integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== - dependencies: - "@noble/curves" "1.4.2" - "@noble/hashes" "1.4.0" - "@scure/bip32" "1.4.0" - "@scure/bip39" "1.3.0" - - ethereum-cryptography@^2.1.2: - version "2.2.1" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz" - integrity sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg== - dependencies: - "@noble/curves" "1.4.2" - "@noble/hashes" "1.4.0" - "@scure/bip32" "1.4.0" - "@scure/bip39" "1.3.0" - - ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz" - integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - - ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - - ethereumjs-util@^7.1.4: - version "7.1.5" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" - integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - - ethers@^5.7.2: - version "5.7.2" - resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - - ethers@^6.1.0, ethers@^6.4.0, ethers@^6.7.0, ethers@6.x: - version "6.13.2" - resolved "https://registry.npmjs.org/ethers/-/ethers-6.13.2.tgz" - integrity sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.17.1" - - ethjs-unit@0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz" - integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== - dependencies: - bn.js "4.11.6" - number-to-bn "1.7.0" - - ethjs-util@^0.1.6, ethjs-util@0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - - evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - - fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - - fast-glob@^3.0.3: - version "3.3.2" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - - fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - - fast-uri@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz" - integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== - - fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - - fill-range@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" - integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== - dependencies: - to-regex-range "^5.0.1" - - find-replace@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz" - integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== - dependencies: - array-back "^3.0.1" - - find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - - find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - - flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - - follow-redirects@^1.12.1, follow-redirects@^1.15.6: - version "1.15.9" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz" - integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== - - form-data@^2.2.0: - version "2.5.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - - form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - - fp-ts@^1.0.0: - version "1.19.5" - resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.5.tgz" - integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== - - fp-ts@1.19.3: - version "1.19.3" - resolved "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz" - integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== - - fs-extra@^10.0.0: - version "10.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz" - integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - - fs-extra@^7.0.0: - version "7.0.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-extra@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz" - integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - - fs-readdir-recursive@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz" - integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== - - fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - - function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - - get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - - get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - - get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - - get-port@^3.1.0: - version "3.2.0" - resolved "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz" - integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== - - ghost-testrpc@^0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz" - integrity sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ== - dependencies: - chalk "^2.4.2" - node-emoji "^1.10.0" - - glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - - glob@^5.0.15: - version "5.0.15" - resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz" - integrity sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA== - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@^7.0.0, glob@^7.1.3: - version "7.2.3" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz" - integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^5.0.1" - once "^1.3.0" - - glob@7.1.7: - version "7.1.7" - resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - global-modules@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz" - integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== - dependencies: - global-prefix "^3.0.0" - - global-prefix@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz" - integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== - dependencies: - ini "^1.3.5" - kind-of "^6.0.2" - which "^1.3.1" - - globby@^10.0.1: - version "10.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz" - integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" - slash "^3.0.0" - - gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - - graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" - integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== - - handlebars@^4.0.1: - version "4.7.8" - resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz" - integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.2" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - - hardhat-gas-reporter@^1.0.8: - version "1.0.10" - resolved "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.10.tgz" - integrity sha512-02N4+So/fZrzJ88ci54GqwVA3Zrf0C9duuTyGt0CFRIh/CdNwbnTgkXkRfojOMLBQ+6t+lBIkgbsOtqMvNwikA== - dependencies: - array-uniq "1.0.3" - eth-gas-reporter "^0.2.25" - sha1 "^1.1.1" - - hardhat@^2.0.0, hardhat@^2.0.2, hardhat@^2.0.4, hardhat@^2.11.0, hardhat@^2.18.0, hardhat@^2.22.11, hardhat@^2.9.4, hardhat@^2.9.5, hardhat@^2.9.9: - version "2.22.11" - resolved "https://registry.npmjs.org/hardhat/-/hardhat-2.22.11.tgz" - integrity sha512-g9xr6BGXbzj2sqG9AjHwqeUOS9v2NwLbuq7rsdjMB2RLWmYp8IFdZnzq8UewwLJisuWgiygB+dwLktjqAbRuOw== - dependencies: - "@ethersproject/abi" "^5.1.2" - "@metamask/eth-sig-util" "^4.0.0" - "@nomicfoundation/edr" "^0.5.2" - "@nomicfoundation/ethereumjs-common" "4.0.4" - "@nomicfoundation/ethereumjs-tx" "5.0.4" - "@nomicfoundation/ethereumjs-util" "9.0.4" - "@nomicfoundation/solidity-analyzer" "^0.1.0" - "@sentry/node" "^5.18.1" - "@types/bn.js" "^5.1.0" - "@types/lru-cache" "^5.1.0" - adm-zip "^0.4.16" - aggregate-error "^3.0.0" - ansi-escapes "^4.3.0" - boxen "^5.1.2" - chalk "^2.4.2" - chokidar "^4.0.0" - ci-info "^2.0.0" - debug "^4.1.1" - enquirer "^2.3.0" - env-paths "^2.2.0" - ethereum-cryptography "^1.0.3" - ethereumjs-abi "^0.6.8" - find-up "^2.1.0" - fp-ts "1.19.3" - fs-extra "^7.0.1" - glob "7.2.0" - immutable "^4.0.0-rc.12" - io-ts "1.10.4" - json-stream-stringify "^3.1.4" - keccak "^3.0.2" - lodash "^4.17.11" - mnemonist "^0.38.0" - mocha "^10.0.0" - p-map "^4.0.0" - raw-body "^2.4.1" - resolve "1.17.0" - semver "^6.3.0" - solc "0.8.26" - source-map-support "^0.5.13" - stacktrace-parser "^0.1.10" - tsort "0.0.1" - undici "^5.14.0" - uuid "^8.3.2" - ws "^7.4.6" - - has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" - integrity sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA== - - has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - - has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - - has-property-descriptors@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" - integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== - dependencies: - es-define-property "^1.0.0" - - has-proto@^1.0.1: - version "1.0.3" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== - - has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - - hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - - hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7, hash.js@1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - - hasown@^2.0.0, hasown@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" - integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== - dependencies: - function-bind "^1.1.2" - - he@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - - "heap@>= 0.2.0": - version "0.2.7" - resolved "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz" - integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== - - hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - - http-basic@^8.1.1: - version "8.1.3" - resolved "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz" - integrity sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw== - dependencies: - caseless "^0.12.0" - concat-stream "^1.6.2" - http-response-object "^3.0.1" - parse-cache-control "^1.0.1" - - http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - - http-response-object@^3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz" - integrity sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA== - dependencies: - "@types/node" "^10.0.3" - - https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - - iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - - ignore@^5.1.1: - version "5.3.2" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" - integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== - - immer@10.0.2: - version "10.0.2" - resolved "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz" - integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA== - - immutable@^4.0.0-rc.12: - version "4.3.7" - resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz" - integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw== - - indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - - inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - - inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - - ini@^1.3.5: - version "1.3.8" - resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== - - interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - - io-ts@1.10.4: - version "1.10.4" - resolved "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz" - integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== - dependencies: - fp-ts "^1.0.0" - - is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - - is-core-module@^2.13.0: - version "2.15.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz" - integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== - dependencies: - hasown "^2.0.2" - - is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - - is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" - integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== - - is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - - is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - - is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz" - integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== - - is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - - is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - - is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - - isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - - isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - - js-sha3@^0.8.0, js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - - js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - - js-yaml@3.x: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - - json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - - json-stream-stringify@^3.1.4: - version "3.1.4" - resolved "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.4.tgz" - integrity sha512-oGoz05ft577LolnXFQHD2CjnXDxXVA5b8lHwfEZgRXQUZeCMo6sObQQRq+NXuHQ3oTeMZHHmmPY2rjVwyqR62A== - - json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - - jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" - integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== - optionalDependencies: - graceful-fs "^4.1.6" - - jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - - jsonschema@^1.2.4: - version "1.4.1" - resolved "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz" - integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== - - keccak@^3.0.0, keccak@^3.0.2: - version "3.0.4" - resolved "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz" - integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - - kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - - kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - - levn@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - - locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - - locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - - lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz" - integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== - - lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz" - integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== - - lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - - lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" - integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== - - lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21, lodash@4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - - log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - - loupe@^2.3.6: - version "2.3.7" - resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== - dependencies: - get-func-name "^2.0.1" - - lru_map@^0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz" - integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== - - make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - - markdown-table@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz" - integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== - - md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - - memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz" - integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== - - merge2@^1.2.3, merge2@^1.3.0: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - - micro-ftch@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz" - integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== - - micromatch@^4.0.4: - version "4.0.8" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz" - integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== - dependencies: - braces "^3.0.3" - picomatch "^2.3.1" - - mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - - mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - - minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - - minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, "minimatch@2 || 3": - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - - minimatch@^5.0.1, minimatch@^5.1.6: - version "5.1.6" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - - minimist@^1.2.5, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - - mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - - mkdirp@0.5.x: - version "0.5.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - - mnemonist@^0.38.0: - version "0.38.5" - resolved "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz" - integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== - dependencies: - obliterator "^2.0.0" - - mocha@^10.0.0, mocha@^10.2.0: - version "10.7.3" - resolved "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz" - integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== - dependencies: - ansi-colors "^4.1.3" - browser-stdout "^1.3.1" - chokidar "^3.5.3" - debug "^4.3.5" - diff "^5.2.0" - escape-string-regexp "^4.0.0" - find-up "^5.0.0" - glob "^8.1.0" - he "^1.2.0" - js-yaml "^4.1.0" - log-symbols "^4.1.0" - minimatch "^5.1.6" - ms "^2.1.3" - serialize-javascript "^6.0.2" - strip-json-comments "^3.1.1" - supports-color "^8.1.1" - workerpool "^6.5.1" - yargs "^16.2.0" - yargs-parser "^20.2.9" - yargs-unparser "^2.0.0" - - ms@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - - ndjson@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz" - integrity sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ== - dependencies: - json-stringify-safe "^5.0.1" - minimist "^1.2.5" - readable-stream "^3.6.0" - split2 "^3.0.0" - through2 "^4.0.0" - - neo-async@^2.6.2: - version "2.6.2" - resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - - node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - - node-emoji@^1.10.0: - version "1.11.0" - resolved "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz" - integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== - dependencies: - lodash "^4.17.21" - - node-gyp-build@^4.2.0: - version "4.8.2" - resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz" - integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw== - - nofilter@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz" - integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== - - nopt@3.x: - version "3.0.6" - resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" - integrity sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg== - dependencies: - abbrev "1" - - normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - - number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz" - integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - - object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - - object-inspect@^1.13.1: - version "1.13.2" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz" - integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== - - obliterator@^2.0.0: - version "2.0.4" - resolved "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz" - integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== - - once@^1.3.0, once@1.x: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - - optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - - ordinal@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/ordinal/-/ordinal-1.0.3.tgz" - integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== - - os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - - p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - - p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - - p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== - dependencies: - p-limit "^1.1.0" - - p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - - p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - - p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - - parse-cache-control@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz" - integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== - - path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" - integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== - - path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - - path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - - path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - - path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - - pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - - pbkdf2@^3.0.17: - version "3.1.2" - resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - - pify@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - - prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== - - prettier-plugin-solidity@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz" - integrity sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg== - dependencies: - "@solidity-parser/parser" "^0.18.0" - semver "^7.5.4" - - prettier@^2.3.1: - version "2.8.8" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - - prettier@^3.3.3, prettier@>=2.3.0: - version "3.3.3" - resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" - integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== - - process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - - promise@^8.0.0: - version "8.3.0" - resolved "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz" - integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== - dependencies: - asap "~2.0.6" - - prompts@^2.4.2: - version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - - proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - - qs@^6.4.0: - version "6.13.0" - resolved "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz" - integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== - dependencies: - side-channel "^1.0.6" - - queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - - randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - - raw-body@^2.4.1: - version "2.5.2" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" - integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - - readable-stream@^2.2.2: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - - readable-stream@^3.0.0, readable-stream@^3.6.0, readable-stream@3: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - - readdirp@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz" - integrity sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw== - - readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - - rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" - integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== - dependencies: - resolve "^1.1.6" - - recursive-readdir@^2.2.2: - version "2.2.3" - resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz" - integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== - dependencies: - minimatch "^3.0.5" - - reduce-flatten@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz" - integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== - - req-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz" - integrity sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ== - dependencies: - req-from "^2.0.0" - - req-from@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz" - integrity sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA== - dependencies: - resolve-from "^3.0.0" - - require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - - require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - - resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz" - integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== - - resolve@^1.1.6: - version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - - resolve@1.1.x: - version "1.1.7" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" - integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== - - resolve@1.17.0: - version "1.17.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== - dependencies: - path-parse "^1.0.6" - - reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - - ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - - rlp@^2.2.3, rlp@^2.2.4: - version "2.2.7" - resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" - integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== - dependencies: - bn.js "^5.2.0" - - run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - - safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - - safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - - "safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - - sc-istanbul@^0.4.5: - version "0.4.6" - resolved "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz" - integrity sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g== - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" - - scrypt-js@^3.0.0, scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - - secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - - semver@^5.5.0: - version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - - semver@^6.3.0: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - - semver@^7.3.4: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - - semver@^7.5.4: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - - serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - - set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - - setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - - setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - - sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - sha1@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz" - integrity sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA== - dependencies: - charenc ">= 0.0.1" - crypt ">= 0.0.1" - - shelljs@^0.8.3: - version "0.8.5" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - - side-channel@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" - integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== - dependencies: - call-bind "^1.0.7" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - - sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - - slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - - slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - - solc@0.8.26: - version "0.8.26" - resolved "https://registry.npmjs.org/solc/-/solc-0.8.26.tgz" - integrity sha512-yiPQNVf5rBFHwN6SIf3TUUvVAFKcQqmSUFeq+fb6pNRCo0ZCgpYOZDi3BVoezCPIAcKrVYd/qXlBLUP9wVrZ9g== - dependencies: - command-exists "^1.2.8" - commander "^8.1.0" - follow-redirects "^1.12.1" - js-sha3 "0.8.0" - memorystream "^0.3.1" - semver "^5.5.0" - tmp "0.0.33" - - solidity-coverage@^0.8.0, solidity-coverage@^0.8.1: - version "0.8.13" - resolved "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.13.tgz" - integrity sha512-RiBoI+kF94V3Rv0+iwOj3HQVSqNzA9qm/qDP1ZDXK5IX0Cvho1qiz8hAXTsAo6KOIUeP73jfscq0KlLqVxzGWA== - dependencies: - "@ethersproject/abi" "^5.0.9" - "@solidity-parser/parser" "^0.18.0" - chalk "^2.4.2" - death "^1.1.0" - difflib "^0.2.4" - fs-extra "^8.1.0" - ghost-testrpc "^0.0.2" - global-modules "^2.0.0" - globby "^10.0.1" - jsonschema "^1.2.4" - lodash "^4.17.21" - mocha "^10.2.0" - node-emoji "^1.10.0" - pify "^4.0.1" - recursive-readdir "^2.2.2" - sc-istanbul "^0.4.5" - semver "^7.3.4" - shelljs "^0.8.3" - web3-utils "^1.3.6" - - source-map-support@^0.5.13: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - - source-map@^0.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - - source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz" - integrity sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA== - dependencies: - amdefine ">=0.0.4" - - split2@^3.0.0: - version "3.2.2" - resolved "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - - sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - - stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== - dependencies: - type-fest "^0.7.1" - - statuses@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - - string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - - string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - - string-format@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz" - integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== - - string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - - string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - - strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== - dependencies: - ansi-regex "^3.0.0" - - strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - - strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz" - integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== - dependencies: - is-hex-prefixed "1.0.0" - - strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - - supports-color@^3.1.0: - version "3.2.3" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz" - integrity sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A== - dependencies: - has-flag "^1.0.0" - - supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - - supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - - supports-color@^8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - - supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - - sync-request@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz" - integrity sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw== - dependencies: - http-response-object "^3.0.1" - sync-rpc "^1.2.1" - then-request "^6.0.0" - - sync-rpc@^1.2.1: - version "1.3.6" - resolved "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz" - integrity sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw== - dependencies: - get-port "^3.1.0" - - table-layout@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz" - integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== - dependencies: - array-back "^4.0.1" - deep-extend "~0.6.0" - typical "^5.2.0" - wordwrapjs "^4.0.0" - - table@^6.8.0: - version "6.8.2" - resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" - integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - - then-request@^6.0.0: - version "6.0.2" - resolved "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz" - integrity sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA== - dependencies: - "@types/concat-stream" "^1.6.0" - "@types/form-data" "0.0.33" - "@types/node" "^8.0.0" - "@types/qs" "^6.2.31" - caseless "~0.12.0" - concat-stream "^1.6.0" - form-data "^2.2.0" - http-basic "^8.1.1" - http-response-object "^3.0.1" - promise "^8.0.0" - qs "^6.4.0" - - through2@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - - tmp@0.0.33: - version "0.0.33" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - - to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - - toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - - ts-command-line-args@^2.2.0: - version "2.5.1" - resolved "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz" - integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== - dependencies: - chalk "^4.1.0" - command-line-args "^5.1.1" - command-line-usage "^6.1.0" - string-format "^2.0.0" - - ts-essentials@^7.0.1: - version "7.0.3" - resolved "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz" - integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== - - ts-node@*, ts-node@>=8.0.0: - version "10.9.2" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - - tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - - tslib@2.4.0: - version "2.4.0" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - - tsort@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz" - integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== - - tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - - tweetnacl@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - - type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" - integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== - dependencies: - prelude-ls "~1.1.2" - - type-detect@^4.0.0, type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - - type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - - type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - - type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz" - integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== - - typechain@^8.3.0, typechain@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz" - integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== - dependencies: - "@types/prettier" "^2.1.1" - debug "^4.3.1" - fs-extra "^7.0.0" - glob "7.1.7" - js-sha3 "^0.8.0" - lodash "^4.17.15" - mkdirp "^1.0.4" - prettier "^2.3.1" - ts-command-line-args "^2.2.0" - ts-essentials "^7.0.1" - - typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" - integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== - - typescript@*, typescript@>=2.7, typescript@>=3.7.0, typescript@>=4.3.0, typescript@>=4.5.0, typescript@>=4.7.0: - version "5.6.2" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz" - integrity sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw== - - typical@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz" - integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== - - typical@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz" - integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== - - uglify-js@^3.1.4: - version "3.19.3" - resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz" - integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== - - undici-types@~6.19.2: - version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== - - undici@^5.14.0: - version "5.28.4" - resolved "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz" - integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== - dependencies: - "@fastify/busboy" "^2.0.0" - - universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - - universalify@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" - integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== - - unpipe@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - - utf8@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== - - util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - - uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - - v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - - web3-utils@^1.3.6: - version "1.10.4" - resolved "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz" - integrity sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A== - dependencies: - "@ethereumjs/util" "^8.1.0" - bn.js "^5.2.1" - ethereum-bloom-filters "^1.0.6" - ethereum-cryptography "^2.1.2" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - utf8 "3.0.0" - - which@^1.1.1, which@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - - widest-line@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz" - integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== - dependencies: - string-width "^4.0.0" - - word-wrap@~1.2.3: - version "1.2.5" - resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - - wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== - - wordwrapjs@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz" - integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== - dependencies: - reduce-flatten "^2.0.0" - typical "^5.2.0" - - workerpool@^6.5.1: - version "6.5.1" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz" - integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== - - wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - - wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - - ws@^7.4.6: - version "7.5.10" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" - integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== - - ws@7.4.6: - version "7.4.6" - resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - - ws@8.17.1: - version "8.17.1" - resolved "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - - y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - - yargs-parser@^20.2.2, yargs-parser@^20.2.9: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - - yargs-unparser@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - - yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - - yn@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - - yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From ce6387b65dab92155f250df28a19479dd4fb068d Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 13:04:00 +0800 Subject: [PATCH 02/21] implement whitelist check functionality across factory contracts and deployment scripts --- contracts/v2/access/WithWhitelistCheck.sol | 47 +++++++ contracts/v2/factory/TermMax4626Factory.sol | 14 +- contracts/v2/factory/TermMaxFactoryV2.sol | 9 +- .../v2/factory/TermMaxVaultFactoryV2.sol | 8 +- script/deploy/DeployBaseV2.s.sol | 21 +-- script/deploy/DeployCoreV2_20251002.s.sol | 120 ------------------ test/v2/FactoryV2.t.sol | 2 +- test/v2/TermMax4626Factory.t.sol | 7 +- test/v2/mainnet-fork/ForkBaseTestV2.sol | 20 ++- test/v2/mainnet-fork/VaultBaseTestV2.t.sol | 2 +- test/v2/utils/DeployUtils.sol | 17 ++- 11 files changed, 119 insertions(+), 148 deletions(-) create mode 100644 contracts/v2/access/WithWhitelistCheck.sol delete mode 100644 script/deploy/DeployCoreV2_20251002.s.sol diff --git a/contracts/v2/access/WithWhitelistCheck.sol b/contracts/v2/access/WithWhitelistCheck.sol new file mode 100644 index 00000000..1208b860 --- /dev/null +++ b/contracts/v2/access/WithWhitelistCheck.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IWhitelistManager} from "./IWhitelistManager.sol"; + +abstract contract WithWhitelistCheck { + error WhitelistManagerNotSet(); + error NoWhitelistModuleConfigured(); + error TargetNotWhitelisted(); + + IWhitelistManager public immutable whitelistManager; + IWhitelistManager.ContractModule public immutable defaultWhitelistModule; + + constructor(address _whitelistManager, IWhitelistManager.ContractModule _defaultWhitelistModule) { + if (_whitelistManager == address(0)) revert WhitelistManagerNotSet(); + whitelistManager = IWhitelistManager(_whitelistManager); + defaultWhitelistModule = _defaultWhitelistModule; + } + + function _registerAddress(address target) internal { + _registerAddressWithMoudle(target, defaultWhitelistModule); + } + + function _registerAddressWithMoudle(address target, IWhitelistManager.ContractModule module) internal { + address[] memory targets = new address[](1); + targets[0] = target; + whitelistManager.batchSetWhitelist(targets, module, true); + } + + function _checkWhitelisted(address target, IWhitelistManager.ContractModule module) internal view { + if (!whitelistManager.isWhitelisted(target, module)) revert TargetNotWhitelisted(); + } + + function _checkWhitelisted(address target) internal view { + _checkWhitelisted(target, defaultWhitelistModule); + } + + modifier onlyWhitelisted(address target) { + _checkWhitelisted(target); + _; + } + + modifier onlyWhitelistedWithModule(address target, IWhitelistManager.ContractModule module) { + _checkWhitelisted(target, module); + _; + } +} diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index 5bf2f03a..731e926b 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -12,9 +12,10 @@ import {StableERC4626ForCustomize} from "../tokens/StableERC4626ForCustomize.sol import {VariableERC4626ForAave} from "../tokens/VariableERC4626ForAave.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {FactoryErrorsV2} from "../errors/FactoryErrorsV2.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; -contract TermMax4626Factory is VersionV2, Ownable2Step { +contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { using Clones for address; bytes32 public constant STABLE_ERC4626_FOR_4626 = keccak256("StableERC4626For4626"); @@ -31,8 +32,9 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { address _stableERC4626ForAaveImplementation, address _stableERC4626ForVenusImplementation, address _variableERC4626ForAaveImplementation, - address _stableERC4626ForCustomizeImplementation - ) Ownable(owner) { + address _stableERC4626ForCustomizeImplementation, + address _whitelistManager + ) Ownable(owner) WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.POOL) { implementations[STABLE_ERC4626_FOR_4626] = _stableERC4626For4626Implementation; implementations[STABLE_ERC4626_FOR_AAVE] = _stableERC4626ForAaveImplementation; implementations[STABLE_ERC4626_FOR_VENUS] = _stableERC4626ForVenusImplementation; @@ -84,6 +86,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { ) external returns (StableERC4626For4626) { StableERC4626For4626 instance = StableERC4626For4626(implementations[STABLE_ERC4626_FOR_4626].clone()); instance.initialize(admin, thirdPool, bufferConfig); + _registerAddress(address(instance)); emit FactoryEventsV2.StableERC4626For4626Created(msg.sender, address(instance)); return instance; } @@ -95,6 +98,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { ) external returns (StableERC4626ForVenus) { StableERC4626ForVenus instance = StableERC4626ForVenus(implementations[STABLE_ERC4626_FOR_VENUS].clone()); instance.initialize(admin, thirdPool, bufferConfig); + _registerAddress(address(instance)); emit FactoryEventsV2.StableERC4626ForVenusCreated(msg.sender, address(instance)); return instance; } @@ -108,6 +112,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { StableERC4626ForCustomize instance = StableERC4626ForCustomize(implementations[STABLE_ERC4626_FOR_CUSTOMIZE].clone()); instance.initialize(admin, thirdPool, underlying, bufferConfig); + _registerAddress(address(instance)); emit FactoryEventsV2.StableERC4626ForCustomizeCreated(msg.sender, address(instance)); return instance; } @@ -119,6 +124,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { ) public returns (StableERC4626ForAave) { StableERC4626ForAave instance = StableERC4626ForAave(implementations[STABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); + _registerAddress(address(instance)); emit FactoryEventsV2.StableERC4626ForAaveCreated(msg.sender, address(instance)); return instance; } @@ -130,6 +136,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { ) public returns (VariableERC4626ForAave) { VariableERC4626ForAave instance = VariableERC4626ForAave(implementations[VARIABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); + _registerAddress(address(instance)); emit FactoryEventsV2.VariableERC4626ForAaveCreated(msg.sender, address(instance)); return instance; } @@ -140,6 +147,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step { address instance = implementation.clone(); (bool success,) = instance.call(initialData); if (!success) revert FactoryErrorsV2.InitializationFailed(); + _registerAddress(instance); emit FactoryEventsV2.TermMax4626Created(msg.sender, key, instance); return instance; } diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index a1f92ddf..e31ea419 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -10,6 +10,7 @@ import {FactoryEvents} from "../../v1/events/FactoryEvents.sol"; import {ITermMaxMarket} from "../../v1/ITermMaxMarket.sol"; import {ITermMaxFactory} from "../../v1/factory/ITermMaxFactory.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; /** @@ -19,7 +20,7 @@ import {VersionV2} from "../VersionV2.sol"; * @dev Manages market deployment, gearing token implementations, and market configuration validation * Inherits from V1 factory interface while adding V2-specific features for improved market creation */ -contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, VersionV2 { +contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, VersionV2, WithWhitelistCheck { /// @notice Constant key for the default ERC20 gearing token implementation bytes32 constant GT_ERC20 = keccak256("GearingTokenWithERC20"); @@ -40,7 +41,10 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver * @param TERMMAX_MARKET_IMPLEMENTATION_ The address of the TermMax market implementation contract * @custom:security Only the admin can create markets and manage gearing token implementations */ - constructor(address admin, address TERMMAX_MARKET_IMPLEMENTATION_) Ownable(admin) { + constructor(address admin, address TERMMAX_MARKET_IMPLEMENTATION_, address _whitelistManager) + Ownable(admin) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) + { if (TERMMAX_MARKET_IMPLEMENTATION_ == address(0)) { revert FactoryErrors.InvalidImplementation(); } @@ -117,6 +121,7 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver // Initialize the newly deployed market with provided parameters ITermMaxMarket(market).initialize(params); + _registerAddress(market); // Emit event for market creation tracking emit FactoryEventsV2.MarketCreated(market, params.collateral, params.debtToken, params); diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index d0c07d0e..ee935b93 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -6,19 +6,22 @@ import {ITermMaxVaultV2} from "../vault/ITermMaxVaultV2.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {ITermMaxVaultFactoryV2} from "./ITermMaxVaultFactoryV2.sol"; import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; /** * @title The TermMax vault factory v2 * @author Term Structure Labs */ -contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2 { +contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck { /** * @notice The implementation of TermMax Vault contract v2 */ address public immutable TERMMAX_VAULT_IMPLEMENTATION; - constructor(address TERMMAX_VAULT_IMPLEMENTATION_) { + constructor(address TERMMAX_VAULT_IMPLEMENTATION_, address _whitelistManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.ORDER_CALLBACK) + { TERMMAX_VAULT_IMPLEMENTATION = TERMMAX_VAULT_IMPLEMENTATION_; } @@ -46,6 +49,7 @@ contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2 { keccak256(abi.encode(msg.sender, initialParams.asset, initialParams.name, initialParams.symbol, salt)) ); ITermMaxVaultV2(vault).initialize(initialParams); + _registerAddress(vault); emit FactoryEventsV2.VaultCreated(vault, msg.sender, initialParams); } } diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index 273b6b0a..38c94845 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -287,17 +287,17 @@ contract DeployBaseV2 is Script { console.log("Deployment info written to:", filePath); } - function deployFactory(address admin) public returns (TermMaxFactoryV2 factory) { + function deployFactory(address admin, address whitelistManager) public returns (TermMaxFactoryV2 factory) { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(admin, address(m)); + factory = new TermMaxFactoryV2(admin, address(m), whitelistManager); } - function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { + function deployVaultFactory(address whitelistManager) public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); - vaultFactory = new TermMaxVaultFactoryV2(address(implementation)); + vaultFactory = new TermMaxVaultFactoryV2(address(implementation), whitelistManager); } function deployOracleAggregator(address admin, uint256 oracleTimelock) public returns (OracleAggregatorV2 oracle) { @@ -376,16 +376,16 @@ contract DeployBaseV2 is Script { public returns (DeployedContracts memory) { - // deploy factory - contracts.factory = deployFactory(address(contracts.accessManager)); - // deploy whitelist manager contracts.whitelistManager = deployWhitelistManager(address(contracts.accessManager)); - contracts.vaultFactory = deployVaultFactory(); + // deploy factory + contracts.factory = deployFactory(address(contracts.accessManager), address(contracts.whitelistManager)); + + contracts.vaultFactory = deployVaultFactory(address(contracts.whitelistManager)); // deploy vault factory - contracts.vaultFactory = deployVaultFactory(); + contracts.vaultFactory = deployVaultFactory(address(contracts.whitelistManager)); // deploy 4626 factory { @@ -406,7 +406,8 @@ contract DeployBaseV2 is Script { stableERC4626ForAave, address(stableERC4626ForVenus), variableERC4626ForAave, - address(stableERC4626ForCustomize) + address(stableERC4626ForCustomize), + address(contracts.whitelistManager) ); } diff --git a/script/deploy/DeployCoreV2_20251002.s.sol b/script/deploy/DeployCoreV2_20251002.s.sol deleted file mode 100644 index 96ba1f6d..00000000 --- a/script/deploy/DeployCoreV2_20251002.s.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {Script} from "forge-std/Script.sol"; -import {VmSafe} from "forge-std/Vm.sol"; -import "forge-std/console.sol"; -import "./DeployBaseV2.s.sol"; - -contract DeployCoreV2_20251002 is DeployBaseV2 { - uint256 deployerPrivateKey; - address accessManagerAddr; - - CoreParams coreParams; - DeployedContracts coreContracts; - - function setUp() public { - // Load network from environment variable - coreParams.network = vm.envString("NETWORK"); - string memory networkUpper = toUpper(coreParams.network); - - // Load network-specific configuration - string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); - string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); - { - string memory AAVEPoolVar = string.concat(networkUpper, "_AAVE_POOL"); - string memory AAVEReferralCodeVar = string.concat(networkUpper, "_AAVE_REFERRAL_CODE"); - coreParams.AAVE_POOL = vm.envAddress(AAVEPoolVar); - coreParams.AAVE_REFERRAL_CODE = uint16(vm.envUint(AAVEReferralCodeVar)); - } - - deployerPrivateKey = vm.envUint(privateKeyVar); - coreParams.deployerAddr = vm.addr(deployerPrivateKey); - coreParams.adminAddr = vm.envAddress(adminVar); - - coreParams.isMainnet = keccak256(abi.encodePacked(coreParams.network)) - == keccak256(abi.encodePacked("eth-mainnet")) - || keccak256(abi.encodePacked(coreParams.network)) == keccak256(abi.encodePacked("arb-mainnet")) - || keccak256(abi.encodePacked(coreParams.network)) == keccak256(abi.encodePacked("bnb-mainnet")); - coreParams.isL2Network = ( - keccak256(abi.encodePacked(toUpper(coreParams.network))) == keccak256(abi.encodePacked("arb-mainnet")) - ) || (keccak256(abi.encodePacked(toUpper(coreParams.network))) == keccak256(abi.encodePacked("arb-sepolia"))); - if (coreParams.isMainnet) { - string memory uniswapV3RouterVar = string.concat(networkUpper, "_UNISWAP_V3_ROUTER_ADDRESS"); - string memory odosV2RouterVar = string.concat(networkUpper, "_ODOS_V2_ROUTER_ADDRESS"); - string memory pendleSwapV3RouterVar = string.concat(networkUpper, "_PENDLE_SWAP_V3_ROUTER_ADDRESS"); - string memory oracleTimelockVar = string.concat(networkUpper, "_ORACLE_TIMELOCK"); - coreParams.uniswapV3Router = vm.envAddress(uniswapV3RouterVar); - coreParams.odosV2Router = vm.envAddress(odosV2RouterVar); - coreParams.pendleSwapV3Router = vm.envAddress(pendleSwapV3RouterVar); - coreParams.oracleTimelock = vm.envUint(oracleTimelockVar); - } - if (coreParams.isL2Network) { - string memory l2SequencerUptimeFeedVar = string.concat(networkUpper, "_L2_SEQUENCER_UPTIME_FEED"); - coreParams.l2SequencerUpPriceFeed = vm.envAddress(l2SequencerUptimeFeedVar); - string memory l2SequencerGracePeriodVar = string.concat(networkUpper, "_L2_SEQUENCER_GRACE_PERIOD"); - coreParams.l2GracePeriod = vm.envUint(l2SequencerGracePeriodVar); - } - { - // Create deployments directory if it doesn't exist - string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); - if (!vm.exists(deploymentsDir)) { - // Directory doesn't exist, create it - vm.createDir(deploymentsDir, true); - } - } - - string memory deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" - ); - if (vm.exists(deploymentPath)) { - string memory json = vm.readFile(deploymentPath); - coreContracts = readDeployData(json); - } - - deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" - ); - string memory json = vm.readFile(deploymentPath); - - accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); - console.log("Using existing AccessManagerV2 at:", accessManagerAddr); - coreContracts.accessManager = AccessManagerV2(accessManagerAddr); - } - - function run() public { - console.log("Network:", coreParams.network); - console.log("Deployer balance:", coreParams.deployerAddr.balance); - - vm.startBroadcast(deployerPrivateKey); - - coreContracts.factory = deployFactory(address(coreContracts.accessManager)); - console.log("FactoryV2 deployed at:", address(coreContracts.factory)); - - coreContracts.vaultFactory = deployVaultFactory(); - console.log("VaultFactoryV2 deployed at:", address(coreContracts.vaultFactory)); - - vm.stopBroadcast(); - - console.log("===== Git Info ====="); - console.log("Git branch:", getGitBranch()); - console.log("Git commit hash:"); - console.logBytes(getGitCommitHash()); - console.log(); - - console.log("===== Block Info ====="); - console.log("Block number:", block.number); - console.log("Block timestamp:", block.timestamp); - console.log(); - - console.log("===== Core Info ====="); - console.log("Deployer:", coreParams.deployerAddr); - console.log("Admin:", coreParams.adminAddr); - - string memory deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" - ); - - writeAsJson(deploymentPath, coreParams, coreContracts); - } -} diff --git a/test/v2/FactoryV2.t.sol b/test/v2/FactoryV2.t.sol index 4f2b8cf2..f90b599d 100644 --- a/test/v2/FactoryV2.t.sol +++ b/test/v2/FactoryV2.t.sol @@ -277,6 +277,6 @@ contract FactoryTestV2 is Test { function testInvalidMarketImplementation() public { vm.expectRevert(abi.encodeWithSelector(FactoryErrors.InvalidImplementation.selector)); - new TermMaxFactoryV2(deployer, address(0)); + new TermMaxFactoryV2(deployer, address(0), address(1)); } } diff --git a/test/v2/TermMax4626Factory.t.sol b/test/v2/TermMax4626Factory.t.sol index ccaa63f2..8ce54212 100644 --- a/test/v2/TermMax4626Factory.t.sol +++ b/test/v2/TermMax4626Factory.t.sol @@ -16,6 +16,7 @@ import {MockVToken} from "contracts/mocks/MockVToken.sol"; import {IAaveV3Pool} from "contracts/v2/extensions/aave/IAaveV3Pool.sol"; import {ERC4626TokenEvents} from "contracts/v2/events/ERC4626TokenEvents.sol"; import {FactoryEventsV2} from "contracts/v2/events/FactoryEventsV2.sol"; +import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; contract TermMax4626FactoryTest is Test { TermMax4626Factory public factory; @@ -37,6 +38,7 @@ contract TermMax4626FactoryTest is Test { StableERC4626ForVenus public implVenus; VariableERC4626ForAave public implVariableAave; StableERC4626ForCustomize public implCustomize; + WhitelistManager public whitelistManager; StakingBuffer.BufferConfig public defaultBufferConfig; @@ -62,6 +64,8 @@ contract TermMax4626FactoryTest is Test { implVariableAave = new VariableERC4626ForAave(address(aavePool), 100); implVenus = new StableERC4626ForVenus(); implCustomize = new StableERC4626ForCustomize(); + whitelistManager = new WhitelistManager(); + whitelistManager.initialize(admin); // Deploy factory factory = new TermMax4626Factory( @@ -70,7 +74,8 @@ contract TermMax4626FactoryTest is Test { address(implStableAave), address(implVenus), address(implVariableAave), - address(implCustomize) + address(implCustomize), + address(whitelistManager) ); // Setup default buffer config diff --git a/test/v2/mainnet-fork/ForkBaseTestV2.sol b/test/v2/mainnet-fork/ForkBaseTestV2.sol index ea6f9c51..9036b717 100644 --- a/test/v2/mainnet-fork/ForkBaseTestV2.sol +++ b/test/v2/mainnet-fork/ForkBaseTestV2.sol @@ -26,7 +26,7 @@ import { LoanConfig, VaultInitialParams } from "contracts/v1/storage/TermMaxStorage.sol"; -import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {WhitelistManager, IWhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; import {DeployUtils} from "../utils/DeployUtils.sol"; import {JSONLoader} from "../utils/JSONLoader.sol"; import "forge-std/Test.sol"; @@ -143,20 +143,23 @@ abstract contract ForkBaseTestV2 is Test { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(admin, address(m)); + IWhitelistManager whitelistManager = deployWhitelistManager(admin); + factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory) { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(admin, address(m)); + IWhitelistManager whitelistManager = deployWhitelistManager(admin); + factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } - function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { + function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); - vaultFactory = new TermMaxVaultFactoryV2(address(implementation)); + IWhitelistManager whitelistManager = deployWhitelistManager(admin); + vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); } function deployOracleAggregator(address admin) public returns (OracleAggregatorV2 oracle) { @@ -170,4 +173,11 @@ abstract contract ForkBaseTestV2 is Test { function deployRouter(address admin) public returns (TermMaxRouterV2, IWhitelistManager) { return DeployUtils.deployRouter(admin); } + + function deployWhitelistManager(address admin) internal returns (IWhitelistManager whitelistManager) { + WhitelistManager implementation = new WhitelistManager(); + bytes memory data = abi.encodeCall(WhitelistManager.initialize, admin); + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); + whitelistManager = IWhitelistManager(address(proxy)); + } } diff --git a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol index 57bd4cdf..e6e7caa1 100644 --- a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol +++ b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol @@ -135,7 +135,7 @@ abstract contract VaultBaseTestV2 is ForkBaseTestV2 { MockPriceFeed.RoundData(1, 1e8, block.timestamp, block.timestamp, 0) ); - res.vault = ITermMaxVault(deployVaultFactory().createVault(res.vaultInitialParams, 0)); + res.vault = ITermMaxVault(deployVaultFactory(res.marketInitialParams.admin).createVault(res.vaultInitialParams, 0)); res.vault.submitMarket(address(res.market), true); vm.warp(res.currentTime + res.vaultInitialParams.timelock + 1); diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index b73ba8d6..43e453e4 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -373,14 +373,23 @@ library DeployUtils { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(admin, address(m)); + IWhitelistManager whitelistManager = deployWhitelistManager(admin); + factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory) { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(admin, address(m)); + IWhitelistManager whitelistManager = deployWhitelistManager(admin); + factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); + } + + function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { + OrderManagerV2 orderManager = new OrderManagerV2(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); + IWhitelistManager whitelistManager = deployWhitelistManager(msg.sender); + vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); } function deployOracle(address admin, uint256 timeLock) public returns (OracleAggregatorV2 oracle) { @@ -398,7 +407,9 @@ library DeployUtils { function deployVault(VaultInitialParamsV2 memory initialParams) public returns (TermMaxVaultV2 vault) { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); - TermMaxVaultFactoryV2 vaultFactory = new TermMaxVaultFactoryV2(address(implementation)); + IWhitelistManager whitelistManager = deployWhitelistManager(initialParams.admin); + TermMaxVaultFactoryV2 vaultFactory = + new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); } From 5e2d3d99b852a3dfc9967f232356d548bef51fb0 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 13:52:00 +0800 Subject: [PATCH 03/21] add mock whitelist manager and fix tests --- contracts/v2/test/MockWhitelistManager.sol | 24 ++++++++++++++++++++++ test/v2/AccessManagerV2.t.sol | 2 -- test/v2/RouterV2.t.sol | 6 +++--- test/v2/TermMax4626Factory.t.sol | 3 ++- test/v2/mainnet-fork/VaultBaseTestV2.t.sol | 3 ++- test/v2/utils/DeployUtils.sol | 19 ++++++++--------- 6 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 contracts/v2/test/MockWhitelistManager.sol diff --git a/contracts/v2/test/MockWhitelistManager.sol b/contracts/v2/test/MockWhitelistManager.sol new file mode 100644 index 00000000..99a77d99 --- /dev/null +++ b/contracts/v2/test/MockWhitelistManager.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IWhitelistManager} from "../access/IWhitelistManager.sol"; + +contract MockWhitelistManager is IWhitelistManager { + mapping(address => mapping(ContractModule => bool)) public whitelist; + + function setWhitelist(address _user, ContractModule _module, bool _approved) external { + whitelist[_user][_module] = _approved; + } + + function batchSetWhitelist(address[] memory _users, ContractModule _module, bool _approved) external { + for (uint256 i = 0; i < _users.length; i++) { + whitelist[_users[i]][_module] = _approved; + } + + emit WhitelistUpdated(_users, _module, _approved); + } + + function isWhitelisted(address _user, ContractModule _module) external view returns (bool) { + return whitelist[_user][_module]; + } +} diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index df4c41fd..a82e2f68 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -96,13 +96,11 @@ contract AccessManagerTestV2 is Test { IOwnable(address(res.market)).transferOwnership(address(manager)); IOwnable(address(res.router)).transferOwnership(address(manager)); IOwnable(address(res.oracle)).transferOwnership(address(manager)); - IOwnable(address(res.whitelistManager)).transferOwnership(address(manager)); manager.acceptOwnership(IOwnable(address(res.factory))); manager.acceptOwnership(IOwnable(address(res.market))); manager.acceptOwnership(IOwnable(address(res.router))); manager.acceptOwnership(IOwnable(address(res.oracle))); - manager.acceptOwnership(IOwnable(address(res.whitelistManager))); manager.grantRole(manager.CONFIGURATOR_ROLE(), deployer); manager.grantRole(manager.PAUSER_ROLE(), deployer); diff --git a/test/v2/RouterV2.t.sol b/test/v2/RouterV2.t.sol index 8527dbc9..be0b9c54 100644 --- a/test/v2/RouterV2.t.sol +++ b/test/v2/RouterV2.t.sol @@ -243,7 +243,7 @@ contract RouterTestV2 is Test { tradingAmts: tradingAmts, netTokenAmt: mintTokenOut, deadline: block.timestamp + 1 hours, - refundAddress: address(0) + refundAddress: address(res.router) }); res.debt.mint(sender, amountIn); @@ -635,7 +635,7 @@ contract RouterTestV2 is Test { tradingAmts: tokenAmtsWantBuy, netTokenAmt: maxDebtAmt, deadline: block.timestamp + 1 hours, - refundAddress: address(0) + refundAddress: address(res.router) }); SwapUnit[] memory swapUnits = new SwapUnit[](1); @@ -754,7 +754,7 @@ contract RouterTestV2 is Test { tradingAmts: amtsToBuyFt, netTokenAmt: mintTokenOut.toUint128(), deadline: block.timestamp + 1 hours, - refundAddress: address(0) + refundAddress: address(res.router) }); units[1] = SwapUnit({ adapter: address(termMaxSwapAdapter), diff --git a/test/v2/TermMax4626Factory.t.sol b/test/v2/TermMax4626Factory.t.sol index 8ce54212..eee68f0c 100644 --- a/test/v2/TermMax4626Factory.t.sol +++ b/test/v2/TermMax4626Factory.t.sol @@ -65,7 +65,6 @@ contract TermMax4626FactoryTest is Test { implVenus = new StableERC4626ForVenus(); implCustomize = new StableERC4626ForCustomize(); whitelistManager = new WhitelistManager(); - whitelistManager.initialize(admin); // Deploy factory factory = new TermMax4626Factory( @@ -78,6 +77,8 @@ contract TermMax4626FactoryTest is Test { address(whitelistManager) ); + whitelistManager.initialize(address(factory)); + // Setup default buffer config defaultBufferConfig = StakingBuffer.BufferConfig({minimumBuffer: 1000e18, maximumBuffer: 10000e18, buffer: 5000e18}); diff --git a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol index e6e7caa1..f22ea2be 100644 --- a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol +++ b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol @@ -135,7 +135,8 @@ abstract contract VaultBaseTestV2 is ForkBaseTestV2 { MockPriceFeed.RoundData(1, 1e8, block.timestamp, block.timestamp, 0) ); - res.vault = ITermMaxVault(deployVaultFactory(res.marketInitialParams.admin).createVault(res.vaultInitialParams, 0)); + res.vault = + ITermMaxVault(deployVaultFactory(res.marketInitialParams.admin).createVault(res.vaultInitialParams, 0)); res.vault.submitMarket(address(res.market), true); vm.warp(res.currentTime + res.vaultInitialParams.timelock + 1); diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index 43e453e4..cd6b585c 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -33,7 +33,7 @@ import { import {VaultInitialParamsV2} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {TermMaxVaultFactoryV2} from "contracts/v2/factory/TermMaxVaultFactoryV2.sol"; import {MockAave} from "contracts/v2/test/MockAave.sol"; -import {WhitelistManager, IWhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; +import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; import {OnlyDeliveryGearingToken} from "contracts/v2/tokens/OnlyDeliveryGearingToken.sol"; library DeployUtils { @@ -373,7 +373,7 @@ library DeployUtils { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(admin); + IWhitelistManager whitelistManager = deployWhitelistManager(); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } @@ -381,14 +381,14 @@ library DeployUtils { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(admin); + IWhitelistManager whitelistManager = deployWhitelistManager(); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); - IWhitelistManager whitelistManager = deployWhitelistManager(msg.sender); + IWhitelistManager whitelistManager = deployWhitelistManager(); vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); } @@ -397,7 +397,7 @@ library DeployUtils { } function deployRouter(address admin) public returns (TermMaxRouterV2 router, IWhitelistManager whitelistManager) { - whitelistManager = deployWhitelistManager(admin); + whitelistManager = deployWhitelistManager(); TermMaxRouterV2 implementation = new TermMaxRouterV2(); bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, address(whitelistManager))); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); @@ -407,7 +407,7 @@ library DeployUtils { function deployVault(VaultInitialParamsV2 memory initialParams) public returns (TermMaxVaultV2 vault) { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); - IWhitelistManager whitelistManager = deployWhitelistManager(initialParams.admin); + IWhitelistManager whitelistManager = deployWhitelistManager(); TermMaxVaultFactoryV2 vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); @@ -421,10 +421,7 @@ library DeployUtils { accessManager = AccessManager(address(proxy)); } - function deployWhitelistManager(address admin) internal returns (IWhitelistManager whitelistManager) { - WhitelistManager implementation = new WhitelistManager(); - bytes memory data = abi.encodeCall(WhitelistManager.initialize, admin); - ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); - whitelistManager = IWhitelistManager(address(proxy)); + function deployWhitelistManager() internal returns (IWhitelistManager whitelistManager) { + whitelistManager = new MockWhitelistManager(); } } From 53477589397fa5a0b7666d80ed7bf03a0184a1a8 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 16:47:43 +0800 Subject: [PATCH 04/21] add whitelist check to vault to check the markets and pools --- contracts/v2/vault/TermMaxVaultV2.sol | 24 ++++++++-- script/deploy/DeployBaseV2.s.sol | 2 +- test/v2/AccessManagerV2.t.sol | 15 ++++-- test/v2/VaultV2.t.sol | 21 ++++++++- test/v2/VaultV2WithPool.t.sol | 61 +++++++++++++++++++------ test/v2/mainnet-fork/ForkBaseTestV2.sol | 2 +- test/v2/utils/DeployUtils.sol | 45 +++++++++++++++--- 7 files changed, 138 insertions(+), 32 deletions(-) diff --git a/contracts/v2/vault/TermMaxVaultV2.sol b/contracts/v2/vault/TermMaxVaultV2.sol index d1101a9c..41227fc0 100644 --- a/contracts/v2/vault/TermMaxVaultV2.sol +++ b/contracts/v2/vault/TermMaxVaultV2.sol @@ -36,6 +36,7 @@ import {ITermMaxVaultV2} from "./ITermMaxVaultV2.sol"; import {VaultErrorsV2} from "../errors/VaultErrorsV2.sol"; import {TransactionReentrancyGuard} from "../lib/TransactionReentrancyGuard.sol"; import {VersionV2} from "../VersionV2.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; contract TermMaxVaultV2 is VaultStorageV2, @@ -46,7 +47,8 @@ contract TermMaxVaultV2 is ISwapCallback, ITermMaxVaultV2, TransactionReentrancyGuard, - VersionV2 + VersionV2, + WithWhitelistCheck { using SafeCast for uint256; using TransferUtils for IERC20; @@ -83,7 +85,9 @@ contract TermMaxVaultV2 is _; } - constructor(address ORDER_MANAGER_SINGLETON_) { + constructor(address ORDER_MANAGER_SINGLETON_, address _whitelistManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) + { ORDER_MANAGER_SINGLETON = ORDER_MANAGER_SINGLETON_; _disableInitializers(); } @@ -508,6 +512,10 @@ contract TermMaxVaultV2 is } function submitMarket(address market, bool isWhitelisted) external virtual onlyCuratorRole { + if (isWhitelisted) { + _checkWhitelisted(market); + } + if (!_submitPendingWhitelist(_marketWhitelist, _pendingMarkets, _setMarketWhitelist, market, isWhitelisted)) { emit VaultEvents.SubmitMarketToWhitelist(market, _pendingMarkets[market].validAt); } @@ -523,9 +531,13 @@ contract TermMaxVaultV2 is if (pool_ == address(_pool)) revert VaultErrors.AlreadySet(); if (_pendingPool.validAt != 0) revert VaultErrors.AlreadyPending(); - _pendingPool.update(pool_, _timelock); - - emit VaultEventsV2.SubmitPendingPool(pool_, _pendingPool.validAt); + if (pool_ != address(0)) { + _checkWhitelisted(pool_, IWhitelistManager.ContractModule.POOL); + _pendingPool.update(pool_, _timelock); + emit VaultEventsV2.SubmitPendingPool(pool_, _pendingPool.validAt); + } else { + _setPool(pool_); + } } function _setPool(address pool_) internal { @@ -534,6 +546,7 @@ contract TermMaxVaultV2 is oldPool.redeem(oldPool.balanceOf(address(this)), address(this), address(this)); } if (pool_ != address(0)) { + _checkWhitelisted(pool_, IWhitelistManager.ContractModule.POOL); IERC20 asset_ = IERC20(asset()); uint256 balance = asset_.balanceOf(address(this)); if (balance > 0) { @@ -626,6 +639,7 @@ contract TermMaxVaultV2 is } function acceptMarket(address market) external virtual afterTimelock(_pendingMarkets[market].validAt) { + _checkWhitelisted(market); _setMarketWhitelist(market, true); } diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index 38c94845..5bd22bf7 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -296,7 +296,7 @@ contract DeployBaseV2 is Script { function deployVaultFactory(address whitelistManager) public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), whitelistManager); vaultFactory = new TermMaxVaultFactoryV2(address(implementation), whitelistManager); } diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index a82e2f68..ca1adb8e 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -32,6 +32,7 @@ import {TermMaxOrderV2} from "contracts/v2/TermMaxOrderV2.sol"; import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "contracts/v2/vault/ITermMaxVaultV2.sol"; import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {MockWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; contract AccessManagerTestV2 is Test { using JSONLoader for *; @@ -83,8 +84,7 @@ contract AccessManagerTestV2 is Test { res.ft.transfer(address(res.order), amount); res.xt.transfer(address(res.order), amount); - (res.router, res.whitelistManager) = DeployUtils.deployRouter(deployer); - res.router.setWhitelistManager(address(res.whitelistManager)); + res.router = DeployUtils.deployRouter(deployer, res.whitelistManager); AccessManagerV2 implementation = new AccessManagerV2(); bytes memory data = abi.encodeCall(AccessManager.initialize, deployer); @@ -126,7 +126,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - res.vault = DeployUtils.deployVault(params); + res.vault = DeployUtils.deployVault(params, res.whitelistManager); vm.stopPrank(); vm.startPrank(curator); @@ -391,6 +391,10 @@ contract AccessManagerTestV2 is Test { address newGuardian = vm.randomAddress(); address vaultManager = vm.randomAddress(); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newMarket, IWhitelistManager.ContractModule.MARKET, true + ); + // Grant VAULT_ROLE to the vault manager and set curator vm.startPrank(deployer); manager.grantRole(manager.VAULT_ROLE(), vaultManager); @@ -724,11 +728,14 @@ contract AccessManagerTestV2 is Test { minApy: 0 }); - TermMaxVaultV2 poolVault = DeployUtils.deployVault(poolParams); + TermMaxVaultV2 poolVault = DeployUtils.deployVault(poolParams, res.whitelistManager); ITermMaxVaultV2 poolVaultV2 = ITermMaxVaultV2(address(poolVault)); address vaultManager = vm.randomAddress(); address newPoolAddress = vm.randomAddress(); // Mock pool address + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, true + ); // Grant VAULT_ROLE to the vault manager vm.startPrank(deployer); diff --git a/test/v2/VaultV2.t.sol b/test/v2/VaultV2.t.sol index 1ffa49d1..04f1220e 100644 --- a/test/v2/VaultV2.t.sol +++ b/test/v2/VaultV2.t.sol @@ -52,6 +52,7 @@ import {IPausable} from "contracts/v1/access/AccessManager.sol"; import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; import {VaultInitialParamsV2} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {TermMaxFactoryV2} from "contracts/v2/factory/TermMaxFactoryV2.sol"; +import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; /// @dev use --isolate to run this tests contract VaultTestV2 is Test { @@ -97,7 +98,7 @@ contract VaultTestV2 is Test { vm.label(address(res.market), "market"); MarketConfig memory marketConfig2 = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); marketConfig2.maturity = uint64(currentTime + 180 days); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer, res.whitelistManager); market2 = TermMaxMarketV2( factory.createMarket( DeployUtils.GT_ERC20, @@ -142,7 +143,7 @@ contract VaultTestV2 is Test { 0 ); - vault = DeployUtils.deployVault(initialParams); + vault = DeployUtils.deployVault(initialParams, res.whitelistManager); vm.label(address(vault), "vault"); vm.label(guardian, "guardian"); @@ -246,6 +247,9 @@ contract VaultTestV2 is Test { // submit market vm.startPrank(curator); address market = address(0x123); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + market, IWhitelistManager.ContractModule.MARKET, true + ); vault.submitMarket(market, false); assertEq(vault.marketWhitelist(market), false); @@ -261,12 +265,18 @@ contract VaultTestV2 is Test { vault.acceptMarket(market); assertEq(vault.marketWhitelist(market), true); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + market, IWhitelistManager.ContractModule.MARKET, false + ); vault.submitMarket(market, false); assertEq(vault.marketWhitelist(market), false); vm.stopPrank(); // Test revoke market address newMarket = address(0x456); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newMarket, IWhitelistManager.ContractModule.MARKET, true + ); vm.prank(curator); vault.submitMarket(newMarket, true); @@ -279,10 +289,17 @@ contract VaultTestV2 is Test { address market = address(0x123); vm.prank(vm.randomAddress()); + vm.expectRevert(VaultErrors.NotCuratorRole.selector); vault.submitMarket(market, true); vm.startPrank(curator); + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + vault.submitMarket(market, true); + + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + market, IWhitelistManager.ContractModule.MARKET, true + ); vault.submitMarket(market, true); vm.expectRevert(VaultErrors.AlreadyPending.selector); diff --git a/test/v2/VaultV2WithPool.t.sol b/test/v2/VaultV2WithPool.t.sol index 3fe1b092..139b3388 100644 --- a/test/v2/VaultV2WithPool.t.sol +++ b/test/v2/VaultV2WithPool.t.sol @@ -53,6 +53,7 @@ import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; import {VaultInitialParamsV2} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {MockERC4626} from "contracts/v2/test/MockERC4626.sol"; import {TermMaxFactoryV2} from "contracts/v2/factory/TermMaxFactoryV2.sol"; +import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; /// @dev use --isolate to run this tests contract VaultV2WithPoolTest is Test { @@ -99,11 +100,14 @@ contract VaultV2WithPoolTest is Test { vm.label(address(res.market), "market"); pool = new MockERC4626(res.debt); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + address(pool), IWhitelistManager.ContractModule.POOL, true + ); vm.label(address(pool), "pool"); { MarketConfig memory marketConfig2 = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); marketConfig2.maturity = uint64(currentTime + 180 days); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer, res.whitelistManager); market2 = TermMaxMarketV2( factory.createMarket( DeployUtils.GT_ERC20, @@ -150,7 +154,7 @@ contract VaultV2WithPoolTest is Test { 0 ); - vault = DeployUtils.deployVault(initialParams); + vault = DeployUtils.deployVault(initialParams, res.whitelistManager); vm.label(address(vault), "vault"); vm.label(guardian, "guardian"); @@ -207,7 +211,7 @@ contract VaultV2WithPoolTest is Test { function testDepositWhenNoOrders() public { initialParams.name = "Vault-DAI2"; initialParams.symbol = "Vault-DAI2"; - TermMaxVaultV2 vault2 = DeployUtils.deployVault(initialParams); + TermMaxVaultV2 vault2 = DeployUtils.deployVault(initialParams, res.whitelistManager); vm.startPrank(deployer); uint256 amount = 10000e8; res.debt.mint(deployer, amount); @@ -592,6 +596,10 @@ contract VaultV2WithPoolTest is Test { MockERC4626 newPool = new MockERC4626(res.debt); address newPoolAddress = address(newPool); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, true + ); + // Test unauthorized access vm.prank(vm.randomAddress()); vm.expectRevert(VaultErrors.NotCuratorRole.selector); @@ -615,6 +623,9 @@ contract VaultV2WithPoolTest is Test { // Test submitting another pool while one is pending should revert MockERC4626 anotherPool = new MockERC4626(res.debt); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + address(anotherPool), IWhitelistManager.ContractModule.POOL, true + ); vm.prank(curator); vm.expectRevert(VaultErrors.AlreadyPending.selector); vaultV2.submitPendingPool(address(anotherPool)); @@ -627,6 +638,10 @@ contract VaultV2WithPoolTest is Test { MockERC4626 newPool = new MockERC4626(res.debt); address newPoolAddress = address(newPool); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, true + ); + // Submit pending pool vm.prank(curator); vaultV2.submitPendingPool(newPoolAddress); @@ -638,6 +653,17 @@ contract VaultV2WithPoolTest is Test { // Move time forward past timelock vm.warp(currentTime + timelock + 1); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, false + ); + + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + vaultV2.acceptPool(); + + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, true + ); + // Get initial balances uint256 oldPoolBalance = pool.balanceOf(address(vault)); uint256 vaultAssetBalance = res.debt.balanceOf(address(vault)); @@ -668,9 +694,17 @@ contract VaultV2WithPoolTest is Test { address newPoolAddress = address(newPool); // Submit pending pool - vm.prank(curator); + vm.startPrank(curator); + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + vaultV2.submitPendingPool(newPoolAddress); + + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + newPoolAddress, IWhitelistManager.ContractModule.POOL, true + ); vaultV2.submitPendingPool(newPoolAddress); + vm.stopPrank(); + // Verify pending state assertEq(vault.pendingPool().value, newPoolAddress); assertEq(vault.pendingPool().validAt, currentTime + timelock); @@ -699,19 +733,14 @@ contract VaultV2WithPoolTest is Test { ITermMaxVaultV2 vaultV2 = ITermMaxVaultV2(address(vault)); // Test submitting zero address as pool (should disable pool) - vm.prank(curator); - vaultV2.submitPendingPool(address(0)); - - // Move time forward and accept - vm.warp(currentTime + timelock + 1); + vm.startPrank(curator); uint256 oldPoolBalance = pool.balanceOf(address(vault)); uint256 expectedAssetBalance = pool.convertToAssets(oldPoolBalance); - vm.expectEmit(true, true, false, false); - emit VaultEventsV2.SetPool(address(this), address(0)); - - vaultV2.acceptPool(); + vm.expectEmit(); + emit VaultEventsV2.SetPool(curator, address(0)); + vaultV2.submitPendingPool(address(0)); // Verify pool was set to zero address assertEq(address(vault.pool()), address(0)); @@ -719,6 +748,8 @@ contract VaultV2WithPoolTest is Test { // Verify assets were withdrawn from old pool assertEq(pool.balanceOf(address(vault)), 0); assertEq(res.debt.balanceOf(address(vault)), expectedAssetBalance); + + vm.stopPrank(); } function testPoolManagementAccessControl() public { @@ -727,6 +758,10 @@ contract VaultV2WithPoolTest is Test { // Create a new pool MockERC4626 newPool = new MockERC4626(res.debt); + MockWhitelistManager(address(res.whitelistManager)).setWhitelist( + address(newPool), IWhitelistManager.ContractModule.POOL, true + ); + // Test that only curator can submit vm.prank(guardian); vm.expectRevert(VaultErrors.NotCuratorRole.selector); diff --git a/test/v2/mainnet-fork/ForkBaseTestV2.sol b/test/v2/mainnet-fork/ForkBaseTestV2.sol index 9036b717..087ad17a 100644 --- a/test/v2/mainnet-fork/ForkBaseTestV2.sol +++ b/test/v2/mainnet-fork/ForkBaseTestV2.sol @@ -157,8 +157,8 @@ abstract contract ForkBaseTestV2 is Test { function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); IWhitelistManager whitelistManager = deployWhitelistManager(admin); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); } diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index cd6b585c..6cea96df 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -77,6 +77,7 @@ library DeployUtils { returns (Res memory res) { res.factory = deployFactory(admin); + res.whitelistManager = res.factory.whitelistManager(); res.collateral = new MockERC20("ETH", "ETH", 18); res.debt = new MockERC20("DAI", "DAI", 8); @@ -253,7 +254,7 @@ library DeployUtils { uint32 maxLtv, uint32 liquidationLtv ) internal returns (Res memory res) { - res.factory = deployFactoryWithMockOrder(admin); + (res.factory, res.whitelistManager) = deployFactoryWithMockOrder(admin); res.debt = MockERC20(address(debt)); MarketConfig memory marketConfig = mc; marketConfig.maturity += uint64(duration * 1 days); @@ -309,7 +310,7 @@ library DeployUtils { internal returns (Res memory res) { - res.factory = deployFactoryWithMockOrder(admin); + (res.factory, res.whitelistManager) = deployFactoryWithMockOrder(admin); res.collateral = new MockERC20("ETH", "ETH", 18); res.debt = new MockERC20("DAI", "DAI", 8); @@ -377,18 +378,31 @@ library DeployUtils { factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } - function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory) { + function deployFactory(address admin, IWhitelistManager whitelistManager) + public + returns (TermMaxFactoryV2 factory) + { + address tokenImplementation = address(new MintableERC20V2()); + address orderImplementation = address(new TermMaxOrderV2()); + TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); + factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); + } + + function deployFactoryWithMockOrder(address admin) + public + returns (TermMaxFactoryV2 factory, IWhitelistManager whitelistManager) + { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(); + whitelistManager = deployWhitelistManager(); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); IWhitelistManager whitelistManager = deployWhitelistManager(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); } @@ -404,10 +418,29 @@ library DeployUtils { router = TermMaxRouterV2(address(proxy)); } + function deployRouter(address admin, IWhitelistManager whitelistManager) public returns (TermMaxRouterV2 router) { + TermMaxRouterV2 implementation = new TermMaxRouterV2(); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, address(whitelistManager))); + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); + router = TermMaxRouterV2(address(proxy)); + } + function deployVault(VaultInitialParamsV2 memory initialParams) public returns (TermMaxVaultV2 vault) { OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager)); IWhitelistManager whitelistManager = deployWhitelistManager(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); + TermMaxVaultFactoryV2 vaultFactory = + new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); + + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + } + + function deployVault(VaultInitialParamsV2 memory initialParams, IWhitelistManager whitelistManager) + public + returns (TermMaxVaultV2 vault) + { + OrderManagerV2 orderManager = new OrderManagerV2(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); TermMaxVaultFactoryV2 vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); From 265183e351000300522795a78d1d90cfaf2c789c Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 16:56:01 +0800 Subject: [PATCH 05/21] clean router v1 code --- contracts/v1/router/ITermMaxRouter.sol | 46 ----------- contracts/v1/router/TermMaxRouter_V1_1_2.sol | 80 -------------------- 2 files changed, 126 deletions(-) diff --git a/contracts/v1/router/ITermMaxRouter.sol b/contracts/v1/router/ITermMaxRouter.sol index 2091cba9..6c80be01 100644 --- a/contracts/v1/router/ITermMaxRouter.sol +++ b/contracts/v1/router/ITermMaxRouter.sol @@ -102,29 +102,6 @@ interface ITermMaxRouter { uint256 deadline ) external returns (uint256 netTokenIn); - /** - * @notice Sells FT and XT tokens for underlying tokens - * @dev Executes multiple orders to sell tokens - * @param recipient Address to receive the output tokens - * @param market The market to sell tokens in - * @param ftInAmt Amount of FT tokens to sell - * @param xtInAmt Amount of XT tokens to sell - * @param orders Array of orders to execute - * @param amtsToSellTokens Array of amounts to sell for each order - * @param minTokenOut Minimum amount of output tokens to receive - * @param deadline The deadline timestamp for the transaction - * @return netTokenOut Actual amount of output tokens received - */ - function sellTokens( - address recipient, - ITermMaxMarket market, - uint128 ftInAmt, - uint128 xtInAmt, - ITermMaxOrder[] memory orders, - uint128[] memory amtsToSellTokens, - uint128 minTokenOut, - uint256 deadline - ) external returns (uint256 netTokenOut); /** * @notice Creates a leveraged position from input tokens @@ -291,27 +268,4 @@ interface ITermMaxRouter { uint256 minTokenOut ) external returns (uint256 redeemedAmt); - /** - * @notice Creates an order and deposits tokens - * @dev Creates a new order and deposits tokens to the market - * @param market The market to create order in - * @param maker Address of the order maker - * @param maxXtReserve Maximum amount of XT to reserve - * @param swapTrigger Swap trigger callback - * @param debtTokenToDeposit Amount of debt tokens to deposit - * @param ftToDeposit Amount of FT tokens to deposit - * @param xtToDeposit Amount of XT tokens to deposit - * @param curveCuts Curve cuts for the order - * @return order The created order - */ - function createOrderAndDeposit( - ITermMaxMarket market, - address maker, - uint256 maxXtReserve, - ISwapCallback swapTrigger, - uint256 debtTokenToDeposit, - uint128 ftToDeposit, - uint128 xtToDeposit, - CurveCuts memory curveCuts - ) external returns (ITermMaxOrder order); } diff --git a/contracts/v1/router/TermMaxRouter_V1_1_2.sol b/contracts/v1/router/TermMaxRouter_V1_1_2.sol index f03d94b6..72a4a146 100644 --- a/contracts/v1/router/TermMaxRouter_V1_1_2.sol +++ b/contracts/v1/router/TermMaxRouter_V1_1_2.sol @@ -227,30 +227,6 @@ contract TermMaxRouter_V1_1_2 is } } - function sellTokens( - address recipient, - ITermMaxMarket market, - uint128 ftInAmt, - uint128 xtInAmt, - ITermMaxOrder[] memory orders, - uint128[] memory amtsToSellTokens, - uint128 minTokenOut, - uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { - (IERC20 ft, IERC20 xt,,, IERC20 debtToken) = market.tokens(); - (uint256 maxBurn, IERC20 toenToSell) = ftInAmt > xtInAmt ? (xtInAmt, ft) : (ftInAmt, xt); - - ft.safeTransferFrom(msg.sender, address(this), ftInAmt); - ft.safeIncreaseAllowance(address(market), maxBurn); - xt.safeTransferFrom(msg.sender, address(this), xtInAmt); - xt.safeIncreaseAllowance(address(market), maxBurn); - market.burn(recipient, maxBurn); - netTokenOut = _swapExactTokenToToken(toenToSell, debtToken, recipient, orders, amtsToSellTokens, 0, deadline); - netTokenOut += maxBurn; - if (netTokenOut < minTokenOut) revert InsufficientTokenOut(address(debtToken), netTokenOut, minTokenOut); - emit SellTokens(market, msg.sender, recipient, ftInAmt, xtInAmt, orders, amtsToSellTokens, netTokenOut); - } - function leverageFromToken( address recipient, ITermMaxMarket market, @@ -521,35 +497,6 @@ contract TermMaxRouter_V1_1_2 is debtToken.safeTransfer(recipient, netTokenOut); } - function flashRepayToGetCollateral( - address recipient, - ITermMaxMarket market, - uint256 gtId, - uint256 expectedOutput, - SwapUnit[] memory units - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { - (IERC20 ft,, IGearingToken gtToken, address collateralAddr, IERC20 debtToken) = market.tokens(); - assembly { - // set callback address - tstore(T_CALLBACK_ADDRESS_STORE, gtToken) - } - gtToken.safeTransferFrom(msg.sender, address(this), gtId, ""); - bool byDebtToken = true; - ITermMaxOrder[] memory orders = new ITermMaxOrder[](0); - uint128[] memory amtsToBuyFt = new uint128[](0); - gtToken.flashRepay(gtId, byDebtToken, abi.encode(orders, amtsToBuyFt, ft, units, 0)); - netTokenOut = IERC20(collateralAddr).balanceOf(address(this)); - if (netTokenOut < expectedOutput) { - revert InsufficientTokenOut(collateralAddr, expectedOutput, netTokenOut); - } - IERC20(collateralAddr).safeTransfer(recipient, netTokenOut); - // transfer remaining debt token to recipient - uint256 debtBalance = debtToken.balanceOf(address(this)); - if (debtBalance != 0) { - debtToken.safeTransfer(recipient, debtBalance); - } - } - /** * @inheritdoc ITermMaxRouter */ @@ -605,33 +552,6 @@ contract TermMaxRouter_V1_1_2 is return redeemedAmt; } - function createOrderAndDeposit( - ITermMaxMarket market, - address maker, - uint256 maxXtReserve, - ISwapCallback swapTrigger, - uint256 debtTokenToDeposit, - uint128 ftToDeposit, - uint128 xtToDeposit, - CurveCuts memory curveCuts - ) external nonReentrant whenNotPaused returns (ITermMaxOrder order) { - (IERC20 ft, IERC20 xt,,, IERC20 debtToken) = market.tokens(); - order = market.createOrder(maker, maxXtReserve, swapTrigger, curveCuts); - if (debtTokenToDeposit > 0) { - debtToken.safeTransferFrom(msg.sender, address(this), debtTokenToDeposit); - debtToken.safeIncreaseAllowance(address(market), debtTokenToDeposit); - market.mint(address(order), debtTokenToDeposit); - } - if (ftToDeposit > 0) { - ft.safeTransferFrom(msg.sender, address(order), ftToDeposit); - } - if (xtToDeposit > 0) { - xt.safeTransferFrom(msg.sender, address(order), xtToDeposit); - } - - emit CreateOrderAndDeposit(market, order, maker, debtTokenToDeposit, ftToDeposit, xtToDeposit, curveCuts); - } - /// @dev Market flash leverage flashloan callback function executeOperation(address, IERC20, uint256 amount, bytes memory data) external From 3a68578392f3f1683c9c97733c8fae92e45ef63b Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 17:12:26 +0800 Subject: [PATCH 06/21] always use market as parameter in router abi --- contracts/v1/router/ITermMaxRouter.sol | 2 -- contracts/v2/router/ITermMaxRouterV2.sol | 16 ++++++++++------ contracts/v2/router/TermMaxRouterV2.sol | 19 ++++++++++--------- test/v2/RouterV2.t.sol | 4 ++-- test/v2/integration/ForkPrdRollOver.t.sol | 6 +++--- .../integration/ForkPrdRollOverToThird.t.sol | 4 ++-- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/contracts/v1/router/ITermMaxRouter.sol b/contracts/v1/router/ITermMaxRouter.sol index 6c80be01..d86b6eaa 100644 --- a/contracts/v1/router/ITermMaxRouter.sol +++ b/contracts/v1/router/ITermMaxRouter.sol @@ -102,7 +102,6 @@ interface ITermMaxRouter { uint256 deadline ) external returns (uint256 netTokenIn); - /** * @notice Creates a leveraged position from input tokens * @dev Swaps tokens for XT and creates a leveraged position @@ -267,5 +266,4 @@ interface ITermMaxRouter { SwapUnit[] memory units, uint256 minTokenOut ) external returns (uint256 redeemedAmt); - } diff --git a/contracts/v2/router/ITermMaxRouterV2.sol b/contracts/v2/router/ITermMaxRouterV2.sol index 153976fc..7e81fcf9 100644 --- a/contracts/v2/router/ITermMaxRouterV2.sol +++ b/contracts/v2/router/ITermMaxRouterV2.sol @@ -157,7 +157,7 @@ interface ITermMaxRouterV2 { /** * @notice Rollover GT position * @dev This function allows users to rollover their GT position to a new market or third-protocol - * @param gtToken The GearingToken contract instance + * @param market The current market of the GT position * @param gtId The ID of the GT token being rolled over * @param additionalAsset The additional asset(debt token, old collateral token, new collateral token) to reduce the LTV * @param additionalAmt Amount of the additional asset @@ -170,7 +170,7 @@ interface ITermMaxRouterV2 { * @return newGtId The ID of the newly created GT token in the next market, newGtId is zero if rollover to Aave or Morpho */ function rolloverGt( - IGearingToken gtToken, + ITermMaxMarket market, uint256 gtId, IERC20 additionalAsset, uint256 additionalAmt, @@ -183,14 +183,18 @@ interface ITermMaxRouterV2 { * @dev input/output: =>, swap: -> * path 0: => any token -> debt token/ft token => router * path 1(optional): remaining debt token => recipient - * @param gt The GearingToken contract instance + * @param market The market to repay debt in * @param gtId The ID of the GearingToken position to repay * @param repayAmt The amount to repay * @param byDebtToken Indicates if the repayment is by debt token * @param paths The SwapPath struct defining the swap operations * @return netOutOrIns The net amounts of tokens received or cost when swapping */ - function swapAndRepay(IGearingToken gt, uint256 gtId, uint128 repayAmt, bool byDebtToken, SwapPath[] memory paths) - external - returns (uint256[] memory netOutOrIns); + function swapAndRepay( + ITermMaxMarket market, + uint256 gtId, + uint128 repayAmt, + bool byDebtToken, + SwapPath[] memory paths + ) external returns (uint256[] memory netOutOrIns); } diff --git a/contracts/v2/router/TermMaxRouterV2.sol b/contracts/v2/router/TermMaxRouterV2.sol index 4f4b981a..93a31a01 100644 --- a/contracts/v2/router/TermMaxRouterV2.sol +++ b/contracts/v2/router/TermMaxRouterV2.sol @@ -329,12 +329,13 @@ contract TermMaxRouterV2 is } function rolloverGt( - IGearingToken gtToken, + ITermMaxMarket market, uint256 gtId, IERC20 additionalAsset, uint256 additionalAmt, bytes memory rolloverData ) external nonReentrant whenNotPaused returns (uint256 newGtId) { + (,, IGearingToken gtToken,,) = market.tokens(); return _rolloverGt(gtToken, gtId, additionalAsset, additionalAmt, rolloverData); } @@ -369,14 +370,14 @@ contract TermMaxRouterV2 is /** * @inheritdoc ITermMaxRouterV2 */ - function swapAndRepay(IGearingToken gt, uint256 gtId, uint128 repayAmt, bool byDebtToken, SwapPath[] memory paths) - external - override - nonReentrant - whenNotPaused - checkSwapPaths(paths) - returns (uint256[] memory netOutOrIns) - { + function swapAndRepay( + ITermMaxMarket market, + uint256 gtId, + uint128 repayAmt, + bool byDebtToken, + SwapPath[] memory paths + ) external override nonReentrant whenNotPaused checkSwapPaths(paths) returns (uint256[] memory netOutOrIns) { + (,, IGearingToken gt,,) = market.tokens(); netOutOrIns = _executeSwapPaths(paths); IERC20 repayToken = IERC20(paths[0].units[paths[0].units.length - 1].tokenOut); repayToken.safeIncreaseAllowance(address(gt), repayAmt); diff --git a/test/v2/RouterV2.t.sol b/test/v2/RouterV2.t.sol index be0b9c54..1f1169e3 100644 --- a/test/v2/RouterV2.t.sol +++ b/test/v2/RouterV2.t.sol @@ -927,7 +927,7 @@ contract RouterTestV2 is Test { vm.expectEmit(true, true, true, true); emit RouterEventsV2.SwapAndRepay(address(res.gt), gtId, debtAmt, 0); - uint256 netCost = res.router.swapAndRepay(res.gt, gtId, debtAmt, false, inputPaths)[0]; + uint256 netCost = res.router.swapAndRepay(res.market, gtId, debtAmt, false, inputPaths)[0]; assertEq(res.debt.balanceOf(sender), maxTokenIn - netCost); assertEq(res.collateral.balanceOf(sender), collateralAmt); @@ -974,7 +974,7 @@ contract RouterTestV2 is Test { res.debt.mint(sender, maxTokenIn); res.debt.approve(address(res.router), maxTokenIn); - uint256 netCost = res.router.swapAndRepay(res.gt, gtId, debtAmt / 2, false, inputPaths)[0]; + uint256 netCost = res.router.swapAndRepay(res.market, gtId, debtAmt / 2, false, inputPaths)[0]; assertEq(res.debt.balanceOf(sender), maxTokenIn - netCost); assertEq(res.collateral.balanceOf(sender), 0); diff --git a/test/v2/integration/ForkPrdRollOver.t.sol b/test/v2/integration/ForkPrdRollOver.t.sol index 1114c3b2..9034fe62 100644 --- a/test/v2/integration/ForkPrdRollOver.t.sol +++ b/test/v2/integration/ForkPrdRollOver.t.sol @@ -220,7 +220,7 @@ contract ForkPrdRollover is ForkBaseTestV2 { abi.encode(FlashRepayOptions.ROLLOVER, abi.encode(borrower, maug_1, maxLtv, collateralPath, debtPaths)); uint256 additionalAmt = additionalAssets; IERC20 additionalAsset = IERC20(usdc); - uint256 gtId2 = router.rolloverGt(gt, gt1, additionalAsset, additionalAmt, rolloverData); + uint256 gtId2 = router.rolloverGt(mmay_30, gt1, additionalAsset, additionalAmt, rolloverData); console.log("new gtId:", gtId2); } @@ -314,7 +314,7 @@ contract ForkPrdRollover is ForkBaseTestV2 { uint256 additionalAmt = additionalCollateral; IERC20 additionalAsset = IERC20(pt_susde_jun_31); - uint256 gtId2 = router.rolloverGt(gt, gt1, additionalAsset, additionalAmt, rolloverData); + uint256 gtId2 = router.rolloverGt(mmay_30, gt1, additionalAsset, additionalAmt, rolloverData); console.log("new gtId:", gtId2); } @@ -406,7 +406,7 @@ contract ForkPrdRollover is ForkBaseTestV2 { bytes memory rolloverData = abi.encode(FlashRepayOptions.ROLLOVER, abi.encode(borrower, maug_1, maxLtv, collateralPath, debtPaths)); - uint256 gtId2 = router.rolloverGt(gt, gt1, additionalAsset, additionalCollateral, rolloverData); + uint256 gtId2 = router.rolloverGt(mmay_30, gt1, additionalAsset, additionalCollateral, rolloverData); console.log("new gtId:", gtId2); } diff --git a/test/v2/integration/ForkPrdRollOverToThird.t.sol b/test/v2/integration/ForkPrdRollOverToThird.t.sol index 98397e68..97d5d74e 100644 --- a/test/v2/integration/ForkPrdRollOverToThird.t.sol +++ b/test/v2/integration/ForkPrdRollOverToThird.t.sol @@ -186,7 +186,7 @@ contract ForkPrdRollOverToThird is ForkBaseTestV2 { abi.encode(collateral, aave, interestRateMode, referralCode, params, collateralPath) ); - router.rolloverGt(gt, gt1, additionalAsset, additionalAmt, rolloverData); + router.rolloverGt(mmay_30, gt1, additionalAsset, additionalAmt, rolloverData); } vm.stopPrank(); @@ -245,7 +245,7 @@ contract ForkPrdRollOverToThird is ForkBaseTestV2 { FlashRepayOptions.ROLLOVER_MORPHO, abi.encode(collateral, morpho, marketId, authorization, sig, collateralPath) ); - router.rolloverGt(gt, gt1, additionalAsset, additionalAmt, rolloverData); + router.rolloverGt(mjul_31, gt1, additionalAsset, additionalAmt, rolloverData); } vm.stopPrank(); From fd63cc0704da7b8d73482aa511bac4f4dfab90ce Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 18:39:18 +0800 Subject: [PATCH 07/21] implement whitelist check in TermMaxRouter and TermMaxRouterV2, update deployment scripts and tests --- contracts/v1/router/TermMaxRouter_V1_1_2.sol | 38 +++++++------ contracts/v2/router/TermMaxRouterV2.sol | 54 ++++++++++--------- script/deploy/DeployBaseV2.s.sol | 22 ++++---- test/v2/AccessManagerV2.t.sol | 2 +- test/v2/RouterV2.t.sol | 11 ++-- .../integration/ForkKodiakSwapAdapter.t.sol | 1 - .../v2/integration/ForkOkxSwapAdapterV2.t.sol | 1 - .../integration/ForkOneInchSwapAdapter.t.sol | 1 - .../v2/integration/ForkPancakeAdapterV2.t.sol | 1 - .../integration/ForkPancakeSmartAdapter.t.sol | 1 - test/v2/integration/ForkPrdFlashRepay.t.sol | 1 - test/v2/integration/ForkPrdRollOver.t.sol | 1 - .../integration/ForkPrdRollOverToThird.t.sol | 1 - .../integration/ForkStrataVaultAdapter.t.sol | 1 - test/v2/integration/ForkTerminal.t.sol | 1 - .../v2/integration/ForkUniswapAdapterV2.t.sol | 1 - test/v2/utils/DeployUtils.sol | 8 +-- 17 files changed, 72 insertions(+), 74 deletions(-) diff --git a/contracts/v1/router/TermMaxRouter_V1_1_2.sol b/contracts/v1/router/TermMaxRouter_V1_1_2.sol index 72a4a146..3733b3c8 100644 --- a/contracts/v1/router/TermMaxRouter_V1_1_2.sol +++ b/contracts/v1/router/TermMaxRouter_V1_1_2.sol @@ -27,6 +27,7 @@ import {ISwapCallback} from "../ISwapCallback.sol"; import {Constants} from "../lib/Constants.sol"; import {MathLib} from "../lib/MathLib.sol"; import {IGtRepayer} from "./IGtRepayer.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../../v2/access/WithWhitelistCheck.sol"; /** * @title TermMax Router V1.1.2 @@ -44,7 +45,8 @@ contract TermMaxRouter_V1_1_2 is RouterErrors, RouterEvents, IGtRepayer, - ReentrancyGuardUpgradeable + ReentrancyGuardUpgradeable, + WithWhitelistCheck { using SafeCast for *; using TransferUtils for IERC20; @@ -78,6 +80,10 @@ contract TermMaxRouter_V1_1_2 is function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} + constructor(address _whitelistManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) + {} + function initialize(address admin) public initializer { __ReentrancyGuard_init_unchained(); __UUPSUpgradeable_init(); @@ -237,7 +243,7 @@ contract TermMaxRouter_V1_1_2 is uint128 maxLtv, SwapUnit[] memory units, uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256 gtId, uint256 netXtOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 gtId, uint256 netXtOut) { assembly { tstore(T_CALLBACK_ADDRESS_STORE, market) // set callback address } @@ -268,7 +274,7 @@ contract TermMaxRouter_V1_1_2 is uint128 tokenInAmt, uint128 maxLtv, SwapUnit[] memory units - ) external nonReentrant whenNotPaused returns (uint256 gtId) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 gtId) { assembly { tstore(T_CALLBACK_ADDRESS_STORE, market) // set callback address } @@ -312,7 +318,7 @@ contract TermMaxRouter_V1_1_2 is uint128 xtInAmt, uint128 minTokenOutAmt, SwapUnit[] memory units - ) external nonReentrant whenNotPaused returns (uint256 gtId) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 gtId) { assembly { tstore(T_CALLBACK_ADDRESS_STORE, market) // set callback address } @@ -354,7 +360,7 @@ contract TermMaxRouter_V1_1_2 is uint128 collateralInAmt, uint128 maxLtv, SwapUnit[] memory units - ) external nonReentrant whenNotPaused returns (uint256 gtId) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 gtId) { assembly { tstore(T_CALLBACK_ADDRESS_STORE, market) // set callback address } @@ -387,7 +393,7 @@ contract TermMaxRouter_V1_1_2 is uint128[] memory tokenAmtsWantBuy, uint128 maxDebtAmt, uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256) { (IERC20 ft,, IGearingToken gt, address collateralAddr, IERC20 debtToken) = market.tokens(); IERC20(collateralAddr).safeTransferFrom(msg.sender, address(this), collInAmt); IERC20(collateralAddr).safeIncreaseAllowance(address(gt), collInAmt); @@ -410,6 +416,7 @@ contract TermMaxRouter_V1_1_2 is external nonReentrant whenNotPaused + onlyWhitelisted(address(market)) returns (uint256) { (IERC20 ft, IERC20 xt, IGearingToken gt, address collateralAddr,) = market.tokens(); @@ -438,6 +445,7 @@ contract TermMaxRouter_V1_1_2 is external nonReentrant whenNotPaused + onlyWhitelisted(address(market)) { (IERC20 ft, IERC20 xt, IGearingToken gt,,) = market.tokens(); @@ -468,7 +476,7 @@ contract TermMaxRouter_V1_1_2 is bool byDebtToken, SwapUnit[] memory units, uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 netTokenOut) { revert("Use flashRepayFromColl with expectedOutput param"); } @@ -482,7 +490,7 @@ contract TermMaxRouter_V1_1_2 is uint256 expectedOutput, SwapUnit[] memory units, uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 netTokenOut) { (IERC20 ft,, IGearingToken gtToken,, IERC20 debtToken) = market.tokens(); assembly { // set callback address @@ -508,7 +516,7 @@ contract TermMaxRouter_V1_1_2 is uint128[] memory ftAmtsWantBuy, uint128 maxTokenIn, uint256 deadline - ) external nonReentrant whenNotPaused returns (uint256 returnAmt) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 returnAmt) { (IERC20 ft,, IGearingToken gt,, IERC20 debtToken) = market.tokens(); debtToken.safeTransferFrom(msg.sender, address(this), maxTokenIn); @@ -538,7 +546,7 @@ contract TermMaxRouter_V1_1_2 is uint256 ftAmount, SwapUnit[] memory units, uint256 minTokenOut - ) external nonReentrant whenNotPaused returns (uint256) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256) { (IERC20 ft,,, address collateralAddr, IERC20 debtToken) = market.tokens(); ft.safeTransferFrom(msg.sender, address(this), ftAmount); ft.safeIncreaseAllowance(address(market), ftAmount); @@ -585,9 +593,7 @@ contract TermMaxRouter_V1_1_2 is uint256 totalAmount = amount + tokenInAmt; collateralData = _doSwap(abi.encode(totalAmount), units); SwapUnit memory lastUnit = units[units.length - 1]; - if (!adapterWhitelist[lastUnit.adapter]) { - revert AdapterNotWhitelisted(lastUnit.adapter); - } + _checkWhitelisted(lastUnit.adapter, IWhitelistManager.ContractModule.ADAPTER); if (flashLoanType == FlashLoanType.COLLATERAL) { IERC20 collateral = IERC20(lastUnit.tokenOut); @@ -647,9 +653,8 @@ contract TermMaxRouter_V1_1_2 is revert SwapUnitsIsEmpty(); } for (uint256 i = 0; i < units.length; ++i) { - if (!adapterWhitelist[units[i].adapter]) { - revert AdapterNotWhitelisted(units[i].adapter); - } + _checkWhitelisted(units[i].adapter, IWhitelistManager.ContractModule.ADAPTER); + bytes memory dataToSwap = abi.encodeCall(ISwapAdapter.swap, (units[i].tokenIn, units[i].tokenOut, inputData, units[i].swapData)); @@ -679,6 +684,7 @@ contract TermMaxRouter_V1_1_2 is override nonReentrant whenNotPaused + onlyWhitelisted(address(market)) returns (uint128 repayAmt) { (IERC20 ft,, IGearingToken gt,, IERC20 debtToken) = market.tokens(); diff --git a/contracts/v2/router/TermMaxRouterV2.sol b/contracts/v2/router/TermMaxRouterV2.sol index 93a31a01..81af84fc 100644 --- a/contracts/v2/router/TermMaxRouterV2.sol +++ b/contracts/v2/router/TermMaxRouterV2.sol @@ -31,7 +31,7 @@ import {IMorpho, Id, MarketParams, Authorization, Signature} from "../extensions import {RouterErrorsV2} from "../errors/RouterErrorsV2.sol"; import {RouterEventsV2} from "../events/RouterEventsV2.sol"; import {ArrayUtilsV2} from "../lib/ArrayUtilsV2.sol"; -import {IWhitelistManager} from "../access/IWhitelistManager.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; /** @@ -49,7 +49,8 @@ contract TermMaxRouterV2 is RouterErrors, RouterEvents, VersionV2, - ReentrancyGuardUpgradeable + ReentrancyGuardUpgradeable, + WithWhitelistCheck { using SafeCast for *; using TransferUtilsV2 for IERC20; @@ -58,7 +59,8 @@ contract TermMaxRouterV2 is /// @notice whitelist mapping of adapter mapping(address => bool) public adapterWhitelist; - IWhitelistManager internal whitelistManager; + /// @dev deprecated: whitelistManager moved to immutable via WithWhitelistCheck + IWhitelistManager internal __deprecated_whitelistManager; uint256 private constant T_ROLLOVER_GT_RESERVE_STORE = 0; uint256 private constant T_CALLBACK_ADDRESS_STORE = 1; @@ -82,28 +84,21 @@ contract TermMaxRouterV2 is _; } + constructor(address _whitelistManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) + {} + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} - function initialize(address admin, address whitelistManager_) external initializer { + function initialize(address admin) external initializer { __ReentrancyGuard_init_unchained(); __UUPSUpgradeable_init_unchained(); __Pausable_init_unchained(); __Ownable_init_unchained(admin); - _setWhitelistManager(whitelistManager_); } - function initializeV2(address whitelistManager_) external reinitializer(2) { + function initializeV2() external reinitializer(2) { __ReentrancyGuard_init_unchained(); - _setWhitelistManager(whitelistManager_); - } - - function setWhitelistManager(address whitelistManager_) external onlyOwner { - _setWhitelistManager(whitelistManager_); - } - - function _setWhitelistManager(address whitelistManager_) internal { - whitelistManager = IWhitelistManager(whitelistManager_); - emit RouterEventsV2.WhitelistManagerUpdated(whitelistManager_); } /** @@ -179,7 +174,7 @@ contract TermMaxRouterV2 is SwapPath[] memory inputPaths, SwapPath memory swapXtPath, SwapPath memory swapCollateralPath - ) external nonReentrant whenNotPaused returns (uint256 gtId, uint256 netXtOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 gtId, uint256 netXtOut) { assembly { tstore(T_CALLBACK_ADDRESS_STORE, market) // set callback address } @@ -225,7 +220,7 @@ contract TermMaxRouterV2 is uint256 collInAmt, uint128 maxDebtAmt, SwapPath memory swapFtPath - ) external nonReentrant whenNotPaused returns (uint256) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256) { (IERC20 ft,, IGearingToken gt, address collateralAddr,) = market.tokens(); IERC20(collateralAddr).safeTransferFrom(_msgSender(), address(this), collInAmt); IERC20(collateralAddr).safeIncreaseAllowance(address(gt), collInAmt); @@ -249,7 +244,7 @@ contract TermMaxRouterV2 is uint256 collInAmt, uint256 borrowAmt, bool isV1 - ) external nonReentrant whenNotPaused returns (uint256) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256) { (IERC20 ft, IERC20 xt, IGearingToken gt, address collateralAddr,) = market.tokens(); IERC20(collateralAddr).safeTransferFrom(_msgSender(), address(this), collInAmt); @@ -280,7 +275,7 @@ contract TermMaxRouterV2 is bool byDebtToken, uint256 expectedOutput, bytes memory callbackData - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 netTokenOut) { return _flashRepayFromCollateral(recipient, market, gtId, byDebtToken, expectedOutput, callbackData, false); } @@ -322,7 +317,7 @@ contract TermMaxRouterV2 is uint256 gtId, uint256 expectedOutput, bytes memory callbackData - ) external nonReentrant whenNotPaused returns (uint256 netTokenOut) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 netTokenOut) { /// @dev flashRepayToGetCollateral always repays by debt token bool byDebtToken = true; return _flashRepayFromCollateral(recipient, market, gtId, byDebtToken, expectedOutput, callbackData, true); @@ -334,7 +329,7 @@ contract TermMaxRouterV2 is IERC20 additionalAsset, uint256 additionalAmt, bytes memory rolloverData - ) external nonReentrant whenNotPaused returns (uint256 newGtId) { + ) external nonReentrant whenNotPaused onlyWhitelisted(address(market)) returns (uint256 newGtId) { (,, IGearingToken gtToken,,) = market.tokens(); return _rolloverGt(gtToken, gtId, additionalAsset, additionalAmt, rolloverData); } @@ -376,7 +371,15 @@ contract TermMaxRouterV2 is uint128 repayAmt, bool byDebtToken, SwapPath[] memory paths - ) external override nonReentrant whenNotPaused checkSwapPaths(paths) returns (uint256[] memory netOutOrIns) { + ) + external + override + nonReentrant + whenNotPaused + onlyWhitelisted(address(market)) + checkSwapPaths(paths) + returns (uint256[] memory netOutOrIns) + { (,, IGearingToken gt,,) = market.tokens(); netOutOrIns = _executeSwapPaths(paths); IERC20 repayToken = IERC20(paths[0].units[paths[0].units.length - 1].tokenOut); @@ -451,6 +454,7 @@ contract TermMaxRouterV2 is SwapPath memory collateralPath, SwapPath memory debtTokenPath ) = abi.decode(callbackData, (address, ITermMaxMarket, uint128, SwapPath, SwapPath)); + _checkWhitelisted(address(market)); // Do swap to get the new collateral,(the inpput amount may contains additional old collateral) if (collateralPath.units.length != 0) { @@ -576,9 +580,7 @@ contract TermMaxRouterV2 is } function _checkAdapterWhitelist(address adapter) internal view { - if (!whitelistManager.isWhitelisted(adapter, IWhitelistManager.ContractModule.ADAPTER)) { - revert AdapterNotWhitelisted(adapter); - } + _checkWhitelisted(adapter, IWhitelistManager.ContractModule.ADAPTER); } function onERC721Received(address, address, uint256, bytes memory) external pure override returns (bytes4) { diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index 5bd22bf7..7eabaf77 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -314,9 +314,9 @@ contract DeployBaseV2 is Script { } function deployRouter(address admin, address whitelistManager) public returns (TermMaxRouterV2 router) { - TermMaxRouterV2 implementation = new TermMaxRouterV2(); + TermMaxRouterV2 implementation = new TermMaxRouterV2(whitelistManager); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, whitelistManager)); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); router = TermMaxRouterV2(address(proxy)); } @@ -325,24 +325,26 @@ contract DeployBaseV2 is Script { public returns (TermMaxRouterV2 router) { - TermMaxRouterV2 implementation = new TermMaxRouterV2(); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initializeV2, whitelistManager); + TermMaxRouterV2 implementation = new TermMaxRouterV2(whitelistManager); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initializeV2, ()); manager.upgradeSubContract(UUPSUpgradeable(routerProxy), address(implementation), data); router = TermMaxRouterV2(routerProxy); } - function upgradeRouter(AccessManagerV2 manager, address routerProxy, bytes memory initData) - public - returns (TermMaxRouterV2 router) - { - TermMaxRouterV2 implementation = new TermMaxRouterV2(); + function upgradeRouter( + AccessManagerV2 manager, + address routerProxy, + address whitelistManager, + bytes memory initData + ) public returns (TermMaxRouterV2 router) { + TermMaxRouterV2 implementation = new TermMaxRouterV2(whitelistManager); manager.upgradeSubContract(UUPSUpgradeable(routerProxy), address(implementation), initData); router = TermMaxRouterV2(routerProxy); } function deployMakerHelper(address admin) public returns (MakerHelper makerHelper) { address implementation = address(new MakerHelper()); - bytes memory data = abi.encodeCall(MakerHelper.initialize, admin); + bytes memory data = abi.encodeCall(MakerHelper.initialize, (admin)); address proxy = address(new ERC1967Proxy(address(implementation), data)); makerHelper = MakerHelper(proxy); } diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index ca1adb8e..158d80cf 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -457,7 +457,7 @@ contract AccessManagerTestV2 is Test { vm.startPrank(deployer); // Deploy a new router implementation - TermMaxRouterV2 routerV2 = new TermMaxRouterV2(); + TermMaxRouterV2 routerV2 = new TermMaxRouterV2(address(res.whitelistManager)); // Test upgrade with UPDATER_ROLE manager.upgradeSubContract(UUPSUpgradeable(address(res.router)), address(routerV2), ""); diff --git a/test/v2/RouterV2.t.sol b/test/v2/RouterV2.t.sol index 1f1169e3..3e7d1617 100644 --- a/test/v2/RouterV2.t.sol +++ b/test/v2/RouterV2.t.sol @@ -131,8 +131,7 @@ contract RouterTestV2 is Test { res.ft.transfer(address(res.order), amount); res.xt.transfer(address(res.order), amount); - (res.router, res.whitelistManager) = DeployUtils.deployRouter(deployer); - res.router.setWhitelistManager(address(res.whitelistManager)); + res.router = DeployUtils.deployRouter(deployer, res.whitelistManager); adapter = new MockSwapAdapterV2(pool); termMaxSwapAdapter = new TermMaxSwapAdapter(address(res.whitelistManager)); @@ -146,13 +145,13 @@ contract RouterTestV2 is Test { } function testUpgradeRouterToV2() public { - TermMaxRouterV2 impl = new TermMaxRouterV2(); + TermMaxRouterV2 impl = new TermMaxRouterV2(address(res.whitelistManager)); address admin = vm.randomAddress(); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, vm.randomAddress())); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(impl), data); TermMaxRouterV2 router_tmp = TermMaxRouterV2(address(proxy)); - TermMaxRouterV2 impl2 = new TermMaxRouterV2(); - data = abi.encodeCall(TermMaxRouterV2.initializeV2, (vm.randomAddress())); + TermMaxRouterV2 impl2 = new TermMaxRouterV2(address(res.whitelistManager)); + data = abi.encodeCall(TermMaxRouterV2.initializeV2, ()); vm.prank(admin); router_tmp.upgradeToAndCall(address(impl2), data); diff --git a/test/v2/integration/ForkKodiakSwapAdapter.t.sol b/test/v2/integration/ForkKodiakSwapAdapter.t.sol index 84439cd4..efea69e1 100644 --- a/test/v2/integration/ForkKodiakSwapAdapter.t.sol +++ b/test/v2/integration/ForkKodiakSwapAdapter.t.sol @@ -63,7 +63,6 @@ contract ForkKodiakSwapAdapter is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(kodiakSwapAdapter); diff --git a/test/v2/integration/ForkOkxSwapAdapterV2.t.sol b/test/v2/integration/ForkOkxSwapAdapterV2.t.sol index 770630a0..6707f7c1 100644 --- a/test/v2/integration/ForkOkxSwapAdapterV2.t.sol +++ b/test/v2/integration/ForkOkxSwapAdapterV2.t.sol @@ -68,7 +68,6 @@ contract ForkOkxSwapAdapterV2 is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(okxSwapAdapter); diff --git a/test/v2/integration/ForkOneInchSwapAdapter.t.sol b/test/v2/integration/ForkOneInchSwapAdapter.t.sol index e02d1c12..a8b0d2cb 100644 --- a/test/v2/integration/ForkOneInchSwapAdapter.t.sol +++ b/test/v2/integration/ForkOneInchSwapAdapter.t.sol @@ -68,7 +68,6 @@ contract ForkOneInchSwapAdapter is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(swapAdapter); diff --git a/test/v2/integration/ForkPancakeAdapterV2.t.sol b/test/v2/integration/ForkPancakeAdapterV2.t.sol index 2192d883..f6481fa5 100644 --- a/test/v2/integration/ForkPancakeAdapterV2.t.sol +++ b/test/v2/integration/ForkPancakeAdapterV2.t.sol @@ -63,7 +63,6 @@ contract ForkPancakeAdapterV2 is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(uniswapAdapter); diff --git a/test/v2/integration/ForkPancakeSmartAdapter.t.sol b/test/v2/integration/ForkPancakeSmartAdapter.t.sol index 99f38634..cd0b270a 100644 --- a/test/v2/integration/ForkPancakeSmartAdapter.t.sol +++ b/test/v2/integration/ForkPancakeSmartAdapter.t.sol @@ -60,7 +60,6 @@ contract ForkPancakeSmartAdapter is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); console.log("router", address(router)); console.log("whitelistManager", address(whitelistManager)); diff --git a/test/v2/integration/ForkPrdFlashRepay.t.sol b/test/v2/integration/ForkPrdFlashRepay.t.sol index 1b6a556f..c950a91a 100644 --- a/test/v2/integration/ForkPrdFlashRepay.t.sol +++ b/test/v2/integration/ForkPrdFlashRepay.t.sol @@ -112,7 +112,6 @@ contract ForkPrdFlashRepay is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](2); adapters[0] = pendleAdapter; diff --git a/test/v2/integration/ForkPrdRollOver.t.sol b/test/v2/integration/ForkPrdRollOver.t.sol index 9034fe62..09d3211b 100644 --- a/test/v2/integration/ForkPrdRollOver.t.sol +++ b/test/v2/integration/ForkPrdRollOver.t.sol @@ -120,7 +120,6 @@ contract ForkPrdRollover is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(whitelistManager)); tmxAdapter = address(tmx); diff --git a/test/v2/integration/ForkPrdRollOverToThird.t.sol b/test/v2/integration/ForkPrdRollOverToThird.t.sol index 97d5d74e..cfa5f104 100644 --- a/test/v2/integration/ForkPrdRollOverToThird.t.sol +++ b/test/v2/integration/ForkPrdRollOverToThird.t.sol @@ -102,7 +102,6 @@ contract ForkPrdRollOverToThird is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(whitelistManager)); tmxAdapter = address(tmx); diff --git a/test/v2/integration/ForkStrataVaultAdapter.t.sol b/test/v2/integration/ForkStrataVaultAdapter.t.sol index 4df9eb97..57f01d9c 100644 --- a/test/v2/integration/ForkStrataVaultAdapter.t.sol +++ b/test/v2/integration/ForkStrataVaultAdapter.t.sol @@ -63,7 +63,6 @@ contract ForkStrataVaultAdapter is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(strataAdapter); diff --git a/test/v2/integration/ForkTerminal.t.sol b/test/v2/integration/ForkTerminal.t.sol index 41315857..0c35a70a 100644 --- a/test/v2/integration/ForkTerminal.t.sol +++ b/test/v2/integration/ForkTerminal.t.sol @@ -73,7 +73,6 @@ contract ForkTerminalTest is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(terminalAdapter); diff --git a/test/v2/integration/ForkUniswapAdapterV2.t.sol b/test/v2/integration/ForkUniswapAdapterV2.t.sol index aa2e5584..7ec9fbae 100644 --- a/test/v2/integration/ForkUniswapAdapterV2.t.sol +++ b/test/v2/integration/ForkUniswapAdapterV2.t.sol @@ -63,7 +63,6 @@ contract ForkUniswapAdapterV2 is ForkBaseTestV2 { vm.startPrank(admin); IWhitelistManager whitelistManager; (router, whitelistManager) = deployRouter(admin); - router.setWhitelistManager(address(whitelistManager)); address[] memory adapters = new address[](1); adapters[0] = address(uniswapAdapter); diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index 6cea96df..d24a9478 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -412,15 +412,15 @@ library DeployUtils { function deployRouter(address admin) public returns (TermMaxRouterV2 router, IWhitelistManager whitelistManager) { whitelistManager = deployWhitelistManager(); - TermMaxRouterV2 implementation = new TermMaxRouterV2(); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, address(whitelistManager))); + TermMaxRouterV2 implementation = new TermMaxRouterV2(address(whitelistManager)); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); router = TermMaxRouterV2(address(proxy)); } function deployRouter(address admin, IWhitelistManager whitelistManager) public returns (TermMaxRouterV2 router) { - TermMaxRouterV2 implementation = new TermMaxRouterV2(); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin, address(whitelistManager))); + TermMaxRouterV2 implementation = new TermMaxRouterV2(address(whitelistManager)); + bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); router = TermMaxRouterV2(address(proxy)); } From 17412f561b7d642ad5b2ae6dff2e4a8f3d383b13 Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 21:29:14 +0800 Subject: [PATCH 08/21] fix issues, add owner check when deploying, add Registry logic(regist via accessmanger) --- contracts/v1/router/TermMaxRouter_V1_1_2.sol | 4 ++ contracts/v2/access/WithWhitelistCheck.sol | 19 +++++- contracts/v2/factory/TermMax4626Factory.sol | 18 +++--- contracts/v2/factory/TermMaxFactoryV2.sol | 4 ++ .../v2/factory/TermMaxVaultFactoryV2.sol | 12 +++- contracts/v2/router/TermMaxRouterV2.sol | 4 ++ contracts/v2/test/MockWhitelistManager.sol | 13 +++- contracts/v2/vault/TermMaxVaultV2.sol | 4 ++ script/deploy/DeployBaseV2.s.sol | 11 ++-- test/v2/AccessManagerV2.t.sol | 6 +- test/v2/TermMax4626Factory.t.sol | 61 ++++++++++++++----- test/v2/VaultV2.t.sol | 5 +- test/v2/VaultV2WithPool.t.sol | 5 +- .../invariant/TermMaxVaultV2Invariant.t.sol | 2 +- test/v2/mainnet-fork/ForkBaseTestV2.sol | 15 ++++- test/v2/utils/DeployUtils.sol | 53 +++++++++++----- 16 files changed, 179 insertions(+), 57 deletions(-) diff --git a/contracts/v1/router/TermMaxRouter_V1_1_2.sol b/contracts/v1/router/TermMaxRouter_V1_1_2.sol index 3733b3c8..be176adc 100644 --- a/contracts/v1/router/TermMaxRouter_V1_1_2.sol +++ b/contracts/v1/router/TermMaxRouter_V1_1_2.sol @@ -78,6 +78,10 @@ contract TermMaxRouter_V1_1_2 is _; } + function _getRegistry() internal view override returns (address) { + return owner(); + } + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} constructor(address _whitelistManager) diff --git a/contracts/v2/access/WithWhitelistCheck.sol b/contracts/v2/access/WithWhitelistCheck.sol index 1208b860..0f22010d 100644 --- a/contracts/v2/access/WithWhitelistCheck.sol +++ b/contracts/v2/access/WithWhitelistCheck.sol @@ -3,6 +3,16 @@ pragma solidity ^0.8.0; import {IWhitelistManager} from "./IWhitelistManager.sol"; +/// @notice Minimal interface for the registry (e.g. AccessManagerV2) that can set whitelists +interface IWhitelistRegistry { + function batchSetWhitelist( + IWhitelistManager whitelistManager, + address[] calldata contractAddresses, + IWhitelistManager.ContractModule module, + bool approved + ) external; +} + abstract contract WithWhitelistCheck { error WhitelistManagerNotSet(); error NoWhitelistModuleConfigured(); @@ -17,14 +27,17 @@ abstract contract WithWhitelistCheck { defaultWhitelistModule = _defaultWhitelistModule; } + /// @notice Returns the address of the registry (e.g. AccessManagerV2) that has permission to set whitelists + function _getRegistry() internal view virtual returns (address); + function _registerAddress(address target) internal { - _registerAddressWithMoudle(target, defaultWhitelistModule); + _registerAddressWithModule(target, defaultWhitelistModule); } - function _registerAddressWithMoudle(address target, IWhitelistManager.ContractModule module) internal { + function _registerAddressWithModule(address target, IWhitelistManager.ContractModule module) internal { address[] memory targets = new address[](1); targets[0] = target; - whitelistManager.batchSetWhitelist(targets, module, true); + IWhitelistRegistry(_getRegistry()).batchSetWhitelist(whitelistManager, targets, module, true); } function _checkWhitelisted(address target, IWhitelistManager.ContractModule module) internal view { diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index 731e926b..7e2aeb15 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -50,6 +50,10 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { ); } + function _getRegistry() internal view override returns (address) { + return owner(); + } + function getImplementations(string memory key) external view returns (address) { return implementations[keccak256(abi.encodePacked(key))]; } @@ -83,7 +87,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external returns (StableERC4626For4626) { + ) external onlyOwner returns (StableERC4626For4626) { StableERC4626For4626 instance = StableERC4626For4626(implementations[STABLE_ERC4626_FOR_4626].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -95,7 +99,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external returns (StableERC4626ForVenus) { + ) external onlyOwner returns (StableERC4626ForVenus) { StableERC4626ForVenus instance = StableERC4626ForVenus(implementations[STABLE_ERC4626_FOR_VENUS].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -108,7 +112,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address thirdPool, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external returns (StableERC4626ForCustomize) { + ) external onlyOwner returns (StableERC4626ForCustomize) { StableERC4626ForCustomize instance = StableERC4626ForCustomize(implementations[STABLE_ERC4626_FOR_CUSTOMIZE].clone()); instance.initialize(admin, thirdPool, underlying, bufferConfig); @@ -121,7 +125,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public returns (StableERC4626ForAave) { + ) public onlyOwner returns (StableERC4626ForAave) { StableERC4626ForAave instance = StableERC4626ForAave(implementations[STABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -133,7 +137,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public returns (VariableERC4626ForAave) { + ) public onlyOwner returns (VariableERC4626ForAave) { VariableERC4626ForAave instance = VariableERC4626ForAave(implementations[VARIABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -141,7 +145,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { return instance; } - function create(string memory key, bytes memory initialData) external returns (address) { + function create(string memory key, bytes memory initialData) external onlyOwner returns (address) { address implementation = implementations[keccak256(abi.encodePacked(key))]; if (implementation == address(0)) revert FactoryErrorsV2.ImplementationNotFound(key); address instance = implementation.clone(); @@ -156,7 +160,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external returns (VariableERC4626ForAave, StableERC4626ForAave) { + ) external onlyOwner returns (VariableERC4626ForAave, StableERC4626ForAave) { VariableERC4626ForAave variableInstance = createVariableERC4626ForAave(admin, underlying, bufferConfig); StableERC4626ForAave stableInstance = createStableERC4626ForAave(admin, underlying, bufferConfig); return (variableInstance, stableInstance); diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index e31ea419..c7da8c39 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -91,6 +91,10 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver ); } + function _getRegistry() internal view override returns (address) { + return owner(); + } + /** * @notice Creates a new TermMax market with specified parameters * @dev Clones the market implementation and initializes it with the provided parameters diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index ee935b93..62caa293 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.27; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; +import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {ITermMaxVaultV2} from "../vault/ITermMaxVaultV2.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {ITermMaxVaultFactoryV2} from "./ITermMaxVaultFactoryV2.sol"; @@ -13,13 +14,14 @@ import {VersionV2} from "../VersionV2.sol"; * @title The TermMax vault factory v2 * @author Term Structure Labs */ -contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck { +contract TermMaxVaultFactoryV2 is Ownable2Step, ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck { /** * @notice The implementation of TermMax Vault contract v2 */ address public immutable TERMMAX_VAULT_IMPLEMENTATION; - constructor(address TERMMAX_VAULT_IMPLEMENTATION_, address _whitelistManager) + constructor(address admin, address TERMMAX_VAULT_IMPLEMENTATION_, address _whitelistManager) + Ownable(admin) WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.ORDER_CALLBACK) { TERMMAX_VAULT_IMPLEMENTATION = TERMMAX_VAULT_IMPLEMENTATION_; @@ -40,10 +42,14 @@ contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhiteli ); } + function _getRegistry() internal view override returns (address) { + return owner(); + } + /** * @inheritdoc ITermMaxVaultFactoryV2 */ - function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) public returns (address vault) { + function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) public onlyOwner returns (address vault) { vault = Clones.cloneDeterministic( TERMMAX_VAULT_IMPLEMENTATION, keccak256(abi.encode(msg.sender, initialParams.asset, initialParams.name, initialParams.symbol, salt)) diff --git a/contracts/v2/router/TermMaxRouterV2.sol b/contracts/v2/router/TermMaxRouterV2.sol index 81af84fc..314891fd 100644 --- a/contracts/v2/router/TermMaxRouterV2.sol +++ b/contracts/v2/router/TermMaxRouterV2.sol @@ -88,6 +88,10 @@ contract TermMaxRouterV2 is WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) {} + function _getRegistry() internal view override returns (address) { + return owner(); + } + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} function initialize(address admin) external initializer { diff --git a/contracts/v2/test/MockWhitelistManager.sol b/contracts/v2/test/MockWhitelistManager.sol index 99a77d99..ec59c202 100644 --- a/contracts/v2/test/MockWhitelistManager.sol +++ b/contracts/v2/test/MockWhitelistManager.sol @@ -2,8 +2,9 @@ pragma solidity ^0.8.0; import {IWhitelistManager} from "../access/IWhitelistManager.sol"; +import {IWhitelistRegistry} from "../access/WithWhitelistCheck.sol"; -contract MockWhitelistManager is IWhitelistManager { +contract MockWhitelistManager is IWhitelistManager, IWhitelistRegistry { mapping(address => mapping(ContractModule => bool)) public whitelist; function setWhitelist(address _user, ContractModule _module, bool _approved) external { @@ -18,6 +19,16 @@ contract MockWhitelistManager is IWhitelistManager { emit WhitelistUpdated(_users, _module, _approved); } + /// @dev IWhitelistRegistry implementation - forwards to the actual whitelist manager + function batchSetWhitelist( + IWhitelistManager _whitelistManager, + address[] calldata _users, + ContractModule _module, + bool _approved + ) external override { + _whitelistManager.batchSetWhitelist(_users, _module, _approved); + } + function isWhitelisted(address _user, ContractModule _module) external view returns (bool) { return whitelist[_user][_module]; } diff --git a/contracts/v2/vault/TermMaxVaultV2.sol b/contracts/v2/vault/TermMaxVaultV2.sol index 41227fc0..d62d2a55 100644 --- a/contracts/v2/vault/TermMaxVaultV2.sol +++ b/contracts/v2/vault/TermMaxVaultV2.sol @@ -92,6 +92,10 @@ contract TermMaxVaultV2 is _disableInitializers(); } + function _getRegistry() internal view override returns (address) { + return owner(); + } + function initialize(VaultInitialParamsV2 memory params) external virtual initializer { __ERC20_init_unchained(params.name, params.symbol); __Ownable_init_unchained(params.admin); diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index 7eabaf77..e781a6c2 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -294,10 +294,13 @@ contract DeployBaseV2 is Script { factory = new TermMaxFactoryV2(admin, address(m), whitelistManager); } - function deployVaultFactory(address whitelistManager) public returns (TermMaxVaultFactoryV2 vaultFactory) { + function deployVaultFactory(address admin, address whitelistManager) + public + returns (TermMaxVaultFactoryV2 vaultFactory) + { OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), whitelistManager); - vaultFactory = new TermMaxVaultFactoryV2(address(implementation), whitelistManager); + vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), whitelistManager); } function deployOracleAggregator(address admin, uint256 oracleTimelock) public returns (OracleAggregatorV2 oracle) { @@ -384,10 +387,10 @@ contract DeployBaseV2 is Script { // deploy factory contracts.factory = deployFactory(address(contracts.accessManager), address(contracts.whitelistManager)); - contracts.vaultFactory = deployVaultFactory(address(contracts.whitelistManager)); + contracts.vaultFactory = deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy vault factory - contracts.vaultFactory = deployVaultFactory(address(contracts.whitelistManager)); + contracts.vaultFactory = deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy 4626 factory { diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index 158d80cf..65e32ad7 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -126,7 +126,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - res.vault = DeployUtils.deployVault(params, res.whitelistManager); + res.vault = DeployUtils.deployVault(address(manager), params, res.whitelistManager); vm.stopPrank(); vm.startPrank(curator); @@ -348,7 +348,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - TermMaxVaultV2 vault = DeployUtils.deployVault(params); + TermMaxVaultV2 vault = DeployUtils.deployVault(address(manager), params); // Grant VAULT_ROLE to the vault manager vm.startPrank(deployer); @@ -728,7 +728,7 @@ contract AccessManagerTestV2 is Test { minApy: 0 }); - TermMaxVaultV2 poolVault = DeployUtils.deployVault(poolParams, res.whitelistManager); + TermMaxVaultV2 poolVault = DeployUtils.deployVault(address(manager), poolParams, res.whitelistManager); ITermMaxVaultV2 poolVaultV2 = ITermMaxVaultV2(address(poolVault)); address vaultManager = vm.randomAddress(); diff --git a/test/v2/TermMax4626Factory.t.sol b/test/v2/TermMax4626Factory.t.sol index eee68f0c..1958a0ae 100644 --- a/test/v2/TermMax4626Factory.t.sol +++ b/test/v2/TermMax4626Factory.t.sol @@ -16,7 +16,8 @@ import {MockVToken} from "contracts/mocks/MockVToken.sol"; import {IAaveV3Pool} from "contracts/v2/extensions/aave/IAaveV3Pool.sol"; import {ERC4626TokenEvents} from "contracts/v2/events/ERC4626TokenEvents.sol"; import {FactoryEventsV2} from "contracts/v2/events/FactoryEventsV2.sol"; -import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; +import {MockWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; +import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; contract TermMax4626FactoryTest is Test { TermMax4626Factory public factory; @@ -38,7 +39,7 @@ contract TermMax4626FactoryTest is Test { StableERC4626ForVenus public implVenus; VariableERC4626ForAave public implVariableAave; StableERC4626ForCustomize public implCustomize; - WhitelistManager public whitelistManager; + MockWhitelistManager public whitelistManager; StakingBuffer.BufferConfig public defaultBufferConfig; @@ -64,7 +65,11 @@ contract TermMax4626FactoryTest is Test { implVariableAave = new VariableERC4626ForAave(address(aavePool), 100); implVenus = new StableERC4626ForVenus(); implCustomize = new StableERC4626ForCustomize(); - whitelistManager = new WhitelistManager(); + whitelistManager = new MockWhitelistManager(); + + // Give admin the MockWhitelistManager code so factory._getRegistry() (which returns owner() == admin) + // can satisfy IWhitelistRegistry calls + vm.etch(admin, address(whitelistManager).code); // Deploy factory factory = new TermMax4626Factory( @@ -77,8 +82,6 @@ contract TermMax4626FactoryTest is Test { address(whitelistManager) ); - whitelistManager.initialize(address(factory)); - // Setup default buffer config defaultBufferConfig = StakingBuffer.BufferConfig({minimumBuffer: 1000e18, maximumBuffer: 10000e18, buffer: 5000e18}); @@ -103,8 +106,9 @@ contract TermMax4626FactoryTest is Test { function testCreateStableERC4626For4626() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626For4626Created(address(this), address(0)); + emit FactoryEventsV2.StableERC4626For4626Created(admin, address(0)); + vm.prank(admin); StableERC4626For4626 vault = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); assertTrue(address(vault) != address(0)); @@ -126,8 +130,9 @@ contract TermMax4626FactoryTest is Test { function testCreateStableERC4626ForAave() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.StableERC4626ForAaveCreated(admin, address(0)); + vm.prank(admin); StableERC4626ForAave vault = factory.createStableERC4626ForAave(admin, address(underlying), defaultBufferConfig); assertTrue(address(vault) != address(0)); @@ -149,8 +154,9 @@ contract TermMax4626FactoryTest is Test { function testCreateVariableERC4626ForAave() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.VariableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.VariableERC4626ForAaveCreated(admin, address(0)); + vm.prank(admin); VariableERC4626ForAave vault = factory.createVariableERC4626ForAave(admin, address(underlying), defaultBufferConfig); @@ -173,9 +179,11 @@ contract TermMax4626FactoryTest is Test { function testCreateMultipleVaultsWithSameParameters() public { // Create first vault + vm.prank(admin); StableERC4626For4626 vault1 = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); // Create second vault with same parameters + vm.prank(admin); StableERC4626For4626 vault2 = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); // Should create different addresses @@ -191,8 +199,10 @@ contract TermMax4626FactoryTest is Test { } function testCreateVaultsWithDifferentAdmins() public { + vm.prank(admin); StableERC4626For4626 vault1 = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); + vm.prank(admin); StableERC4626For4626 vault2 = factory.createStableERC4626For4626(user1, address(thirdPool), defaultBufferConfig); assertEq(vault1.owner(), admin); @@ -206,7 +216,9 @@ contract TermMax4626FactoryTest is Test { StakingBuffer.BufferConfig memory config2 = StakingBuffer.BufferConfig({minimumBuffer: 2000e18, maximumBuffer: 20000e18, buffer: 10000e18}); + vm.prank(admin); StableERC4626For4626 vault1 = factory.createStableERC4626For4626(admin, address(thirdPool), config1); + vm.prank(admin); StableERC4626For4626 vault2 = factory.createStableERC4626For4626(admin, address(thirdPool), config2); (uint256 min1, uint256 max1, uint256 buf1) = vault1.bufferConfig(); @@ -223,21 +235,25 @@ contract TermMax4626FactoryTest is Test { function testCreateWithZeroAddressAdmin() public { vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626For4626(address(0), address(thirdPool), defaultBufferConfig); } function testCreateStableERC4626For4626WithZeroThirdPool() public { vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626For4626(admin, address(0), defaultBufferConfig); } function testCreateStableERC4626ForAaveWithZeroUnderlying() public { vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626ForAave(admin, address(0), defaultBufferConfig); } function testCreateVariableERC4626ForAaveWithZeroUnderlying() public { vm.expectRevert(); + vm.prank(admin); factory.createVariableERC4626ForAave(admin, address(0), defaultBufferConfig); } @@ -247,36 +263,42 @@ contract TermMax4626FactoryTest is Test { StakingBuffer.BufferConfig({minimumBuffer: 10000e18, maximumBuffer: 5000e18, buffer: 7500e18}); vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626For4626(admin, address(thirdPool), invalidConfig); // Test buffer outside min/max range (below minimum) invalidConfig = StakingBuffer.BufferConfig({minimumBuffer: 5000e18, maximumBuffer: 10000e18, buffer: 4000e18}); vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626For4626(admin, address(thirdPool), invalidConfig); // Test buffer outside min/max range (above maximum) invalidConfig = StakingBuffer.BufferConfig({minimumBuffer: 5000e18, maximumBuffer: 10000e18, buffer: 11000e18}); vm.expectRevert(); + vm.prank(admin); factory.createStableERC4626For4626(admin, address(thirdPool), invalidConfig); } function testEventEmissions() public { // Test StableERC4626For4626Created event vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626For4626Created(address(this), address(0)); + emit FactoryEventsV2.StableERC4626For4626Created(admin, address(0)); + vm.prank(admin); StableERC4626For4626 vault1 = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); // Test StableERC4626ForAaveCreated event vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.StableERC4626ForAaveCreated(admin, address(0)); + vm.prank(admin); StableERC4626ForAave vault2 = factory.createStableERC4626ForAave(admin, address(underlying), defaultBufferConfig); // Test VariableERC4626ForAaveCreated event vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.VariableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.VariableERC4626ForAaveCreated(admin, address(0)); + vm.prank(admin); VariableERC4626ForAave vault3 = factory.createVariableERC4626ForAave(admin, address(underlying), defaultBufferConfig); @@ -310,6 +332,7 @@ contract TermMax4626FactoryTest is Test { function testVaultFunctionality() public { // Create a vault and test basic functionality + vm.prank(admin); StableERC4626For4626 stableVault = factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); @@ -339,6 +362,7 @@ contract TermMax4626FactoryTest is Test { function testGasUsage() public { uint256 gasBefore = gasleft(); + vm.prank(admin); factory.createStableERC4626For4626(admin, address(thirdPool), defaultBufferConfig); uint256 gasUsed = gasBefore - gasleft(); @@ -347,6 +371,7 @@ contract TermMax4626FactoryTest is Test { emit log_named_uint("Gas used for createStableERC4626For4626", gasUsed); gasBefore = gasleft(); + vm.prank(admin); factory.createStableERC4626ForAave(admin, address(underlying), defaultBufferConfig); gasUsed = gasBefore - gasleft(); @@ -354,6 +379,7 @@ contract TermMax4626FactoryTest is Test { emit log_named_uint("Gas used for createStableERC4626ForAave", gasUsed); gasBefore = gasleft(); + vm.prank(admin); factory.createVariableERC4626ForAave(admin, address(underlying), defaultBufferConfig); gasUsed = gasBefore - gasleft(); @@ -377,8 +403,10 @@ contract TermMax4626FactoryTest is Test { StakingBuffer.BufferConfig({minimumBuffer: 1000e18, maximumBuffer: 10000e18, buffer: 5000e18}); // Should still be able to create vaults + vm.prank(admin); StableERC4626For4626 vault1 = factory.createStableERC4626For4626(admin, address(extremePool), extremeBufferConfig); + vm.prank(admin); StableERC4626ForAave vault2 = factory.createStableERC4626ForAave(admin, address(extremeToken), extremeBufferConfig); @@ -388,8 +416,9 @@ contract TermMax4626FactoryTest is Test { function testCreateStableERC4626ForVenus() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626ForVenusCreated(address(this), address(0)); + emit FactoryEventsV2.StableERC4626ForVenusCreated(admin, address(0)); + vm.prank(admin); StableERC4626ForVenus vault = factory.createStableERC4626ForVenus(admin, address(venusPool), defaultBufferConfig); @@ -401,8 +430,9 @@ contract TermMax4626FactoryTest is Test { function testCreateStableERC4626ForCustomize() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626ForCustomizeCreated(address(this), address(0)); + emit FactoryEventsV2.StableERC4626ForCustomizeCreated(admin, address(0)); + vm.prank(admin); StableERC4626ForCustomize vault = factory.createStableERC4626ForCustomize(admin, customizePool, address(underlying), defaultBufferConfig); @@ -414,10 +444,11 @@ contract TermMax4626FactoryTest is Test { function testCreateVariableAndStableERC4626ForAave() public { vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.VariableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.VariableERC4626ForAaveCreated(admin, address(0)); vm.expectEmit(true, false, false, false); - emit FactoryEventsV2.StableERC4626ForAaveCreated(address(this), address(0)); + emit FactoryEventsV2.StableERC4626ForAaveCreated(admin, address(0)); + vm.prank(admin); (VariableERC4626ForAave vImpl, StableERC4626ForAave sImpl) = factory.createVariableAndStableERC4626ForAave(admin, address(underlying), defaultBufferConfig); diff --git a/test/v2/VaultV2.t.sol b/test/v2/VaultV2.t.sol index 04f1220e..290efa9d 100644 --- a/test/v2/VaultV2.t.sol +++ b/test/v2/VaultV2.t.sol @@ -143,7 +143,8 @@ contract VaultTestV2 is Test { 0 ); - vault = DeployUtils.deployVault(initialParams, res.whitelistManager); + vault = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); + vm.startPrank(deployer); vm.label(address(vault), "vault"); vm.label(guardian, "guardian"); @@ -489,7 +490,7 @@ contract VaultTestV2 is Test { function testDepositWhenNoOrders() public { initialParams.name = "Vault-DAI2"; initialParams.symbol = "Vault-DAI2"; - TermMaxVaultV2 vault2 = DeployUtils.deployVault(initialParams); + TermMaxVaultV2 vault2 = DeployUtils.deployVault(deployer, initialParams); vm.startPrank(deployer); uint256 amount = 10000e8; res.debt.mint(deployer, amount); diff --git a/test/v2/VaultV2WithPool.t.sol b/test/v2/VaultV2WithPool.t.sol index 139b3388..2a034df0 100644 --- a/test/v2/VaultV2WithPool.t.sol +++ b/test/v2/VaultV2WithPool.t.sol @@ -154,7 +154,8 @@ contract VaultV2WithPoolTest is Test { 0 ); - vault = DeployUtils.deployVault(initialParams, res.whitelistManager); + vault = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); + vm.startPrank(deployer); vm.label(address(vault), "vault"); vm.label(guardian, "guardian"); @@ -211,7 +212,7 @@ contract VaultV2WithPoolTest is Test { function testDepositWhenNoOrders() public { initialParams.name = "Vault-DAI2"; initialParams.symbol = "Vault-DAI2"; - TermMaxVaultV2 vault2 = DeployUtils.deployVault(initialParams, res.whitelistManager); + TermMaxVaultV2 vault2 = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); vm.startPrank(deployer); uint256 amount = 10000e8; res.debt.mint(deployer, amount); diff --git a/test/v2/invariant/TermMaxVaultV2Invariant.t.sol b/test/v2/invariant/TermMaxVaultV2Invariant.t.sol index ea2986cc..b29f93fc 100644 --- a/test/v2/invariant/TermMaxVaultV2Invariant.t.sol +++ b/test/v2/invariant/TermMaxVaultV2Invariant.t.sol @@ -590,7 +590,7 @@ contract TermMaxVaultV2InvariantTest is StdInvariant, Test { }); // Use DeployUtils to properly create the vault - vault = DeployUtils.deployVault(vaultParams); + vault = DeployUtils.deployVault(owner, vaultParams); // Setup initial liquidity by depositing assets uint256 initialAmount = 100_000e18; diff --git a/test/v2/mainnet-fork/ForkBaseTestV2.sol b/test/v2/mainnet-fork/ForkBaseTestV2.sol index 087ad17a..2070d9fb 100644 --- a/test/v2/mainnet-fork/ForkBaseTestV2.sol +++ b/test/v2/mainnet-fork/ForkBaseTestV2.sol @@ -27,9 +27,11 @@ import { VaultInitialParams } from "contracts/v1/storage/TermMaxStorage.sol"; import {WhitelistManager, IWhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; +import {MockWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; import {DeployUtils} from "../utils/DeployUtils.sol"; import {JSONLoader} from "../utils/JSONLoader.sol"; import "forge-std/Test.sol"; +import {Vm} from "forge-std/Vm.sol"; abstract contract ForkBaseTestV2 is Test { using SafeCast for *; @@ -139,7 +141,16 @@ abstract contract ForkBaseTestV2 is Test { priceFeed.updateRoundData(roundData); } + /// @dev Etches MockWhitelistManager bytecode onto `admin` if it has no code, + /// so the address can serve as an IWhitelistRegistry implementation. + function _etchMockWhitelistManager(address admin) internal { + if (admin.code.length == 0) { + vm.etch(admin, address(new MockWhitelistManager()).code); + } + } + function deployFactory(address admin) public returns (TermMaxFactoryV2 factory) { + _etchMockWhitelistManager(admin); address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); @@ -148,6 +159,7 @@ abstract contract ForkBaseTestV2 is Test { } function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory) { + _etchMockWhitelistManager(admin); address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); @@ -156,10 +168,11 @@ abstract contract ForkBaseTestV2 is Test { } function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { + _etchMockWhitelistManager(admin); OrderManagerV2 orderManager = new OrderManagerV2(); IWhitelistManager whitelistManager = deployWhitelistManager(admin); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); + vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); } function deployOracleAggregator(address admin) public returns (OracleAggregatorV2 oracle) { diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index d24a9478..b6157c44 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.27; import {console} from "forge-std/Script.sol"; +import {Vm} from "forge-std/Vm.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -37,6 +38,8 @@ import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhi import {OnlyDeliveryGearingToken} from "contracts/v2/tokens/OnlyDeliveryGearingToken.sol"; library DeployUtils { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + bytes32 constant GT_ERC20 = keccak256("GearingTokenWithERC20"); struct SwapRange { @@ -72,6 +75,14 @@ library DeployUtils { IWhitelistManager whitelistManager; } + /// @dev Etch MockWhitelistManager code onto an EOA address so it can serve as IWhitelistRegistry + function _etchRegistry(address target) internal { + if (target.code.length == 0) { + MockWhitelistManager mock = new MockWhitelistManager(); + vm.etch(target, address(mock).code); + } + } + function deployMarket(address admin, MarketConfig memory marketConfig, uint32 maxLtv, uint32 liquidationLtv) internal returns (Res memory res) @@ -375,6 +386,7 @@ library DeployUtils { address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); IWhitelistManager whitelistManager = deployWhitelistManager(); + _etchRegistry(admin); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } @@ -385,6 +397,7 @@ library DeployUtils { address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); + _etchRegistry(admin); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } @@ -396,14 +409,26 @@ library DeployUtils { address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); whitelistManager = deployWhitelistManager(); + _etchRegistry(admin); factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); } - function deployVaultFactory() public returns (TermMaxVaultFactoryV2 vaultFactory) { + function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { OrderManagerV2 orderManager = new OrderManagerV2(); IWhitelistManager whitelistManager = deployWhitelistManager(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); + _etchRegistry(admin); + vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); + } + + function deployVaultFactory(address admin, IWhitelistManager whitelistManager) + public + returns (TermMaxVaultFactoryV2 vaultFactory) + { + OrderManagerV2 orderManager = new OrderManagerV2(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); + _etchRegistry(admin); + vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); } function deployOracle(address admin, uint256 timeLock) public returns (OracleAggregatorV2 oracle) { @@ -425,26 +450,24 @@ library DeployUtils { router = TermMaxRouterV2(address(proxy)); } - function deployVault(VaultInitialParamsV2 memory initialParams) public returns (TermMaxVaultV2 vault) { - OrderManagerV2 orderManager = new OrderManagerV2(); - IWhitelistManager whitelistManager = deployWhitelistManager(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - TermMaxVaultFactoryV2 vaultFactory = - new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); - + function deployVault(address admin, VaultInitialParamsV2 memory initialParams) + public + returns (TermMaxVaultV2 vault) + { + TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin); + vm.startPrank(admin); vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + vm.stopPrank(); } - function deployVault(VaultInitialParamsV2 memory initialParams, IWhitelistManager whitelistManager) + function deployVault(address admin, VaultInitialParamsV2 memory initialParams, IWhitelistManager whitelistManager) public returns (TermMaxVaultV2 vault) { - OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - TermMaxVaultFactoryV2 vaultFactory = - new TermMaxVaultFactoryV2(address(implementation), address(whitelistManager)); - + TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin, whitelistManager); + vm.startPrank(admin); vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + vm.stopPrank(); } function deployAccessManager(address admin) internal returns (AccessManager accessManager) { From 174a3633a7ea1e3766e8dba41ef3a6eb02db6d1e Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 23:10:56 +0800 Subject: [PATCH 09/21] refactor: introduce Roles contract for centralized role management and update factories to utilize access manager roles --- contracts/v1/access/AccessManager.sol | 14 +------ contracts/v2/access/AccessManagerV2.sol | 6 --- contracts/v2/access/Roles.sol | 29 +++++++++++++++ contracts/v2/access/WithAccessManagerRole.sol | 21 +++++++++++ contracts/v2/factory/TermMax4626Factory.sol | 37 ++++++++++++------- contracts/v2/factory/TermMaxFactoryV2.sol | 19 ++++++---- .../v2/factory/TermMaxVaultFactoryV2.sol | 16 +++++--- contracts/v2/test/MockWhitelistManager.sol | 12 +++--- script/deploy/DeployBaseV2.s.sol | 6 ++- 9 files changed, 106 insertions(+), 54 deletions(-) create mode 100644 contracts/v2/access/Roles.sol create mode 100644 contracts/v2/access/WithAccessManagerRole.sol diff --git a/contracts/v1/access/AccessManager.sol b/contracts/v1/access/AccessManager.sol index 816e1305..df0b97d0 100644 --- a/contracts/v1/access/AccessManager.sol +++ b/contracts/v1/access/AccessManager.sol @@ -10,6 +10,7 @@ import {ITermMaxOrder} from "../ITermMaxOrder.sol"; import {IOracle} from "../oracle/IOracle.sol"; import {ITermMaxVault} from "../vault/ITermMaxVault.sol"; import {MarketConfig, FeeConfig, MarketInitialParams} from "../storage/TermMaxStorage.sol"; +import {Roles} from "../../v2/access/Roles.sol"; interface IOwnable { function transferOwnership(address newOwner) external; @@ -27,20 +28,9 @@ interface IPausable { * @title TermMax Access Manager * @author Term Structure Labs */ -contract AccessManager is AccessControlUpgradeable, UUPSUpgradeable { +contract AccessManager is AccessControlUpgradeable, UUPSUpgradeable, Roles { error CannotRevokeDefaultAdminRole(); - /// @notice Role to manage switch - bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); - /// @notice Role to manage configuration items - bytes32 public constant CONFIGURATOR_ROLE = keccak256("CONFIGURATOR_ROLE"); - /// @notice Role to manage vault - bytes32 public constant VAULT_ROLE = keccak256("VAULT_ROLE"); - /// @notice Role to manage oracle - bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); - /// @notice Role to manage market - bytes32 public constant MARKET_ROLE = keccak256("MARKET_ROLE"); - function initialize(address admin) public initializer { __UUPSUpgradeable_init(); __AccessControl_init(); diff --git a/contracts/v2/access/AccessManagerV2.sol b/contracts/v2/access/AccessManagerV2.sol index 94b3a242..10deccd4 100644 --- a/contracts/v2/access/AccessManagerV2.sol +++ b/contracts/v2/access/AccessManagerV2.sol @@ -16,12 +16,6 @@ import {VersionV2} from "../VersionV2.sol"; contract AccessManagerV2 is AccessManager, VersionV2 { error CannotRenounceRole(); - /// @notice Role to manage whitelist - bytes32 public constant WHITELIST_ROLE = keccak256("WHITELIST_ROLE"); - - /// @notice Role to upgrade contracts - bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); - function upgradeSubContract(UUPSUpgradeable proxy, address newImplementation, bytes memory data) external override diff --git a/contracts/v2/access/Roles.sol b/contracts/v2/access/Roles.sol new file mode 100644 index 00000000..ff2de333 --- /dev/null +++ b/contracts/v2/access/Roles.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @title Roles +/// @notice Defines role constants for access control in the TermMax protocol +abstract contract Roles { + /// @notice Role to manage switch + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + /// @notice Role to manage configuration items + bytes32 public constant CONFIGURATOR_ROLE = keccak256("CONFIGURATOR_ROLE"); + /// @notice Role to manage vault + bytes32 public constant VAULT_ROLE = keccak256("VAULT_ROLE"); + /// @notice Role to manage oracle + bytes32 public constant ORACLE_ROLE = keccak256("ORACLE_ROLE"); + /// @notice Role to manage market + bytes32 public constant MARKET_ROLE = keccak256("MARKET_ROLE"); + /// @notice Role to manage whitelist + bytes32 public constant WHITELIST_ROLE = keccak256("WHITELIST_ROLE"); + /// @notice Role to upgrade contracts + bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE"); + /// @notice Role to configure TermMax market factory + bytes32 public constant TERMMAX_MARKET_FACTORY_ROLE = keccak256("TERMMAX_MARKET_FACTORY_ROLE"); + /// @notice Role to configure TermMax 4626 pools + bytes32 public constant TERMMAX_4626_FACTORY_ROLE = keccak256("TERMMAX_4626_FACTORY_ROLE"); + /// @notice Role to deploy pools + bytes32 public constant POOL_DEPLOYER_ROLE = keccak256("POOL_DEPLOYER_ROLE"); + /// @notice Role to deploy vaults + bytes32 public constant VAULT_DEPLOYER_ROLE = keccak256("VAULT_DEPLOYER_ROLE"); +} diff --git a/contracts/v2/access/WithAccessManagerRole.sol b/contracts/v2/access/WithAccessManagerRole.sol new file mode 100644 index 00000000..55daadaf --- /dev/null +++ b/contracts/v2/access/WithAccessManagerRole.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; +import {Roles} from "./Roles.sol"; +/** + * @notice Reuse OpenZeppelin onlyRole while delegating role checks to AccessManager. + */ + +abstract contract WithAccessManagerRole is AccessControl, Roles { + address public immutable ACCESS_MANAGER; + + constructor(address accessManager) { + ACCESS_MANAGER = accessManager; + } + + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return IAccessControl(ACCESS_MANAGER).hasRole(role, account); + } +} diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index 7e2aeb15..5008c586 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -2,8 +2,6 @@ pragma solidity ^0.8.27; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; -import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {StakingBuffer} from "../tokens/StakingBuffer.sol"; import {StableERC4626For4626} from "../tokens/StableERC4626For4626.sol"; import {StableERC4626ForAave} from "../tokens/StableERC4626ForAave.sol"; @@ -12,10 +10,11 @@ import {StableERC4626ForCustomize} from "../tokens/StableERC4626ForCustomize.sol import {VariableERC4626ForAave} from "../tokens/VariableERC4626ForAave.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {FactoryErrorsV2} from "../errors/FactoryErrorsV2.sol"; +import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; -contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { +contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerRole { using Clones for address; bytes32 public constant STABLE_ERC4626_FOR_4626 = keccak256("StableERC4626For4626"); @@ -27,14 +26,17 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { mapping(bytes32 => address) internal implementations; constructor( - address owner, + address accessManager, address _stableERC4626For4626Implementation, address _stableERC4626ForAaveImplementation, address _stableERC4626ForVenusImplementation, address _variableERC4626ForAaveImplementation, address _stableERC4626ForCustomizeImplementation, address _whitelistManager - ) Ownable(owner) WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.POOL) { + ) + WithAccessManagerRole(accessManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.POOL) + { implementations[STABLE_ERC4626_FOR_4626] = _stableERC4626For4626Implementation; implementations[STABLE_ERC4626_FOR_AAVE] = _stableERC4626ForAaveImplementation; implementations[STABLE_ERC4626_FOR_VENUS] = _stableERC4626ForVenusImplementation; @@ -51,14 +53,17 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { } function _getRegistry() internal view override returns (address) { - return owner(); + return ACCESS_MANAGER; } function getImplementations(string memory key) external view returns (address) { return implementations[keccak256(abi.encodePacked(key))]; } - function setImplementation(string memory key, address implementation) external onlyOwner { + function setImplementation(string memory key, address implementation) + external + onlyRole(TERMMAX_4626_FACTORY_ROLE) + { implementations[keccak256(abi.encodePacked(key))] = implementation; emit FactoryEventsV2.ImplementationSet(key, implementation); } @@ -87,7 +92,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyOwner returns (StableERC4626For4626) { + ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626For4626) { StableERC4626For4626 instance = StableERC4626For4626(implementations[STABLE_ERC4626_FOR_4626].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -99,7 +104,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyOwner returns (StableERC4626ForVenus) { + ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForVenus) { StableERC4626ForVenus instance = StableERC4626ForVenus(implementations[STABLE_ERC4626_FOR_VENUS].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -112,7 +117,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address thirdPool, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyOwner returns (StableERC4626ForCustomize) { + ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForCustomize) { StableERC4626ForCustomize instance = StableERC4626ForCustomize(implementations[STABLE_ERC4626_FOR_CUSTOMIZE].clone()); instance.initialize(admin, thirdPool, underlying, bufferConfig); @@ -125,7 +130,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public onlyOwner returns (StableERC4626ForAave) { + ) public onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForAave) { StableERC4626ForAave instance = StableERC4626ForAave(implementations[STABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -137,7 +142,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public onlyOwner returns (VariableERC4626ForAave) { + ) public onlyRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave) { VariableERC4626ForAave instance = VariableERC4626ForAave(implementations[VARIABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -145,7 +150,11 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { return instance; } - function create(string memory key, bytes memory initialData) external onlyOwner returns (address) { + function create(string memory key, bytes memory initialData) + external + onlyRole(POOL_DEPLOYER_ROLE) + returns (address) + { address implementation = implementations[keccak256(abi.encodePacked(key))]; if (implementation == address(0)) revert FactoryErrorsV2.ImplementationNotFound(key); address instance = implementation.clone(); @@ -160,7 +169,7 @@ contract TermMax4626Factory is VersionV2, Ownable2Step, WithWhitelistCheck { address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyOwner returns (VariableERC4626ForAave, StableERC4626ForAave) { + ) external onlyRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave, StableERC4626ForAave) { VariableERC4626ForAave variableInstance = createVariableERC4626ForAave(admin, underlying, bufferConfig); StableERC4626ForAave stableInstance = createStableERC4626ForAave(admin, underlying, bufferConfig); return (variableInstance, stableInstance); diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index c7da8c39..f11d947c 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; import {GearingTokenWithERC20V2} from "../tokens/GearingTokenWithERC20V2.sol"; import {MarketInitialParams} from "../../v1/storage/TermMaxStorage.sol"; @@ -10,6 +9,7 @@ import {FactoryEvents} from "../../v1/events/FactoryEvents.sol"; import {ITermMaxMarket} from "../../v1/ITermMaxMarket.sol"; import {ITermMaxFactory} from "../../v1/factory/ITermMaxFactory.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; +import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; @@ -20,7 +20,7 @@ import {VersionV2} from "../VersionV2.sol"; * @dev Manages market deployment, gearing token implementations, and market configuration validation * Inherits from V1 factory interface while adding V2-specific features for improved market creation */ -contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, VersionV2, WithWhitelistCheck { +contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2, WithWhitelistCheck, WithAccessManagerRole { /// @notice Constant key for the default ERC20 gearing token implementation bytes32 constant GT_ERC20 = keccak256("GearingTokenWithERC20"); @@ -37,12 +37,12 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver /** * @notice Constructs the TermMax Factory V2 with initial configurations * @dev Sets up the factory with a market implementation and deploys the default ERC20 gearing token - * @param admin The address that will have administrative privileges over the factory + * @param accessManager The address of the access manager contract for role-based access control * @param TERMMAX_MARKET_IMPLEMENTATION_ The address of the TermMax market implementation contract * @custom:security Only the admin can create markets and manage gearing token implementations */ - constructor(address admin, address TERMMAX_MARKET_IMPLEMENTATION_, address _whitelistManager) - Ownable(admin) + constructor(address accessManager, address TERMMAX_MARKET_IMPLEMENTATION_, address _whitelistManager) + WithAccessManagerRole(accessManager) WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) { if (TERMMAX_MARKET_IMPLEMENTATION_ == address(0)) { @@ -62,7 +62,10 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver * @custom:access Only the factory owner can register new implementations * @custom:events Emits SetGtImplement event for tracking implementation changes */ - function setGtImplement(string memory gtImplementName, address gtImplement) external onlyOwner { + function setGtImplement(string memory gtImplementName, address gtImplement) + external + onlyRole(TERMMAX_4626_FACTORY_ROLE) + { bytes32 key = keccak256(abi.encodePacked(gtImplementName)); gtImplements[key] = gtImplement; emit FactoryEvents.SetGtImplement(key, gtImplement); @@ -92,7 +95,7 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver } function _getRegistry() internal view override returns (address) { - return owner(); + return ACCESS_MANAGER; } /** @@ -108,7 +111,7 @@ contract TermMaxFactoryV2 is Ownable2Step, ITermMaxFactory, FactoryEventsV2, Ver */ function createMarket(bytes32 gtKey, MarketInitialParams memory params, uint256 salt) external - onlyOwner + onlyRole(MARKET_ROLE) returns (address market) { // Retrieve the gearing token implementation for the requested key diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index 62caa293..f4d0e06b 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.27; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; -import {Ownable, Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {ITermMaxVaultV2} from "../vault/ITermMaxVaultV2.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {ITermMaxVaultFactoryV2} from "./ITermMaxVaultFactoryV2.sol"; import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol"; +import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; import {VersionV2} from "../VersionV2.sol"; @@ -14,14 +14,14 @@ import {VersionV2} from "../VersionV2.sol"; * @title The TermMax vault factory v2 * @author Term Structure Labs */ -contract TermMaxVaultFactoryV2 is Ownable2Step, ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck { +contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck, WithAccessManagerRole { /** * @notice The implementation of TermMax Vault contract v2 */ address public immutable TERMMAX_VAULT_IMPLEMENTATION; - constructor(address admin, address TERMMAX_VAULT_IMPLEMENTATION_, address _whitelistManager) - Ownable(admin) + constructor(address accessManager, address TERMMAX_VAULT_IMPLEMENTATION_, address _whitelistManager) + WithAccessManagerRole(accessManager) WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.ORDER_CALLBACK) { TERMMAX_VAULT_IMPLEMENTATION = TERMMAX_VAULT_IMPLEMENTATION_; @@ -43,13 +43,17 @@ contract TermMaxVaultFactoryV2 is Ownable2Step, ITermMaxVaultFactoryV2, VersionV } function _getRegistry() internal view override returns (address) { - return owner(); + return ACCESS_MANAGER; } /** * @inheritdoc ITermMaxVaultFactoryV2 */ - function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) public onlyOwner returns (address vault) { + function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) + public + onlyRole(VAULT_DEPLOYER_ROLE) + returns (address vault) + { vault = Clones.cloneDeterministic( TERMMAX_VAULT_IMPLEMENTATION, keccak256(abi.encode(msg.sender, initialParams.asset, initialParams.name, initialParams.symbol, salt)) diff --git a/contracts/v2/test/MockWhitelistManager.sol b/contracts/v2/test/MockWhitelistManager.sol index ec59c202..234d687b 100644 --- a/contracts/v2/test/MockWhitelistManager.sol +++ b/contracts/v2/test/MockWhitelistManager.sol @@ -11,22 +11,22 @@ contract MockWhitelistManager is IWhitelistManager, IWhitelistRegistry { whitelist[_user][_module] = _approved; } - function batchSetWhitelist(address[] memory _users, ContractModule _module, bool _approved) external { - for (uint256 i = 0; i < _users.length; i++) { - whitelist[_users[i]][_module] = _approved; + function batchSetWhitelist(address[] memory _addresses, ContractModule _module, bool _approved) external { + for (uint256 i = 0; i < _addresses.length; i++) { + whitelist[_addresses[i]][_module] = _approved; } - emit WhitelistUpdated(_users, _module, _approved); + emit WhitelistUpdated(_addresses, _module, _approved); } /// @dev IWhitelistRegistry implementation - forwards to the actual whitelist manager function batchSetWhitelist( IWhitelistManager _whitelistManager, - address[] calldata _users, + address[] calldata _addresses, ContractModule _module, bool _approved ) external override { - _whitelistManager.batchSetWhitelist(_users, _module, _approved); + _whitelistManager.batchSetWhitelist(_addresses, _module, _approved); } function isWhitelisted(address _user, ContractModule _module) external view returns (bool) { diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index e781a6c2..14bf8951 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -387,10 +387,12 @@ contract DeployBaseV2 is Script { // deploy factory contracts.factory = deployFactory(address(contracts.accessManager), address(contracts.whitelistManager)); - contracts.vaultFactory = deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); + contracts.vaultFactory = + deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy vault factory - contracts.vaultFactory = deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); + contracts.vaultFactory = + deployVaultFactory(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy 4626 factory { From b7b00100e75e3686e4ddb8f0f3e74b4d6d8a8f2d Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 23:26:30 +0800 Subject: [PATCH 10/21] clean check logic --- contracts/v2/access/WithAccessManagerRole.sol | 11 +++++++---- contracts/v2/factory/TermMax4626Factory.sol | 19 ++++++++----------- contracts/v2/factory/TermMaxFactoryV2.sol | 4 ++-- .../v2/factory/TermMaxVaultFactoryV2.sol | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/contracts/v2/access/WithAccessManagerRole.sol b/contracts/v2/access/WithAccessManagerRole.sol index 55daadaf..ce8c07cb 100644 --- a/contracts/v2/access/WithAccessManagerRole.sol +++ b/contracts/v2/access/WithAccessManagerRole.sol @@ -1,21 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol"; import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {Roles} from "./Roles.sol"; /** * @notice Reuse OpenZeppelin onlyRole while delegating role checks to AccessManager. */ -abstract contract WithAccessManagerRole is AccessControl, Roles { +abstract contract WithAccessManagerRole is Roles { address public immutable ACCESS_MANAGER; constructor(address accessManager) { ACCESS_MANAGER = accessManager; } - function hasRole(bytes32 role, address account) public view virtual override returns (bool) { - return IAccessControl(ACCESS_MANAGER).hasRole(role, account); + modifier hasRole(bytes32 role) { + require( + IAccessControl(ACCESS_MANAGER).hasRole(role, msg.sender), + IAccessControl.AccessControlUnauthorizedAccount(msg.sender, role) + ); + _; } } diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index 5008c586..640585b2 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -60,10 +60,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR return implementations[keccak256(abi.encodePacked(key))]; } - function setImplementation(string memory key, address implementation) - external - onlyRole(TERMMAX_4626_FACTORY_ROLE) - { + function setImplementation(string memory key, address implementation) external hasRole(TERMMAX_4626_FACTORY_ROLE) { implementations[keccak256(abi.encodePacked(key))] = implementation; emit FactoryEventsV2.ImplementationSet(key, implementation); } @@ -92,7 +89,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626For4626) { + ) external hasRole(POOL_DEPLOYER_ROLE) returns (StableERC4626For4626) { StableERC4626For4626 instance = StableERC4626For4626(implementations[STABLE_ERC4626_FOR_4626].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -104,7 +101,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address admin, address thirdPool, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForVenus) { + ) external hasRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForVenus) { StableERC4626ForVenus instance = StableERC4626ForVenus(implementations[STABLE_ERC4626_FOR_VENUS].clone()); instance.initialize(admin, thirdPool, bufferConfig); _registerAddress(address(instance)); @@ -117,7 +114,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address thirdPool, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForCustomize) { + ) external hasRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForCustomize) { StableERC4626ForCustomize instance = StableERC4626ForCustomize(implementations[STABLE_ERC4626_FOR_CUSTOMIZE].clone()); instance.initialize(admin, thirdPool, underlying, bufferConfig); @@ -130,7 +127,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public onlyRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForAave) { + ) public hasRole(POOL_DEPLOYER_ROLE) returns (StableERC4626ForAave) { StableERC4626ForAave instance = StableERC4626ForAave(implementations[STABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -142,7 +139,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) public onlyRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave) { + ) public hasRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave) { VariableERC4626ForAave instance = VariableERC4626ForAave(implementations[VARIABLE_ERC4626_FOR_AAVE].clone()); instance.initialize(admin, underlying, bufferConfig); _registerAddress(address(instance)); @@ -152,7 +149,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR function create(string memory key, bytes memory initialData) external - onlyRole(POOL_DEPLOYER_ROLE) + hasRole(POOL_DEPLOYER_ROLE) returns (address) { address implementation = implementations[keccak256(abi.encodePacked(key))]; @@ -169,7 +166,7 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR address admin, address underlying, StakingBuffer.BufferConfig memory bufferConfig - ) external onlyRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave, StableERC4626ForAave) { + ) external hasRole(POOL_DEPLOYER_ROLE) returns (VariableERC4626ForAave, StableERC4626ForAave) { VariableERC4626ForAave variableInstance = createVariableERC4626ForAave(admin, underlying, bufferConfig); StableERC4626ForAave stableInstance = createStableERC4626ForAave(admin, underlying, bufferConfig); return (variableInstance, stableInstance); diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index f11d947c..9a550b6f 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -64,7 +64,7 @@ contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2, WithWh */ function setGtImplement(string memory gtImplementName, address gtImplement) external - onlyRole(TERMMAX_4626_FACTORY_ROLE) + hasRole(TERMMAX_MARKET_FACTORY_ROLE) { bytes32 key = keccak256(abi.encodePacked(gtImplementName)); gtImplements[key] = gtImplement; @@ -111,7 +111,7 @@ contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2, WithWh */ function createMarket(bytes32 gtKey, MarketInitialParams memory params, uint256 salt) external - onlyRole(MARKET_ROLE) + hasRole(MARKET_ROLE) returns (address market) { // Retrieve the gearing token implementation for the requested key diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index f4d0e06b..cc34ffec 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -51,7 +51,7 @@ contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhiteli */ function createVault(VaultInitialParamsV2 memory initialParams, uint256 salt) public - onlyRole(VAULT_DEPLOYER_ROLE) + hasRole(VAULT_DEPLOYER_ROLE) returns (address vault) { vault = Clones.cloneDeterministic( From d82a68ae20e9ede0c998d940c7c376461312e28f Mon Sep 17 00:00:00 2001 From: Evan Date: Mon, 6 Apr 2026 23:50:28 +0800 Subject: [PATCH 11/21] fix tests --- contracts/v2/access/WithAccessManagerRole.sol | 10 +- test/v2/AccessManagerV2.t.sol | 21 +- test/v2/FactoryV2.t.sol | 7 +- test/v2/TermMax4626Factory.t.sol | 18 +- test/v2/utils/DeployUtils.sol | 196 +++++++++++++++--- 5 files changed, 209 insertions(+), 43 deletions(-) diff --git a/contracts/v2/access/WithAccessManagerRole.sol b/contracts/v2/access/WithAccessManagerRole.sol index ce8c07cb..6735532d 100644 --- a/contracts/v2/access/WithAccessManagerRole.sol +++ b/contracts/v2/access/WithAccessManagerRole.sol @@ -15,10 +15,12 @@ abstract contract WithAccessManagerRole is Roles { } modifier hasRole(bytes32 role) { - require( - IAccessControl(ACCESS_MANAGER).hasRole(role, msg.sender), - IAccessControl.AccessControlUnauthorizedAccount(msg.sender, role) - ); + if (msg.sender != ACCESS_MANAGER) { + require( + IAccessControl(ACCESS_MANAGER).hasRole(role, msg.sender), + IAccessControl.AccessControlUnauthorizedAccount(msg.sender, role) + ); + } _; } } diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index 65e32ad7..f8fa087e 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -50,6 +50,7 @@ contract AccessManagerTestV2 is Test { AccessManagerV2 manager; address curator = vm.randomAddress(); TermMaxOrderV2 vaultOrder; + MockWhitelistManager whitelistManager; function setUp() public { vm.startPrank(deployer); @@ -61,7 +62,15 @@ contract AccessManagerTestV2 is Test { marketConfig = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); orderConfig = JSONLoader.getOrderConfigFromJson(testdata, ".orderConfig"); - res = DeployUtils.deployMarket(deployer, marketConfig, maxLtv, liquidationLtv); + whitelistManager = new MockWhitelistManager(); + + AccessManagerV2 implementation = new AccessManagerV2(); + bytes memory data = abi.encodeCall(AccessManager.initialize, deployer); + address proxy = address(new ERC1967Proxy(address(implementation), data)); + + manager = AccessManagerV2(proxy); + + res = DeployUtils.deployMarket(deployer, manager, marketConfig, maxLtv, liquidationLtv, whitelistManager); res.order = TermMaxOrderV2( address( @@ -86,12 +95,6 @@ contract AccessManagerTestV2 is Test { res.router = DeployUtils.deployRouter(deployer, res.whitelistManager); - AccessManagerV2 implementation = new AccessManagerV2(); - bytes memory data = abi.encodeCall(AccessManager.initialize, deployer); - address proxy = address(new ERC1967Proxy(address(implementation), data)); - - manager = AccessManagerV2(proxy); - IOwnable(address(res.factory)).transferOwnership(address(manager)); IOwnable(address(res.market)).transferOwnership(address(manager)); IOwnable(address(res.router)).transferOwnership(address(manager)); @@ -126,7 +129,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - res.vault = DeployUtils.deployVault(address(manager), params, res.whitelistManager); + res.vault = DeployUtils.deployVault(deployer, manager, params, res.whitelistManager); vm.stopPrank(); vm.startPrank(curator); @@ -728,7 +731,7 @@ contract AccessManagerTestV2 is Test { minApy: 0 }); - TermMaxVaultV2 poolVault = DeployUtils.deployVault(address(manager), poolParams, res.whitelistManager); + TermMaxVaultV2 poolVault = DeployUtils.deployVault(deployer, manager, poolParams, res.whitelistManager); ITermMaxVaultV2 poolVaultV2 = ITermMaxVaultV2(address(poolVault)); address vaultManager = vm.randomAddress(); diff --git a/test/v2/FactoryV2.t.sol b/test/v2/FactoryV2.t.sol index f90b599d..0f13566d 100644 --- a/test/v2/FactoryV2.t.sol +++ b/test/v2/FactoryV2.t.sol @@ -5,6 +5,7 @@ import "forge-std/Test.sol"; import {console} from "forge-std/console.sol"; import {DeployUtils} from "./utils/DeployUtils.sol"; import {JSONLoader} from "./utils/JSONLoader.sol"; +import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; import {ITermMaxMarketV2, TermMaxMarketV2, Constants, MarketErrors} from "contracts/v2/TermMaxMarketV2.sol"; import {MockERC20, ERC20} from "contracts/v1/test/MockERC20.sol"; @@ -269,7 +270,11 @@ contract FactoryTestV2 is Test { GearingTokenWithERC20V2 gt = new GearingTokenWithERC20V2(); string memory key = "gt-test"; - vm.expectRevert(abi.encodePacked(bytes4(keccak256("OwnableUnauthorizedAccount(address)")), abi.encode(sender))); + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, sender, factory.TERMMAX_MARKET_FACTORY_ROLE() + ) + ); factory.setGtImplement(key, address(gt)); vm.stopPrank(); diff --git a/test/v2/TermMax4626Factory.t.sol b/test/v2/TermMax4626Factory.t.sol index 1958a0ae..03a8a073 100644 --- a/test/v2/TermMax4626Factory.t.sol +++ b/test/v2/TermMax4626Factory.t.sol @@ -18,6 +18,8 @@ import {ERC4626TokenEvents} from "contracts/v2/events/ERC4626TokenEvents.sol"; import {FactoryEventsV2} from "contracts/v2/events/FactoryEventsV2.sol"; import {MockWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {AccessManagerV2, AccessManager} from "contracts/v2/access/AccessManagerV2.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; contract TermMax4626FactoryTest is Test { TermMax4626Factory public factory; @@ -40,6 +42,7 @@ contract TermMax4626FactoryTest is Test { VariableERC4626ForAave public implVariableAave; StableERC4626ForCustomize public implCustomize; MockWhitelistManager public whitelistManager; + AccessManagerV2 public accessManager; StakingBuffer.BufferConfig public defaultBufferConfig; @@ -67,13 +70,13 @@ contract TermMax4626FactoryTest is Test { implCustomize = new StableERC4626ForCustomize(); whitelistManager = new MockWhitelistManager(); - // Give admin the MockWhitelistManager code so factory._getRegistry() (which returns owner() == admin) - // can satisfy IWhitelistRegistry calls - vm.etch(admin, address(whitelistManager).code); + AccessManagerV2 implementation = new AccessManagerV2(); + bytes memory data = abi.encodeCall(AccessManager.initialize, admin); + accessManager = AccessManagerV2(address(new ERC1967Proxy(address(implementation), data))); // Deploy factory factory = new TermMax4626Factory( - admin, + address(accessManager), address(impl4626), address(implStableAave), address(implVenus), @@ -86,8 +89,15 @@ contract TermMax4626FactoryTest is Test { defaultBufferConfig = StakingBuffer.BufferConfig({minimumBuffer: 1000e18, maximumBuffer: 10000e18, buffer: 5000e18}); + vm.startPrank(admin); + accessManager.grantRole(accessManager.POOL_DEPLOYER_ROLE(), admin); + accessManager.grantRole(accessManager.TERMMAX_4626_FACTORY_ROLE(), admin); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(factory)); + vm.stopPrank(); + // Labels for better test output vm.label(address(factory), "TermMax4626Factory"); + vm.label(address(accessManager), "AccessManagerV2"); vm.label(address(underlying), "USDC"); vm.label(address(thirdPool), "ThirdPool"); vm.label(address(aavePool), "AavePool"); diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index b6157c44..97fabe4f 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import {console} from "forge-std/Script.sol"; -import {Vm} from "forge-std/Vm.sol"; +import {Vm, VmSafe} from "forge-std/Vm.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; @@ -36,6 +36,7 @@ import {TermMaxVaultFactoryV2} from "contracts/v2/factory/TermMaxVaultFactoryV2. import {MockAave} from "contracts/v2/test/MockAave.sol"; import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; import {OnlyDeliveryGearingToken} from "contracts/v2/tokens/OnlyDeliveryGearingToken.sol"; +import {AccessManagerV2} from "contracts/v2/access/AccessManagerV2.sol"; library DeployUtils { Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); @@ -75,14 +76,6 @@ library DeployUtils { IWhitelistManager whitelistManager; } - /// @dev Etch MockWhitelistManager code onto an EOA address so it can serve as IWhitelistRegistry - function _etchRegistry(address target) internal { - if (target.code.length == 0) { - MockWhitelistManager mock = new MockWhitelistManager(); - vm.etch(target, address(mock).code); - } - } - function deployMarket(address admin, MarketConfig memory marketConfig, uint32 maxLtv, uint32 liquidationLtv) internal returns (Res memory res) @@ -139,6 +132,66 @@ library DeployUtils { (res.ft, res.xt, res.gt,,) = res.market.tokens(); } + function deployMarket( + address admin, + AccessManagerV2 accessManager, + MarketConfig memory marketConfig, + uint32 maxLtv, + uint32 liquidationLtv, + IWhitelistManager whitelistManager + ) internal returns (Res memory res) { + res.factory = deployFactory(admin, accessManager, whitelistManager); + res.whitelistManager = whitelistManager; + + res.collateral = new MockERC20("ETH", "ETH", 18); + res.debt = new MockERC20("DAI", "DAI", 8); + + res.debtOracle = new MockPriceFeed(admin); + res.collateralOracle = new MockPriceFeed(admin); + res.oracle = deployOracle(admin, 0); + + res.oracle.submitPendingOracle( + address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) + ); + res.oracle.submitPendingOracle( + address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) + ); + + res.oracle.acceptPendingOracle(address(res.debt)); + res.oracle.acceptPendingOracle(address(res.collateral)); + + MockPriceFeed.RoundData memory roundData = MockPriceFeed.RoundData({ + roundId: 1, + answer: int256(1e1 ** res.collateralOracle.decimals()), + startedAt: 0, + updatedAt: 0, + answeredInRound: 0 + }); + res.collateralOracle.updateRoundData(roundData); + + MarketInitialParams memory initialParams = MarketInitialParams({ + collateral: address(res.collateral), + debtToken: res.debt, + admin: admin, + gtImplementation: address(0), + marketConfig: marketConfig, + loanConfig: LoanConfig({ + oracle: IOracle(address(res.oracle)), + liquidationLtv: liquidationLtv, + maxLtv: maxLtv, + liquidatable: true + }), + gtInitalParams: abi.encode(type(uint256).max), + tokenName: "DAI-ETH", + tokenSymbol: "DAI-ETH" + }); + + res.marketConfig = marketConfig; + res.market = TermMaxMarketV2(res.factory.createMarket(GT_ERC20, initialParams, 0)); + + (res.ft, res.xt, res.gt,,) = res.market.tokens(); + } + function deployMarket( address admin, MarketConfig memory marketConfig, @@ -382,53 +435,82 @@ library DeployUtils { } function deployFactory(address admin) public returns (TermMaxFactoryV2 factory) { + AccessManagerV2 accessManager = deployAccessManagerV2(admin); address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); IWhitelistManager whitelistManager = deployWhitelistManager(); - _etchRegistry(admin); - factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); + factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); + _grantFactoryRoles(accessManager, admin, factory); } function deployFactory(address admin, IWhitelistManager whitelistManager) public returns (TermMaxFactoryV2 factory) { + AccessManagerV2 accessManager = deployAccessManagerV2(admin); address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new TermMaxOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - _etchRegistry(admin); - factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); + factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); + _grantFactoryRoles(accessManager, admin, factory); + } + + function deployFactory(address admin, AccessManagerV2 accessManager, IWhitelistManager whitelistManager) + public + returns (TermMaxFactoryV2 factory) + { + address tokenImplementation = address(new MintableERC20V2()); + address orderImplementation = address(new TermMaxOrderV2()); + TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); + factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); + _grantFactoryRoles(accessManager, admin, factory); } function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory, IWhitelistManager whitelistManager) { + AccessManagerV2 accessManager = deployAccessManagerV2(admin); address tokenImplementation = address(new MintableERC20V2()); address orderImplementation = address(new MockOrderV2()); TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); whitelistManager = deployWhitelistManager(); - _etchRegistry(admin); - factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); + factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); + _grantFactoryRoles(accessManager, admin, factory); } function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { + AccessManagerV2 accessManager = deployAccessManagerV2(admin); OrderManagerV2 orderManager = new OrderManagerV2(); IWhitelistManager whitelistManager = deployWhitelistManager(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - _etchRegistry(admin); - vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); + vaultFactory = + new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); + _grantVaultFactoryRoles(accessManager, admin, vaultFactory); } function deployVaultFactory(address admin, IWhitelistManager whitelistManager) public returns (TermMaxVaultFactoryV2 vaultFactory) { + AccessManagerV2 accessManager = deployAccessManagerV2(admin); OrderManagerV2 orderManager = new OrderManagerV2(); TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - _etchRegistry(admin); - vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); + vaultFactory = + new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); + _grantVaultFactoryRoles(accessManager, admin, vaultFactory); + } + + function deployVaultFactory(address admin, AccessManagerV2 accessManager, IWhitelistManager whitelistManager) + public + returns (TermMaxVaultFactoryV2 vaultFactory) + { + OrderManagerV2 orderManager = new OrderManagerV2(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); + vaultFactory = + new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); + _grantVaultFactoryRoles(accessManager, admin, vaultFactory); } function deployOracle(address admin, uint256 timeLock) public returns (OracleAggregatorV2 oracle) { @@ -455,9 +537,14 @@ library DeployUtils { returns (TermMaxVaultV2 vault) { TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin); - vm.startPrank(admin); - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - vm.stopPrank(); + (VmSafe.CallerMode callerMode,,) = vm.readCallers(); + if (callerMode == VmSafe.CallerMode.None) { + vm.startPrank(admin); + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + vm.stopPrank(); + } else { + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + } } function deployVault(address admin, VaultInitialParamsV2 memory initialParams, IWhitelistManager whitelistManager) @@ -465,9 +552,31 @@ library DeployUtils { returns (TermMaxVaultV2 vault) { TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin, whitelistManager); - vm.startPrank(admin); - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - vm.stopPrank(); + (VmSafe.CallerMode callerMode,,) = vm.readCallers(); + if (callerMode == VmSafe.CallerMode.None) { + vm.startPrank(admin); + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + vm.stopPrank(); + } else { + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + } + } + + function deployVault( + address admin, + AccessManagerV2 accessManager, + VaultInitialParamsV2 memory initialParams, + IWhitelistManager whitelistManager + ) public returns (TermMaxVaultV2 vault) { + TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin, accessManager, whitelistManager); + (VmSafe.CallerMode callerMode,,) = vm.readCallers(); + if (callerMode == VmSafe.CallerMode.None) { + vm.startPrank(admin); + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + vm.stopPrank(); + } else { + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); + } } function deployAccessManager(address admin) internal returns (AccessManager accessManager) { @@ -477,6 +586,43 @@ library DeployUtils { accessManager = AccessManager(address(proxy)); } + function deployAccessManagerV2(address admin) internal returns (AccessManagerV2 accessManager) { + AccessManagerV2 implementation = new AccessManagerV2(); + bytes memory data = abi.encodeCall(AccessManager.initialize, admin); + ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); + accessManager = AccessManagerV2(address(proxy)); + } + + function _grantFactoryRoles(AccessManagerV2 accessManager, address admin, TermMaxFactoryV2 factory) private { + (VmSafe.CallerMode callerMode,,) = vm.readCallers(); + if (callerMode == VmSafe.CallerMode.None) { + vm.startPrank(admin); + accessManager.grantRole(accessManager.MARKET_ROLE(), admin); + accessManager.grantRole(accessManager.TERMMAX_MARKET_FACTORY_ROLE(), admin); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(factory)); + vm.stopPrank(); + } else { + accessManager.grantRole(accessManager.MARKET_ROLE(), admin); + accessManager.grantRole(accessManager.TERMMAX_MARKET_FACTORY_ROLE(), admin); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(factory)); + } + } + + function _grantVaultFactoryRoles(AccessManagerV2 accessManager, address admin, TermMaxVaultFactoryV2 vaultFactory) + private + { + (VmSafe.CallerMode callerMode,,) = vm.readCallers(); + if (callerMode == VmSafe.CallerMode.None) { + vm.startPrank(admin); + accessManager.grantRole(accessManager.VAULT_DEPLOYER_ROLE(), admin); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(vaultFactory)); + vm.stopPrank(); + } else { + accessManager.grantRole(accessManager.VAULT_DEPLOYER_ROLE(), admin); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(vaultFactory)); + } + } + function deployWhitelistManager() internal returns (IWhitelistManager whitelistManager) { whitelistManager = new MockWhitelistManager(); } From b33238c51570fa9dad2c4ef364f03af210fef473 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 09:36:08 +0800 Subject: [PATCH 12/21] fix the order issue that attacker may front-run delegate and deploy different orders --- contracts/v2/TermMaxMarketV2.sol | 8 ++------ test/v2/MakerHelper.t.sol | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/v2/TermMaxMarketV2.sol b/contracts/v2/TermMaxMarketV2.sol index 70effa5f..1442ad65 100644 --- a/contracts/v2/TermMaxMarketV2.sol +++ b/contracts/v2/TermMaxMarketV2.sol @@ -467,10 +467,7 @@ contract TermMaxMarketV2 is returns (ITermMaxOrder order) { order = ITermMaxOrder( - Clones.cloneDeterministic( - TERMMAX_ORDER_IMPLEMENT, - keccak256(abi.encode(params.maker, params.pool, params.orderConfig.swapTrigger, address(this), salt)) - ) + Clones.cloneDeterministic(TERMMAX_ORDER_IMPLEMENT, keccak256(abi.encode(params, address(this), salt))) ); _initalizeOrder(params, address(order)); } @@ -484,8 +481,7 @@ contract TermMaxMarketV2 is returns (address orderAddress) { return Clones.predictDeterministicAddress( - TERMMAX_ORDER_IMPLEMENT, - keccak256(abi.encode(params.maker, params.pool, params.orderConfig.swapTrigger, address(this), salt)) + TERMMAX_ORDER_IMPLEMENT, keccak256(abi.encode(params, address(this), salt)) ); } diff --git a/test/v2/MakerHelper.t.sol b/test/v2/MakerHelper.t.sol index fb46b7bd..27134506 100644 --- a/test/v2/MakerHelper.t.sol +++ b/test/v2/MakerHelper.t.sol @@ -228,6 +228,7 @@ contract MakerHelperTest is Test { initialParams.maker = delegator; initialParams.orderConfig = orderConfig; initialParams.virtualXtReserve = 1e8; + initialParams.orderConfig.gtId = res.gt.totalSupply() + 1; // Set gtId to be the next minted GT ID // Set up proper delegation parameters uint256 nonce = DelegateAble(address(res.gt)).nonces(delegator); From 44b955c6ef1ddc31df890789c3ab6468fa8e44c1 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 09:57:37 +0800 Subject: [PATCH 13/21] implement order expiry timestamp management and related error handling --- contracts/v2/TermMaxMarketV2.sol | 5 +- contracts/v2/TermMaxOrderV2.sol | 85 ++++++++++++-- contracts/v2/errors/OrderErrorsV2.sol | 3 + contracts/v2/events/OrderEventsV2.sol | 4 + test/v2/OrderV2.t.sol | 153 ++++++++++++++++++++++++++ 5 files changed, 241 insertions(+), 9 deletions(-) diff --git a/contracts/v2/TermMaxMarketV2.sol b/contracts/v2/TermMaxMarketV2.sol index 1442ad65..f18a87c8 100644 --- a/contracts/v2/TermMaxMarketV2.sol +++ b/contracts/v2/TermMaxMarketV2.sol @@ -486,7 +486,10 @@ contract TermMaxMarketV2 is } function _initalizeOrder(OrderInitialParams memory params, address order) internal { - params.maturity = _config.maturity; + if (params.maturity == 0) { + params.maturity = _config.maturity; + } + params.ft = ft; params.xt = xt; params.gt = gt; diff --git a/contracts/v2/TermMaxOrderV2.sol b/contracts/v2/TermMaxOrderV2.sol index 864b0ed0..b301dcdf 100644 --- a/contracts/v2/TermMaxOrderV2.sol +++ b/contracts/v2/TermMaxOrderV2.sol @@ -58,12 +58,25 @@ contract TermMaxOrderV2 is OrderConfig private _orderConfig; - uint64 private maturity; + /// @notice The timestamp when the order expires + uint64 public orderExpiryTimestamp; /// @notice The virtual xt reserve can present current price, which only changed when swap happens uint256 public virtualXtReserve; IERC4626 public pool; + // ============================================================================= + // TRANSIENT STORAGE + // ============================================================================= + + /// @notice Transient storage slot for caching treasurer address during swap + /// @dev Using EIP-1153 transient storage to save gas on repeated market.config().treasurer calls + bytes32 private constant TREASURER_CACHE_SLOT = keccak256("termmax.order.v2.treasurer_cache"); + + /// @notice Transient storage slot for caching maturity during swap + /// @dev Using EIP-1153 transient storage to save gas on repeated market.config().maturity calls + bytes32 private constant MATURITY_CACHE_SLOT = keccak256("termmax.order.v2.maturity_cache"); + // ============================================================================= // MODIFIERS // ============================================================================= @@ -87,7 +100,7 @@ contract TermMaxOrderV2 is /// @notice Check if the order is tradable modifier onlyOpen() { _requireNotPaused(); - if (block.timestamp >= maturity) { + if (block.timestamp >= orderExpiryTimestamp) { revert TermIsNotOpen(); } _; @@ -132,7 +145,6 @@ contract TermMaxOrderV2 is __Pausable_init_unchained(); address _market = _msgSender(); market = ITermMaxMarket(_market); - maturity = params.maturity; ft = params.ft; xt = params.xt; debtToken = params.debtToken; @@ -140,6 +152,7 @@ contract TermMaxOrderV2 is _setPool(params.pool); _setCurveAndPrice(params.virtualXtReserve, params.orderConfig.maxXtReserve, params.orderConfig.curveCuts); _updateGeneralConfig(params.orderConfig.gtId, params.orderConfig.swapTrigger); + _setExpiryTimestamp(params.maturity); emit OrderEventsV2.OrderInitialized(params.maker, _market); } @@ -162,7 +175,7 @@ contract TermMaxOrderV2 is */ function orderConfig() external view virtual returns (OrderConfig memory orderConfig_) { orderConfig_ = _orderConfig; - orderConfig_.feeConfig = market.config().feeConfig; + orderConfig_.feeConfig = _getMarketConfig().feeConfig; } /** @@ -241,7 +254,53 @@ contract TermMaxOrderV2 is * @return daysToMaturity Number of days to maturity */ function _daysToMaturity() internal view returns (uint256 daysToMaturity) { - daysToMaturity = (maturity - block.timestamp + Constants.SECONDS_IN_DAY - 1) / Constants.SECONDS_IN_DAY; + uint256 maturity_ = _getMaturityCached(); + if (maturity_ == 0) { + maturity_ = _getMarketConfig().maturity; + } + daysToMaturity = (maturity_ - block.timestamp + Constants.SECONDS_IN_DAY - 1) / Constants.SECONDS_IN_DAY; + } + + // ============================================================================= + // TRANSIENT STORAGE HELPERS + // ============================================================================= + + function _getTreasurerCached() internal view returns (address treasurer) { + bytes32 slot = TREASURER_CACHE_SLOT; + assembly { + treasurer := tload(slot) + } + } + + function _cacheTreasurer(address treasurer) internal { + bytes32 slot = TREASURER_CACHE_SLOT; + assembly { + tstore(slot, treasurer) + } + } + + function _cacheMaturity(uint256 maturity_) internal { + bytes32 slot = MATURITY_CACHE_SLOT; + assembly { + tstore(slot, maturity_) + } + } + + function _getMaturityCached() internal view returns (uint256 maturity_) { + bytes32 slot = MATURITY_CACHE_SLOT; + assembly { + maturity_ := tload(slot) + } + } + + function _getMarketConfig() internal view returns (MarketConfig memory config) { + config = market.config(); + } + + function _getMarketConfigAndCache() internal returns (MarketConfig memory config) { + config = _getMarketConfig(); + _cacheTreasurer(config.treasurer); + _cacheMaturity(config.maturity); } // ============================================================================= @@ -342,6 +401,16 @@ contract TermMaxOrderV2 is _updateGeneralConfig(gtId, swapTrigger); } + function setExpiryTimestamp(uint64 newExpiryTimestamp) external virtual onlyOwner { + _setExpiryTimestamp(newExpiryTimestamp); + } + + function _setExpiryTimestamp(uint64 newExpiryTimestamp) internal { + require(newExpiryTimestamp <= _getMarketConfig().maturity, OrderErrorsV2.InvalidExpiryTimestamp()); + orderExpiryTimestamp = newExpiryTimestamp; + emit OrderEventsV2.ExpiryTimestampUpdated(newExpiryTimestamp); + } + function setPool(IERC4626 newPool) external virtual onlyOwner { _setPool(newPool); } @@ -610,7 +679,7 @@ contract TermMaxOrderV2 is IERC20 _ft = ft; IERC20 _xt = xt; OrderConfig memory orderConfig_ = _orderConfig; - orderConfig_.feeConfig = market.config().feeConfig; + orderConfig_.feeConfig = _getMarketConfigAndCache().feeConfig; int256 deltaFt; int256 deltaXt; if (tokenIn == _ft && tokenOut == _debtToken) { @@ -680,7 +749,7 @@ contract TermMaxOrderV2 is int256 deltaFt; int256 deltaXt; OrderConfig memory orderConfig_ = _orderConfig; - orderConfig_.feeConfig = market.config().feeConfig; + orderConfig_.feeConfig = _getMarketConfigAndCache().feeConfig; if (tokenIn == _debtToken && tokenOut == _ft) { (netTokenIn, feeAmt, deltaFt, deltaXt) = _swapAndUpdateReserves(tokenAmtOut, maxTokenIn, orderConfig_, _buyExactFt); @@ -770,7 +839,7 @@ contract TermMaxOrderV2 is } // Pay fee - _ft.safeTransfer(_market.config().treasurer, feeAmt); + _ft.safeTransfer(_getTreasurerCached(), feeAmt); } // ============================================================================= diff --git a/contracts/v2/errors/OrderErrorsV2.sol b/contracts/v2/errors/OrderErrorsV2.sol index d3097a69..99555352 100644 --- a/contracts/v2/errors/OrderErrorsV2.sol +++ b/contracts/v2/errors/OrderErrorsV2.sol @@ -19,4 +19,7 @@ interface OrderErrorsV2 { /// @notice Error thrown when attempting to call updateOrder function on a v2 order /// The v2 orders do not support the updateOrder function error UpdateOrderFunctionDisabled(); + + /// @notice Error thrown when setting an expiry timestamp that is after the market maturity + error InvalidExpiryTimestamp(); } diff --git a/contracts/v2/events/OrderEventsV2.sol b/contracts/v2/events/OrderEventsV2.sol index 13cec8a7..ea3e45bd 100644 --- a/contracts/v2/events/OrderEventsV2.sol +++ b/contracts/v2/events/OrderEventsV2.sol @@ -14,6 +14,10 @@ interface OrderEventsV2 { /// @param market The address of the market associated with the order event OrderInitialized(address indexed maker, address indexed market); + /// @notice Emitted when the expiry timestamp of the order is updated + /// @param newExpiryTimestamp The new expiry timestamp set for the order + event ExpiryTimestampUpdated(uint64 newExpiryTimestamp); + /// @notice Emitted when the staking or reward pool associated with the order is changed /// @param pool The address of the new staking/reward pool contract event PoolUpdated(address indexed pool); diff --git a/test/v2/OrderV2.t.sol b/test/v2/OrderV2.t.sol index 9538a233..0528075d 100644 --- a/test/v2/OrderV2.t.sol +++ b/test/v2/OrderV2.t.sol @@ -1249,6 +1249,159 @@ contract OrderTestV2 is Test { vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", sender)); res.order.borrowToken(recipient, 1e8); } + + // ============================================================================= + // ORDER EXPIRY TIMESTAMP TESTS + // ============================================================================= + + function testOrderExpiryTimestamp_InitializedWithMaturity() public { + // The order should be initialized with maturity as the expiry timestamp + uint64 maturity = res.market.config().maturity; + assertEq(res.order.orderExpiryTimestamp(), maturity, "Order expiry timestamp should equal maturity"); + } + + function testOrderExpiryTimestamp_SetExpiryTimestamp() public { + vm.startPrank(maker); + + uint64 maturity = res.market.config().maturity; + uint64 newExpiryTimestamp = maturity - 1 days; + + vm.expectEmit(); + emit OrderEventsV2.ExpiryTimestampUpdated(newExpiryTimestamp); + res.order.setExpiryTimestamp(newExpiryTimestamp); + + assertEq(res.order.orderExpiryTimestamp(), newExpiryTimestamp, "Order expiry timestamp not updated"); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_SetExpiryTimestampToMaturity() public { + vm.startPrank(maker); + + // First set it to a lower value + uint64 maturity = res.market.config().maturity; + uint64 lowerTimestamp = maturity - 1 days; + res.order.setExpiryTimestamp(lowerTimestamp); + + // Then set it back to maturity (boundary condition) + vm.expectEmit(); + emit OrderEventsV2.ExpiryTimestampUpdated(maturity); + res.order.setExpiryTimestamp(maturity); + + assertEq(res.order.orderExpiryTimestamp(), maturity, "Order expiry timestamp should equal maturity"); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_RevertWhenExceedsMaturity() public { + vm.startPrank(maker); + + uint64 maturity = res.market.config().maturity; + uint64 invalidExpiryTimestamp = maturity + 1; + + vm.expectRevert(abi.encodeWithSelector(OrderErrorsV2.InvalidExpiryTimestamp.selector)); + res.order.setExpiryTimestamp(invalidExpiryTimestamp); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_SwapRevertsAfterExpiry() public { + vm.startPrank(maker); + + // Set expiry timestamp to 1 day from now + uint64 expiryTimestamp = uint64(block.timestamp + 1 days); + res.order.setExpiryTimestamp(expiryTimestamp); + + vm.stopPrank(); + + // Warp time to after expiry + vm.warp(expiryTimestamp); + + vm.startPrank(sender); + + uint128 underlyingAmtIn = 100e8; + uint128 minTokenOut = 0e8; + res.debt.mint(sender, underlyingAmtIn); + res.debt.approve(address(res.order), underlyingAmtIn); + + // Should revert because order has expired + vm.expectRevert(abi.encodeWithSelector(OrderErrors.TermIsNotOpen.selector)); + res.order.swapExactTokenToToken( + res.debt, res.ft, sender, underlyingAmtIn, minTokenOut, block.timestamp + 1 hours + ); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_SwapWorksBeforeExpiry() public { + vm.startPrank(maker); + + // Set expiry timestamp to 1 day from now + uint64 expiryTimestamp = uint64(block.timestamp + 1 days); + res.order.setExpiryTimestamp(expiryTimestamp); + + vm.stopPrank(); + + // Warp time to just before expiry + vm.warp(expiryTimestamp - 1); + + vm.startPrank(sender); + + uint128 underlyingAmtIn = 100e8; + uint128 minTokenOut = 0e8; + res.debt.mint(sender, underlyingAmtIn); + res.debt.approve(address(res.order), underlyingAmtIn); + + // Should work because we're still before expiry + uint256 netOut = res.order.swapExactTokenToToken( + res.debt, res.ft, sender, underlyingAmtIn, minTokenOut, block.timestamp + 1 hours + ); + + assertGt(netOut, 0, "Should receive tokens"); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_OnlyOwnerCanSet() public { + vm.startPrank(sender); + + uint64 maturity = res.market.config().maturity; + uint64 newExpiryTimestamp = maturity - 1 days; + + vm.expectRevert(abi.encodeWithSignature("OwnableUnauthorizedAccount(address)", sender)); + res.order.setExpiryTimestamp(newExpiryTimestamp); + + vm.stopPrank(); + } + + function testOrderExpiryTimestamp_MultipleUpdates() public { + vm.startPrank(maker); + + uint64 maturity = res.market.config().maturity; + + // Update 1 + uint64 timestamp1 = maturity - 3 days; + vm.expectEmit(); + emit OrderEventsV2.ExpiryTimestampUpdated(timestamp1); + res.order.setExpiryTimestamp(timestamp1); + assertEq(res.order.orderExpiryTimestamp(), timestamp1, "First update failed"); + + // Update 2 + uint64 timestamp2 = maturity - 2 days; + vm.expectEmit(); + emit OrderEventsV2.ExpiryTimestampUpdated(timestamp2); + res.order.setExpiryTimestamp(timestamp2); + assertEq(res.order.orderExpiryTimestamp(), timestamp2, "Second update failed"); + + // Update 3 - back to lower value + uint64 timestamp3 = maturity - 4 days; + vm.expectEmit(); + emit OrderEventsV2.ExpiryTimestampUpdated(timestamp3); + res.order.setExpiryTimestamp(timestamp3); + assertEq(res.order.orderExpiryTimestamp(), timestamp3, "Third update failed"); + + vm.stopPrank(); + } } // Mock contracts for testing From 0bebdc55a06dcc5969496f8bf69d52f9a6c2a8e1 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 10:50:04 +0800 Subject: [PATCH 14/21] change version tag --- contracts/v2/TermMaxMarketV2.sol | 4 ++-- contracts/v2/TermMaxOrderV2.sol | 4 ++-- contracts/v2/VersionV2_0_1.sol | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 contracts/v2/VersionV2_0_1.sol diff --git a/contracts/v2/TermMaxMarketV2.sol b/contracts/v2/TermMaxMarketV2.sol index f18a87c8..85612cf0 100644 --- a/contracts/v2/TermMaxMarketV2.sol +++ b/contracts/v2/TermMaxMarketV2.sol @@ -32,7 +32,7 @@ import {TransferUtilsV2} from "./lib/TransferUtilsV2.sol"; import {ITermMaxMarket, IMintableERC20, IERC20} from "../v1/ITermMaxMarket.sol"; import {IMintableERC20V2} from "./tokens/IMintableERC20V2.sol"; import {ITermMaxOrderV2} from "./ITermMaxOrderV2.sol"; -import {VersionV2} from "./VersionV2.sol"; +import {VersionV2_0_1} from "./VersionV2_0_1.sol"; /** * @title TermMax Market V2 @@ -45,7 +45,7 @@ contract TermMaxMarketV2 is Ownable2StepUpgradeable, MarketErrors, MarketEvents, - VersionV2 + VersionV2_0_1 { using SafeCast for uint256; using SafeCast for int256; diff --git a/contracts/v2/TermMaxOrderV2.sol b/contracts/v2/TermMaxOrderV2.sol index b301dcdf..d60c0874 100644 --- a/contracts/v2/TermMaxOrderV2.sol +++ b/contracts/v2/TermMaxOrderV2.sol @@ -22,7 +22,7 @@ import {TransferUtils} from "../v1/lib/TransferUtils.sol"; import {ITermMaxOrderV2, OrderInitialParams} from "./ITermMaxOrderV2.sol"; import {OrderEventsV2} from "./events/OrderEventsV2.sol"; import {OrderErrorsV2} from "./errors/OrderErrorsV2.sol"; -import {VersionV2} from "./VersionV2.sol"; +import {VersionV2_0_1} from "./VersionV2_0_1.sol"; /** * @title TermMax Order V2 @@ -37,7 +37,7 @@ contract TermMaxOrderV2 is PausableUpgradeable, OrderErrors, OrderEvents, - VersionV2 + VersionV2_0_1 { using SafeCast for uint256; using SafeCast for int256; diff --git a/contracts/v2/VersionV2_0_1.sol b/contracts/v2/VersionV2_0_1.sol new file mode 100644 index 00000000..12450c10 --- /dev/null +++ b/contracts/v2/VersionV2_0_1.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +abstract contract VersionV2_0_1 { + // Function to get the version number + function getVersion() public pure virtual returns (string memory) { + return "2.0.1"; + } +} From 060d5ed470452ae98709b03c1a9527c5344eb64e Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 19:44:34 +0800 Subject: [PATCH 15/21] update whitelist manager and fix unit tests --- contracts/v1/router/TermMaxRouter_V1_1_2.sol | 4 - contracts/v2/access/WhitelistManager.sol | 14 +- contracts/v2/access/WithWhitelistCheck.sol | 15 +- contracts/v2/factory/TermMax4626Factory.sol | 4 - contracts/v2/factory/TermMaxFactoryV2.sol | 4 - .../v2/factory/TermMaxVaultFactoryV2.sol | 4 - contracts/v2/router/TermMaxRouterV2.sol | 4 - contracts/v2/test/MockWhitelistManager.sol | 13 +- .../v2/tokens/OnlyDeliveryGearingToken.sol | 288 ---- contracts/v2/vault/TermMaxVaultV2.sol | 4 - script/deploy/DeployBaseV2.s.sol | 6 +- test/v2/AccessManagerV2.t.sol | 60 +- test/v2/FactoryV2.t.sol | 19 +- test/v2/MakerHelper.t.sol | 13 +- test/v2/OnlyDeliveryGt.t.sol | 1190 ----------------- test/v2/RouterV2.t.sol | 2 +- test/v2/VaultV2.t.sol | 33 +- test/v2/VaultV2WithPool.t.sol | 54 +- .../integration/ForkKodiakSwapAdapter.t.sol | 8 +- .../v2/integration/ForkOkxSwapAdapterV2.t.sol | 9 +- .../integration/ForkOneInchSwapAdapter.t.sol | 8 +- .../v2/integration/ForkPancakeAdapterV2.t.sol | 8 +- .../integration/ForkPancakeSmartAdapter.t.sol | 10 +- test/v2/integration/ForkPrdFlashRepay.t.sol | 17 +- test/v2/integration/ForkPrdRollOver.t.sol | 11 +- .../integration/ForkPrdRollOverToThird.t.sol | 9 +- .../integration/ForkStrataVaultAdapter.t.sol | 8 +- test/v2/integration/ForkTerminal.t.sol | 7 +- .../v2/integration/ForkUniswapAdapterV2.t.sol | 7 +- .../invariant/TermMaxVaultV2Invariant.t.sol | 2 +- test/v2/mainnet-fork/ForkBaseTestV2.sol | 49 - test/v2/mainnet-fork/GtBaseTestV2.t.sol | 18 +- test/v2/mainnet-fork/MarketBaseTestV2.t.sol | 11 +- test/v2/mainnet-fork/VaultBaseTestV2.t.sol | 11 +- test/v2/utils/DeployUtils.sol | 528 +++----- 35 files changed, 331 insertions(+), 2121 deletions(-) delete mode 100644 contracts/v2/tokens/OnlyDeliveryGearingToken.sol delete mode 100644 test/v2/OnlyDeliveryGt.t.sol diff --git a/contracts/v1/router/TermMaxRouter_V1_1_2.sol b/contracts/v1/router/TermMaxRouter_V1_1_2.sol index be176adc..3733b3c8 100644 --- a/contracts/v1/router/TermMaxRouter_V1_1_2.sol +++ b/contracts/v1/router/TermMaxRouter_V1_1_2.sol @@ -78,10 +78,6 @@ contract TermMaxRouter_V1_1_2 is _; } - function _getRegistry() internal view override returns (address) { - return owner(); - } - function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} constructor(address _whitelistManager) diff --git a/contracts/v2/access/WhitelistManager.sol b/contracts/v2/access/WhitelistManager.sol index baec3323..8337cd51 100644 --- a/contracts/v2/access/WhitelistManager.sol +++ b/contracts/v2/access/WhitelistManager.sol @@ -7,17 +7,27 @@ import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {IWhitelistManager} from "./IWhitelistManager.sol"; +import {WithAccessManagerRole} from "./WithAccessManagerRole.sol"; import {VersionV2} from "../VersionV2.sol"; /** + * TODO add with access manager role and whitelist check * @title WhitelistManager * @author Term Structure Labs * @notice Manages whitelists for different contract modules such as adapters, order callbacks, and markets * @dev This contract uses UUPS upgradeability and Ownable2Step for ownership management */ -contract WhitelistManager is IWhitelistManager, UUPSUpgradeable, Ownable2StepUpgradeable, VersionV2 { +contract WhitelistManager is + IWhitelistManager, + UUPSUpgradeable, + Ownable2StepUpgradeable, + WithAccessManagerRole, + VersionV2 +{ mapping(ContractModule => mapping(address => bool)) private whitelists; + constructor(address accessManager) WithAccessManagerRole(accessManager) {} + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} function initialize(address admin) public initializer { @@ -35,7 +45,7 @@ contract WhitelistManager is IWhitelistManager, UUPSUpgradeable, Ownable2StepUpg function batchSetWhitelist(address[] memory contractAddresses, ContractModule module, bool approved) external - onlyOwner + hasRole(WHITELIST_ROLE) { _setWhitelist(contractAddresses, module, approved); } diff --git a/contracts/v2/access/WithWhitelistCheck.sol b/contracts/v2/access/WithWhitelistCheck.sol index 0f22010d..5379dc96 100644 --- a/contracts/v2/access/WithWhitelistCheck.sol +++ b/contracts/v2/access/WithWhitelistCheck.sol @@ -3,16 +3,6 @@ pragma solidity ^0.8.0; import {IWhitelistManager} from "./IWhitelistManager.sol"; -/// @notice Minimal interface for the registry (e.g. AccessManagerV2) that can set whitelists -interface IWhitelistRegistry { - function batchSetWhitelist( - IWhitelistManager whitelistManager, - address[] calldata contractAddresses, - IWhitelistManager.ContractModule module, - bool approved - ) external; -} - abstract contract WithWhitelistCheck { error WhitelistManagerNotSet(); error NoWhitelistModuleConfigured(); @@ -27,9 +17,6 @@ abstract contract WithWhitelistCheck { defaultWhitelistModule = _defaultWhitelistModule; } - /// @notice Returns the address of the registry (e.g. AccessManagerV2) that has permission to set whitelists - function _getRegistry() internal view virtual returns (address); - function _registerAddress(address target) internal { _registerAddressWithModule(target, defaultWhitelistModule); } @@ -37,7 +24,7 @@ abstract contract WithWhitelistCheck { function _registerAddressWithModule(address target, IWhitelistManager.ContractModule module) internal { address[] memory targets = new address[](1); targets[0] = target; - IWhitelistRegistry(_getRegistry()).batchSetWhitelist(whitelistManager, targets, module, true); + whitelistManager.batchSetWhitelist(targets, module, true); } function _checkWhitelisted(address target, IWhitelistManager.ContractModule module) internal view { diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index 640585b2..b8cec096 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -52,10 +52,6 @@ contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerR ); } - function _getRegistry() internal view override returns (address) { - return ACCESS_MANAGER; - } - function getImplementations(string memory key) external view returns (address) { return implementations[keccak256(abi.encodePacked(key))]; } diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index 9a550b6f..624a941d 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -94,10 +94,6 @@ contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2, WithWh ); } - function _getRegistry() internal view override returns (address) { - return ACCESS_MANAGER; - } - /** * @notice Creates a new TermMax market with specified parameters * @dev Clones the market implementation and initializes it with the provided parameters diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index cc34ffec..61de53f1 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -42,10 +42,6 @@ contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhiteli ); } - function _getRegistry() internal view override returns (address) { - return ACCESS_MANAGER; - } - /** * @inheritdoc ITermMaxVaultFactoryV2 */ diff --git a/contracts/v2/router/TermMaxRouterV2.sol b/contracts/v2/router/TermMaxRouterV2.sol index 314891fd..81af84fc 100644 --- a/contracts/v2/router/TermMaxRouterV2.sol +++ b/contracts/v2/router/TermMaxRouterV2.sol @@ -88,10 +88,6 @@ contract TermMaxRouterV2 is WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) {} - function _getRegistry() internal view override returns (address) { - return owner(); - } - function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} function initialize(address admin) external initializer { diff --git a/contracts/v2/test/MockWhitelistManager.sol b/contracts/v2/test/MockWhitelistManager.sol index 234d687b..f86127fd 100644 --- a/contracts/v2/test/MockWhitelistManager.sol +++ b/contracts/v2/test/MockWhitelistManager.sol @@ -2,9 +2,8 @@ pragma solidity ^0.8.0; import {IWhitelistManager} from "../access/IWhitelistManager.sol"; -import {IWhitelistRegistry} from "../access/WithWhitelistCheck.sol"; -contract MockWhitelistManager is IWhitelistManager, IWhitelistRegistry { +contract MockWhitelistManager is IWhitelistManager { mapping(address => mapping(ContractModule => bool)) public whitelist; function setWhitelist(address _user, ContractModule _module, bool _approved) external { @@ -19,16 +18,6 @@ contract MockWhitelistManager is IWhitelistManager, IWhitelistRegistry { emit WhitelistUpdated(_addresses, _module, _approved); } - /// @dev IWhitelistRegistry implementation - forwards to the actual whitelist manager - function batchSetWhitelist( - IWhitelistManager _whitelistManager, - address[] calldata _addresses, - ContractModule _module, - bool _approved - ) external override { - _whitelistManager.batchSetWhitelist(_addresses, _module, _approved); - } - function isWhitelisted(address _user, ContractModule _module) external view returns (bool) { return whitelist[_user][_module]; } diff --git a/contracts/v2/tokens/OnlyDeliveryGearingToken.sol b/contracts/v2/tokens/OnlyDeliveryGearingToken.sol deleted file mode 100644 index 70ca87e1..00000000 --- a/contracts/v2/tokens/OnlyDeliveryGearingToken.sol +++ /dev/null @@ -1,288 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "./AbstractGearingTokenV2.sol"; - -/** - * @title TermMax Gearing Token, only support delivery, can not remove collateral - * after mint unless repay all debt - * @author Term Structure Labs - */ -contract OnlyDeliveryGearingToken is AbstractGearingTokenV2 { - using SafeCast for uint256; - using SafeCast for int256; - using TransferUtils for IERC20; - using TransferUtils for IERC20Metadata; - using Math for *; - - uint256 constant UINT256_LENGTH = 32; - - /// @notice The max capacity of collateral token - uint256 public collateralCapacity; - - uint256 private collateralDenominator; - - constructor() { - _disableInitializers(); - } - - function __GearingToken_Implement_init(bytes memory initialParams) internal override onlyInitializing { - if (_config.loanConfig.liquidatable) { - revert GtDoNotSupportLiquidation(); - } - _updateConfig(initialParams); - collateralDenominator = 10 ** IERC20Metadata(_config.collateral).decimals(); - } - - function _updateConfig(bytes memory configData) internal virtual override { - collateralCapacity = abi.decode(configData, (uint256)); - emit GearingTokenEventsV2.CollateralCapacityUpdated(collateralCapacity); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function flashRepay( - uint256 id, - uint128 repayAmt, - bool byDebtToken, - bytes memory removedCollateral, - bytes calldata callbackData - ) external virtual override nonReentrant isOwnerOrDelegate(id, msg.sender) returns (bool) { - LoanInfo memory loan = loanMapping[id]; - require( - repayAmt == loan.debtAmt && keccak256(removedCollateral) == keccak256(loan.collateralData), - GearingTokenErrorsV2.OnlyFullRepaySupported() - ); - return _flashRepay(id, repayAmt, byDebtToken, removedCollateral, callbackData); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function repayAndRemoveCollateral( - uint256 id, - uint128 repayAmt, - bool byDebtToken, - address collateralRecipient, - bytes memory removedCollateral - ) - external - virtual - override - nonReentrant - isOwnerOrDelegate(id, msg.sender) - returns (bool repayAll, uint128 finalRepayAmt) - { - GtConfig memory config = _config; - if (config.maturity <= block.timestamp) { - revert GearingTokenErrorsV2.GtIsExpired(); - } - LoanInfo memory loan; - (loan, repayAll, finalRepayAmt) = _repay(id, repayAmt); - if (loan.debtAmt != 0) { - revert GearingTokenErrorsV2.OnlyFullRepaySupported(); - } - loan.collateralData = _removeCollateral(loan, removedCollateral); - loanMapping[id] = loan; - // Transfer collateral to the recipient - _transferCollateral(collateralRecipient, removedCollateral); - // Transfer debt/ft tokens from caller to market - if (byDebtToken) { - config.debtToken.safeTransferFrom(msg.sender, marketAddr(), finalRepayAmt); - } else { - config.ft.safeTransferFrom(msg.sender, marketAddr(), finalRepayAmt); - } - emit GearingTokenEventsV2.RepayAndRemoveCollateral(id, finalRepayAmt, byDebtToken, removedCollateral); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function augmentDebt(address caller, uint256 id, uint256 ftAmt) - external - virtual - override - nonReentrant - onlyOwner - isOwnerOrDelegate(id, caller) - { - revert GearingTokenErrorsV2.CannotAugmentDebtOnOnlyDeliveryGt(); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function removeCollateral(uint256 id, bytes memory collateralData) - external - virtual - override - nonReentrant - isOwnerOrDelegate(id, msg.sender) - { - GtConfig memory config = _config; - if (config.maturity <= block.timestamp) { - revert GearingTokenErrorsV2.GtIsExpired(); - } - - LoanInfo memory loan = loanMapping[id]; - if (loan.debtAmt != 0) { - revert GearingTokenErrorsV2.CannotRemoveCollateralWithDebt(); - } - loan.collateralData = _removeCollateral(loan, collateralData); - loanMapping[id] = loan; - - // Transfer collateral to the owner or delegator - _transferCollateral(msg.sender, collateralData); - - emit RemoveCollateral(id, loan.collateralData); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function getLiquidationInfo(uint256 id) - external - view - virtual - override - returns (bool isLiquidable, uint128 ltv, uint128 maxRepayAmt) - { - (,, ltv,) = _getLiquidationInfo(loanMapping[id], _config); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function liquidate(uint256 id, uint128 repayAmt, bool byDebtToken) external virtual override nonReentrant { - revert GtDoNotSupportLiquidation(); - } - - function _checkBeforeMint(uint128, bytes memory collateralData) internal virtual override { - if (collateralData.length > UINT256_LENGTH) { - revert GearingTokenErrorsV2.InvalidCollateralData(); - } - if (IERC20(_config.collateral).balanceOf(address(this)) + _decodeAmount(collateralData) > collateralCapacity) { - revert GearingTokenErrorsV2.CollateralCapacityExceeded(); - } - } - - function _delivery(uint256 proportion) internal view virtual override returns (bytes memory deliveryData) { - uint256 collateralReserve = IERC20(_config.collateral).balanceOf(address(this)); - uint256 amount = collateralReserve.mulDiv(proportion, Constants.DECIMAL_BASE_SQ); - deliveryData = abi.encode(amount); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _mergeCollateral(bytes memory collateralDataA, bytes memory collateralDataB) - internal - virtual - override - returns (bytes memory collateralData) - { - uint256 total = _decodeAmount(collateralDataA) + _decodeAmount(collateralDataB); - collateralData = abi.encode(total); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _transferCollateralFrom(address from, address to, bytes memory collateralData) internal virtual override { - uint256 amount = _decodeAmount(collateralData); - if (amount != 0) { - IERC20(_config.collateral).safeTransferFrom(from, to, amount); - } - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _transferCollateral(address to, bytes memory collateralData) internal virtual override { - uint256 amount = _decodeAmount(collateralData); - if (amount != 0) { - IERC20(_config.collateral).safeTransfer(to, amount); - } - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _getCollateralValue(bytes memory collateralData, bytes memory priceData) - internal - view - virtual - override - returns (uint256) - { - uint256 collateralAmt = _decodeAmount(collateralData); - (uint256 price, uint256 priceDenominator, uint256 collateralDenominator) = - abi.decode(priceData, (uint256, uint256, uint256)); - return collateralAmt.mulDiv(price * Constants.DECIMAL_BASE, priceDenominator * collateralDenominator); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _getCollateralPriceData(GtConfig memory config) - internal - view - virtual - override - returns (bytes memory priceData) - { - (uint256 price, uint8 decimals) = config.loanConfig.oracle.getPrice(config.collateral); - uint256 priceDenominator = 10 ** decimals; - - priceData = abi.encode(price, priceDenominator, collateralDenominator); - } - - /// @notice Decode amount from collateral data - function _decodeAmount(bytes memory collateralData) internal pure returns (uint256 amount) { - amount = abi.decode(collateralData, (uint256)); - } - - /// @notice Encode amount to collateral data - function _encodeAmount(uint256 amount) internal pure returns (bytes memory) { - return abi.encode(amount); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _removeCollateral(LoanInfo memory loan, bytes memory collateralData) - internal - virtual - override - returns (bytes memory) - { - uint256 amount = _decodeAmount(loan.collateralData) - _decodeAmount(collateralData); - return _encodeAmount(amount); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _addCollateral(LoanInfo memory loan, bytes memory collateralData) - internal - virtual - override - returns (bytes memory) - { - uint256 amount = _decodeAmount(loan.collateralData) + _decodeAmount(collateralData); - return _encodeAmount(amount); - } - - /** - * @inheritdoc AbstractGearingTokenV2 - */ - function _calcLiquidationResult(LoanInfo memory loan, uint128 repayAmt, ValueAndPrice memory valueAndPrice) - internal - virtual - override - returns (bytes memory, bytes memory, bytes memory) - { - revert GtDoNotSupportLiquidation(); - } -} diff --git a/contracts/v2/vault/TermMaxVaultV2.sol b/contracts/v2/vault/TermMaxVaultV2.sol index d62d2a55..41227fc0 100644 --- a/contracts/v2/vault/TermMaxVaultV2.sol +++ b/contracts/v2/vault/TermMaxVaultV2.sol @@ -92,10 +92,6 @@ contract TermMaxVaultV2 is _disableInitializers(); } - function _getRegistry() internal view override returns (address) { - return owner(); - } - function initialize(VaultInitialParamsV2 memory params) external virtual initializer { __ERC20_init_unchained(params.name, params.symbol); __Ownable_init_unchained(params.admin); diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index 14bf8951..a97b630a 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -523,9 +523,9 @@ contract DeployBaseV2 is Script { terminalVaultAdapter = new TerminalVaultAdapter(); } - function deployWhitelistManager(address admin) public returns (WhitelistManager whitelistManager) { - address implementation = address(new WhitelistManager()); - bytes memory data = abi.encodeCall(WhitelistManager.initialize, admin); + function deployWhitelistManager(address accessManager) public returns (WhitelistManager whitelistManager) { + address implementation = address(new WhitelistManager(accessManager)); + bytes memory data = abi.encodeCall(WhitelistManager.initialize, accessManager); address proxy = address(new ERC1967Proxy(address(implementation), data)); whitelistManager = WhitelistManager(proxy); } diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index f8fa087e..a4b09d7f 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -32,7 +32,7 @@ import {TermMaxOrderV2} from "contracts/v2/TermMaxOrderV2.sol"; import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "contracts/v2/vault/ITermMaxVaultV2.sol"; import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; -import {MockWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; +import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; contract AccessManagerTestV2 is Test { using JSONLoader for *; @@ -50,7 +50,7 @@ contract AccessManagerTestV2 is Test { AccessManagerV2 manager; address curator = vm.randomAddress(); TermMaxOrderV2 vaultOrder; - MockWhitelistManager whitelistManager; + WhitelistManager whitelistManager; function setUp() public { vm.startPrank(deployer); @@ -62,16 +62,9 @@ contract AccessManagerTestV2 is Test { marketConfig = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); orderConfig = JSONLoader.getOrderConfigFromJson(testdata, ".orderConfig"); - whitelistManager = new MockWhitelistManager(); - - AccessManagerV2 implementation = new AccessManagerV2(); - bytes memory data = abi.encodeCall(AccessManager.initialize, deployer); - address proxy = address(new ERC1967Proxy(address(implementation), data)); - - manager = AccessManagerV2(proxy); - - res = DeployUtils.deployMarket(deployer, manager, marketConfig, maxLtv, liquidationLtv, whitelistManager); - + res = DeployUtils.deployMarket(deployer, marketConfig, maxLtv, liquidationLtv); + whitelistManager = res.whitelistManager; + manager = res.accessManager; res.order = TermMaxOrderV2( address( res.market.createOrder( @@ -93,25 +86,14 @@ contract AccessManagerTestV2 is Test { res.ft.transfer(address(res.order), amount); res.xt.transfer(address(res.order), amount); - res.router = DeployUtils.deployRouter(deployer, res.whitelistManager); + res.router = DeployUtils.deployRouter(deployer, address(res.whitelistManager)); - IOwnable(address(res.factory)).transferOwnership(address(manager)); - IOwnable(address(res.market)).transferOwnership(address(manager)); - IOwnable(address(res.router)).transferOwnership(address(manager)); - IOwnable(address(res.oracle)).transferOwnership(address(manager)); - - manager.acceptOwnership(IOwnable(address(res.factory))); - manager.acceptOwnership(IOwnable(address(res.market))); + res.router.transferOwnership(address(manager)); manager.acceptOwnership(IOwnable(address(res.router))); + res.oracle.transferOwnership(address(manager)); manager.acceptOwnership(IOwnable(address(res.oracle))); - - manager.grantRole(manager.CONFIGURATOR_ROLE(), deployer); - manager.grantRole(manager.PAUSER_ROLE(), deployer); - manager.grantRole(manager.VAULT_ROLE(), deployer); - manager.grantRole(manager.MARKET_ROLE(), deployer); - manager.grantRole(manager.ORACLE_ROLE(), deployer); - manager.grantRole(manager.WHITELIST_ROLE(), deployer); - manager.grantRole(manager.UPGRADER_ROLE(), deployer); + res.market.transferOwnership(address(manager)); + manager.acceptOwnership(IOwnable(address(res.market))); // Create vault initialization parameters VaultInitialParamsV2 memory params = VaultInitialParamsV2({ @@ -129,7 +111,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - res.vault = DeployUtils.deployVault(deployer, manager, params, res.whitelistManager); + res.vault = DeployUtils.deployVault(res.vaultFactory, params); vm.stopPrank(); vm.startPrank(curator); @@ -351,7 +333,7 @@ contract AccessManagerTestV2 is Test { }); // Deploy vault - TermMaxVaultV2 vault = DeployUtils.deployVault(address(manager), params); + TermMaxVaultV2 vault = DeployUtils.deployVault(res.vaultFactory, params, 1); // Grant VAULT_ROLE to the vault manager vm.startPrank(deployer); @@ -389,14 +371,19 @@ contract AccessManagerTestV2 is Test { vm.stopPrank(); } + function _setWhitelist(address addr, IWhitelistManager.ContractModule module, bool status) internal { + address[] memory addrArray = new address[](1); + addrArray[0] = addr; + manager.batchSetWhitelist(IWhitelistManager(address(res.whitelistManager)), addrArray, module, status); + } + function testRevokeVaultPendingValues() public { address newMarket = vm.randomAddress(); address newGuardian = vm.randomAddress(); address vaultManager = vm.randomAddress(); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newMarket, IWhitelistManager.ContractModule.MARKET, true - ); + vm.prank(deployer); + _setWhitelist(newMarket, IWhitelistManager.ContractModule.MARKET, true); // Grant VAULT_ROLE to the vault manager and set curator vm.startPrank(deployer); @@ -731,14 +718,13 @@ contract AccessManagerTestV2 is Test { minApy: 0 }); - TermMaxVaultV2 poolVault = DeployUtils.deployVault(deployer, manager, poolParams, res.whitelistManager); + TermMaxVaultV2 poolVault = DeployUtils.deployVault(res.vaultFactory, poolParams); ITermMaxVaultV2 poolVaultV2 = ITermMaxVaultV2(address(poolVault)); address vaultManager = vm.randomAddress(); address newPoolAddress = vm.randomAddress(); // Mock pool address - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(deployer); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, true); // Grant VAULT_ROLE to the vault manager vm.startPrank(deployer); diff --git a/test/v2/FactoryV2.t.sol b/test/v2/FactoryV2.t.sol index 0f13566d..4546f4ac 100644 --- a/test/v2/FactoryV2.t.sol +++ b/test/v2/FactoryV2.t.sol @@ -45,15 +45,19 @@ contract FactoryTestV2 is Test { uint32 liquidationLtv = 0.9e8; MarketConfig marketConfig; + DeployUtils.Res res; + function setUp() public { string memory testdata = vm.readFile(string.concat(vm.projectRoot(), "/test/testdata/testdata.json")); marketConfig = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); + vm.startPrank(deployer); + res = DeployUtils.deployMarket(deployer, marketConfig, maxLtv, liquidationLtv); + vm.stopPrank(); } function testDeploy() public { vm.startPrank(deployer); - DeployUtils.Res memory res = DeployUtils.deployMarket(deployer, marketConfig, maxLtv, liquidationLtv); address predictedMarketAddress = res.factory.predictMarketAddress( deployer, address(res.collateral), address(res.debt), marketConfig.maturity, 0 @@ -104,7 +108,8 @@ contract FactoryTestV2 is Test { function testDeployMarketWithInvalidParams() public { vm.startPrank(deployer); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + + TermMaxFactoryV2 factory = res.factory; MockERC20 collateral = new MockERC20("ETH", "ETH", 18); MockERC20 debt = new MockERC20("DAI", "DAI", 8); @@ -155,7 +160,7 @@ contract FactoryTestV2 is Test { function testLiquidationLtvMustBeGreaterThanMaxLtv() public { vm.startPrank(deployer); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = res.factory; MockERC20 collateral = new MockERC20("ETH", "ETH", 18); MockERC20 debt = new MockERC20("DAI", "DAI", 8); @@ -188,7 +193,7 @@ contract FactoryTestV2 is Test { function testInvalidLiquidationLtv() public { vm.startPrank(deployer); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = res.factory; MockERC20 collateral = new MockERC20("ETH", "ETH", 18); MockERC20 debt = new MockERC20("DAI", "DAI", 8); @@ -221,7 +226,7 @@ contract FactoryTestV2 is Test { function testRevertByCantNotFindGtImplementation() public { vm.startPrank(deployer); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = res.factory; MockERC20 collateral = new MockERC20("ETH", "ETH", 18); MockERC20 debt = new MockERC20("DAI", "DAI", 8); @@ -252,7 +257,7 @@ contract FactoryTestV2 is Test { function testSetGtImplement() public { vm.startPrank(deployer); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = res.factory; GearingTokenWithERC20V2 gt = new GearingTokenWithERC20V2(); string memory gtImplemtName = "gt-test"; bytes32 key = keccak256(abi.encodePacked(gtImplemtName)); @@ -266,7 +271,7 @@ contract FactoryTestV2 is Test { function testSetGtImplementWithoutAuth() public { address sender = vm.randomAddress(); vm.startPrank(sender); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer); + TermMaxFactoryV2 factory = res.factory; GearingTokenWithERC20V2 gt = new GearingTokenWithERC20V2(); string memory key = "gt-test"; diff --git a/test/v2/MakerHelper.t.sol b/test/v2/MakerHelper.t.sol index 27134506..b75a7060 100644 --- a/test/v2/MakerHelper.t.sol +++ b/test/v2/MakerHelper.t.sol @@ -262,17 +262,16 @@ contract MakerHelperTest is Test { (uint8 v, bytes32 r, bytes32 s) = vm.sign(delegatorPrivateKey, digest); DelegateAble.Signature memory delegateSignature = DelegateAble.Signature({v: v, r: r, s: s}); - // Switch to delegatee to call the function (as required by setDelegateWithSignature) + // Switch to delegator to call the function (as required by setDelegateWithSignature) vm.stopPrank(); - vm.startPrank(delegatee); - - // Also need to approve tokens for delegatee - res.debt.mint(delegatee, debtTokenToDeposit); - deal(address(res.ft), delegatee, ftToDeposit); + vm.startPrank(delegator); + // Also need to approve tokens for delegator + res.debt.mint(delegator, debtTokenToDeposit); + deal(address(res.ft), delegator, ftToDeposit); res.debt.approve(address(makerHelper), debtTokenToDeposit); res.ft.approve(address(makerHelper), ftToDeposit); res.xt.approve(address(makerHelper), xtToDeposit); - res.collateral.mint(delegatee, collateralToMintGt); + res.collateral.mint(delegator, collateralToMintGt); res.collateral.approve(address(makerHelper), collateralToMintGt); if (salt % 2 == 0) { vm.expectRevert(MakerHelperErrors.OrderAddressIsDifferentFromDelegatee.selector); diff --git a/test/v2/OnlyDeliveryGt.t.sol b/test/v2/OnlyDeliveryGt.t.sol deleted file mode 100644 index 823550e4..00000000 --- a/test/v2/OnlyDeliveryGt.t.sol +++ /dev/null @@ -1,1190 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; -import {DeployUtils} from "./utils/DeployUtils.sol"; -import {JSONLoader} from "./utils/JSONLoader.sol"; -import {StateChecker} from "./utils/StateChecker.sol"; -import {SwapUtils} from "./utils/SwapUtils.sol"; -import {LoanUtils} from "./utils/LoanUtils.sol"; - -import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {Constants} from "contracts/v1/lib/Constants.sol"; -import { - ITermMaxMarketV2, TermMaxMarketV2, Constants, MarketErrors, MarketEvents -} from "contracts/v2/TermMaxMarketV2.sol"; -import {MockERC20, ERC20} from "contracts/v1/test/MockERC20.sol"; - -import {MockPriceFeed} from "contracts/v1/test/MockPriceFeed.sol"; -import {IMintableERC20} from "contracts/v1/tokens/MintableERC20.sol"; -import {IGearingToken} from "contracts/v1/tokens/IGearingToken.sol"; -import { - GearingTokenWithERC20V2, - GearingTokenEvents, - GearingTokenErrors, - GearingTokenErrorsV2, - GearingTokenEventsV2, - GtConfig -} from "contracts/v2/tokens/GearingTokenWithERC20V2.sol"; -import { - ITermMaxFactory, - TermMaxFactoryV2, - FactoryErrors, - FactoryEvents, - FactoryEventsV2 -} from "contracts/v2/factory/TermMaxFactoryV2.sol"; -import {IOracleV2, OracleAggregatorV2, AggregatorV3Interface} from "contracts/v2/oracle/OracleAggregatorV2.sol"; -import {IOracle} from "contracts/v1/oracle/IOracle.sol"; -import { - VaultInitialParams, - MarketConfig, - MarketInitialParams, - LoanConfig, - OrderConfig, - CurveCuts -} from "contracts/v1/storage/TermMaxStorage.sol"; -import {MockFlashLoanReceiver} from "contracts/v1/test/MockFlashLoanReceiver.sol"; -import {MockFlashRepayerV2} from "contracts/v2/test/MockFlashRepayerV2.sol"; -import {ISwapCallback} from "contracts/v1/ISwapCallback.sol"; -import {TermMaxOrderV2, OrderInitialParams} from "contracts/v2/TermMaxOrderV2.sol"; -import {OnlyDeliveryGearingToken} from "contracts/v2/tokens/OnlyDeliveryGearingToken.sol"; - -contract OnlyDeliveryGtTest is Test { - using JSONLoader for *; - using SafeCast for uint256; - using SafeCast for int256; - - DeployUtils.Res res; - - OrderConfig orderConfig; - MarketConfig marketConfig; - - address deployer = vm.randomAddress(); - address sender = vm.randomAddress(); - address treasurer = vm.randomAddress(); - address maker = vm.randomAddress(); - string testdata; - - MockFlashLoanReceiver flashLoanReceiver; - - MockFlashRepayerV2 flashRepayer; - - uint32 maxLtv = 0.89e8; - uint32 liquidationLtv = 0.9e8; - - function setUp() public { - vm.startPrank(deployer); - testdata = vm.readFile(string.concat(vm.projectRoot(), "/test/testdata/testdata.json")); - - marketConfig = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); - orderConfig = JSONLoader.getOrderConfigFromJson(testdata, ".orderConfig"); - orderConfig.maxXtReserve = type(uint128).max; - // vm.expectRevert(GearingTokenErrors.GtDoNotSupportLiquidation.selector); - res = DeployUtils.deployOnlyDeliveryMarket(deployer, marketConfig, maxLtv, liquidationLtv); - - res.order = TermMaxOrderV2( - address( - res.market.createOrder( - maker, orderConfig.maxXtReserve, ISwapCallback(address(0)), orderConfig.curveCuts - ) - ) - ); - - OrderInitialParams memory orderParams; - orderParams.maker = maker; - orderParams.orderConfig = orderConfig; - uint256 amount = 15000e8; - orderParams.virtualXtReserve = amount; - res.order = TermMaxOrderV2(address(res.market.createOrder(orderParams))); - - vm.warp(vm.parseUint(vm.parseJsonString(testdata, ".currentTime"))); - - // update oracle - res.collateralOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_2000_DAI_1.eth")); - res.debtOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_2000_DAI_1.dai")); - - res.debt.mint(deployer, amount); - res.debt.approve(address(res.market), amount); - res.market.mint(deployer, amount); - res.ft.transfer(address(res.order), amount); - res.xt.transfer(address(res.order), amount); - - flashLoanReceiver = new MockFlashLoanReceiver(res.market); - flashRepayer = new MockFlashRepayerV2(res.gt); - - vm.stopPrank(); - } - - function testMintGtByIssueFt() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - res.collateral.mint(sender, collateralAmt); - - vm.startPrank(sender); - - res.collateral.approve(address(res.gt), collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - uint256 issueFee = (debtAmt * res.market.mintGtFeeRatio()) / Constants.DECIMAL_BASE; - vm.expectEmit(); - emit MarketEvents.IssueFt( - sender, sender, 1, debtAmt, uint128(debtAmt - issueFee), uint128(issueFee), collateralData - ); - - (uint256 gtId, uint128 ftOutAmt) = res.market.issueFt(sender, debtAmt, collateralData); - - assert(ftOutAmt == (debtAmt - issueFee)); - assert(gtId == 1); - - state.collateralReserve += collateralAmt; - StateChecker.checkMarketState(res, state); - - assert(res.ft.balanceOf(marketConfig.treasurer) == issueFee); - assert(res.ft.balanceOf(sender) == ftOutAmt); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assert(owner == sender); - assert(d == debtAmt); - assert(collateralAmt == abi.decode(cd, (uint256))); - (, uint128 ltv,) = res.gt.getLiquidationInfo(gtId); - assert(LoanUtils.calcLtv(res, debtAmt, collateralAmt) == ltv); - - vm.stopPrank(); - } - - function testMintGtWithInvalidCollateral() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - res.collateral.mint(sender, collateralAmt); - - vm.startPrank(sender); - - res.collateral.approve(address(res.gt), collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - bytes memory byte12k = new bytes(12 * 1024); // 12KB - collateralData = abi.encodePacked(collateralData, byte12k); - - vm.expectRevert(GearingTokenErrorsV2.InvalidCollateralData.selector); - res.market.issueFt(sender, debtAmt, collateralData); - - vm.stopPrank(); - } - - function testMintGtByLeverage() public { - vm.startPrank(sender); - uint256 collateralAmt = 1e18; - bytes memory callbackData = abi.encode(sender, collateralAmt); - res.collateral.mint(address(flashLoanReceiver), collateralAmt); - - uint128 xtAmt = 90e8; - uint256 debtAmt = xtAmt * Constants.DECIMAL_BASE / (Constants.DECIMAL_BASE - res.market.mintGtFeeRatio()); - - uint128 debtAmtInForBuyXt = 5e8; - uint128 minXTOut = 0e8; - res.debt.mint(sender, debtAmtInForBuyXt); - res.debt.approve(address(res.order), debtAmtInForBuyXt); - res.order.swapExactTokenToToken( - res.debt, res.xt, sender, debtAmtInForBuyXt, minXTOut, block.timestamp + 1 hours - ); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - uint256 xtBefore = res.xt.balanceOf(address(sender)); - - res.xt.approve(address(flashLoanReceiver), xtAmt); - - vm.expectEmit(); - emit MarketEvents.LeverageByXt( - address(flashLoanReceiver), - sender, - 1, - uint128(debtAmt), - xtAmt, - uint128(debtAmt - xtAmt), - abi.encode(collateralAmt) - ); - uint256 gtId = flashLoanReceiver.leverageByXt(xtAmt, callbackData); - - assert(gtId == 1); - state.collateralReserve += collateralAmt; - state.debtReserve -= xtAmt; - StateChecker.checkMarketState(res, state); - - uint256 xtAfter = res.xt.balanceOf(address(sender)); - assert(xtBefore - xtAfter == xtAmt); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assert(owner == sender); - assert(d == debtAmt); - assert(collateralAmt == abi.decode(cd, (uint256))); - - vm.stopPrank(); - } - - function testMintGtWhenOracleOutdated() public { - uint128 debtAmt = 1000e8; - uint256 collateralAmt = 1e18; - res.collateral.mint(sender, collateralAmt); - - vm.prank(deployer); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 3600, 3600) - ); - vm.warp(block.timestamp + 3600); - - vm.startPrank(sender); - res.collateral.approve(address(res.gt), collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - - vm.expectRevert(abi.encodeWithSelector(IOracleV2.OracleIsNotWorking.selector, address(res.collateral))); - res.market.issueFt(sender, debtAmt, collateralData); - - vm.stopPrank(); - - vm.startPrank(deployer); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) - ); - vm.stopPrank(); - - vm.startPrank(sender); - res.collateral.approve(address(res.gt), collateralAmt); - res.market.issueFt(sender, debtAmt, collateralData); - - vm.stopPrank(); - } - - function testRevertByGtIsNotHealthyWhenIssueFt() public { - // debt 1790 USD collaretal 2000USD ltv 0.891 - uint128 debtAmt = 1790e8; - uint256 collateralAmt = 1e18; - res.collateral.mint(sender, collateralAmt); - - vm.startPrank(sender); - - res.collateral.approve(address(res.gt), collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - - vm.expectRevert( - abi.encodeWithSelector( - GearingTokenErrors.GtIsNotHealthy.selector, 0, sender, LoanUtils.calcLtv(res, debtAmt, collateralAmt) - ) - ); - res.market.issueFt(sender, debtAmt, collateralData); - - vm.stopPrank(); - } - - function testRevertByGtIsNotHealthyWhenCollateralCloseZero() public { - // debt 5 USD collaretal 2e-7 USD - uint128 debtAmt = 5e8; - uint256 collateralAmt = 1; - res.collateral.mint(sender, collateralAmt); - - vm.startPrank(sender); - - res.collateral.approve(address(res.gt), collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - - vm.expectRevert( - abi.encodeWithSelector( - GearingTokenErrors.GtIsNotHealthy.selector, 0, sender, LoanUtils.calcLtv(res, debtAmt, collateralAmt) - ) - ); - res.market.issueFt(sender, debtAmt, collateralData); - - vm.stopPrank(); - } - - function testRevertByGtIsNotHealthyWhenLeverage() public { - vm.startPrank(sender); - uint256 collateralAmt = 0.001e18; - bytes memory callbackData = abi.encode(sender, collateralAmt); - res.collateral.mint(address(flashLoanReceiver), collateralAmt); - - uint128 xtAmt = 90e8; - uint256 debtAmt = xtAmt * Constants.DECIMAL_BASE / (Constants.DECIMAL_BASE - res.market.mintGtFeeRatio()); - - uint128 debtAmtInForBuyXt = 5e8; - uint128 minXTOut = 0e8; - res.debt.mint(sender, debtAmtInForBuyXt); - res.debt.approve(address(res.order), debtAmtInForBuyXt); - res.order.swapExactTokenToToken( - res.debt, res.xt, sender, debtAmtInForBuyXt, minXTOut, block.timestamp + 1 hours - ); - - res.xt.approve(address(flashLoanReceiver), xtAmt); - - vm.expectRevert( - abi.encodeWithSelector( - GearingTokenErrors.GtIsNotHealthy.selector, 0, sender, LoanUtils.calcLtv(res, debtAmt, collateralAmt) - ) - ); - flashLoanReceiver.leverageByXt(xtAmt, callbackData); - - vm.stopPrank(); - } - - function testReapyByDebtToken() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, debtAmt); - - res.debt.approve(address(res.gt), debtAmt); - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - uint256 debtBalanceBefore = res.debt.balanceOf(sender); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - bool byDebtToken = true; - vm.expectEmit(); - emit GearingTokenEventsV2.Repay(gtId, debtAmt, byDebtToken, true); - res.gt.repay(gtId, debtAmt, byDebtToken); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 debtBalanceAfter = res.debt.balanceOf(sender); - state.debtReserve += debtAmt; - state.collateralReserve -= collateralAmt; - StateChecker.checkMarketState(res, state); - - assert(collateralBalanceAfter - collateralBalanceBefore == collateralAmt); - assert(debtBalanceAfter + debtAmt == debtBalanceBefore); - vm.expectRevert(abi.encodePacked(bytes4(keccak256("ERC721NonexistentToken(uint256)")), gtId)); - res.gt.loanInfo(gtId); - - vm.stopPrank(); - } - - function testReapyByFt() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - // get FT token - uint128 debtAmtInForBuyFt = 100e8; - uint128 minFTOut = 0e8; - res.debt.mint(sender, debtAmtInForBuyFt); - res.debt.approve(address(res.order), debtAmtInForBuyFt); - res.order.swapExactTokenToToken( - res.debt, res.ft, sender, debtAmtInForBuyFt, minFTOut, block.timestamp + 1 hours - ); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - uint256 ftBalanceBefore = res.ft.balanceOf(sender); - uint256 ftInMarketBefore = res.ft.balanceOf(address(res.market)); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - res.ft.approve(address(res.gt), debtAmt); - - bool byDebtToken = false; - vm.expectEmit(); - emit GearingTokenEventsV2.Repay(gtId, debtAmt, byDebtToken, true); - res.gt.repay(gtId, debtAmt, byDebtToken); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 ftBalanceAfter = res.ft.balanceOf(sender); - uint256 ftInMarketAfter = res.ft.balanceOf(address(res.market)); - state.collateralReserve -= collateralAmt; - StateChecker.checkMarketState(res, state); - assert(ftInMarketAfter - debtAmt == ftInMarketBefore); - assert(collateralBalanceAfter - collateralBalanceBefore == collateralAmt); - assert(ftBalanceAfter + debtAmt == ftBalanceBefore); - vm.expectRevert(abi.encodePacked(bytes4(keccak256("ERC721NonexistentToken(uint256)")), gtId)); - res.gt.loanInfo(gtId); - - vm.stopPrank(); - } - - function testPatriallyReapy() public { - uint128 debtAmt = 100e8; - uint128 repayAmt = 10e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - // Repay repayAmt - address thirdPeople = vm.randomAddress(); - res.debt.mint(thirdPeople, debtAmt); - // Repay repayAmt - vm.startPrank(thirdPeople); - res.debt.approve(address(res.gt), debtAmt); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - bool byDebtToken = true; - vm.expectEmit(); - emit GearingTokenEventsV2.Repay(gtId, repayAmt, byDebtToken, false); - res.gt.repay(gtId, repayAmt, byDebtToken); - state.debtReserve += repayAmt; - StateChecker.checkMarketState(res, state); - assert(res.debt.balanceOf(thirdPeople) == debtAmt - repayAmt); - assert(res.collateral.balanceOf(thirdPeople) == 0); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assert(owner == sender); - assert(d == debtAmt - repayAmt); - assert(collateralAmt == abi.decode(cd, (uint256))); - - // Repay all - uint256 debtBalanceBefore = res.debt.balanceOf(sender); - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - - vm.expectEmit(); - emit GearingTokenEventsV2.Repay(gtId, debtAmt - repayAmt, byDebtToken, true); - res.gt.repay(gtId, debtAmt - repayAmt, byDebtToken); - - state.debtReserve += (debtAmt - repayAmt); - state.collateralReserve -= collateralAmt; - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 debtBalanceAfter = res.debt.balanceOf(sender); - StateChecker.checkMarketState(res, state); - - assert(collateralBalanceAfter - collateralBalanceBefore == collateralAmt); - assert(debtBalanceAfter == debtBalanceBefore); - assert(res.debt.balanceOf(thirdPeople) == 0); - assert(res.collateral.balanceOf(thirdPeople) == 0); - - vm.expectRevert(abi.encodePacked(bytes4(keccak256("ERC721NonexistentToken(uint256)")), gtId)); - res.gt.loanInfo(gtId); - - vm.stopPrank(); - } - - function testRepayAmtExceedsMaxRepayAmt() public { - uint128 debtAmt = 9000e8; - uint256 collateralAmt = 10e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - uint128 maxRepayAmt = 10000e8; - res.debt.mint(sender, maxRepayAmt); - res.debt.approve(address(res.gt), maxRepayAmt); - - uint256 debtBalanceBefore = res.debt.balanceOf(sender); - res.gt.repay(gtId, maxRepayAmt, true); - assertEq(res.debt.balanceOf(sender), debtBalanceBefore - debtAmt, "sender debt balance after repay"); - - vm.stopPrank(); - } - - function testFlashRepay() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(address(flashRepayer), debtAmt); - res.gt.approve(address(flashRepayer), gtId); - - uint256 removedCollateral = collateralAmt; - uint128 repayAmt = debtAmt; - bool byDebtToken = true; - bool repayAll = true; - - vm.expectEmit(); - emit GearingTokenEventsV2.FlashRepay( - gtId, address(flashRepayer), repayAmt, byDebtToken, repayAll, abi.encode(removedCollateral) - ); - flashRepayer.flashRepay(gtId, repayAmt, byDebtToken, abi.encode(removedCollateral)); - - vm.stopPrank(); - } - - function testPartialFlashRepay() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(address(flashRepayer), debtAmt); - res.gt.approve(address(flashRepayer), gtId); - - uint256 removedCollateral = 0.5e18; - uint128 repayAmt = 50e8; - bool byDebtToken = true; - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.OnlyFullRepaySupported.selector)); - flashRepayer.flashRepay(gtId, repayAmt, byDebtToken, abi.encode(removedCollateral)); - - vm.stopPrank(); - } - - function testRevertByGtIsExpiredWhenRepay() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.warp(marketConfig.maturity); - res.debt.mint(sender, debtAmt); - - res.debt.approve(address(res.gt), debtAmt); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIsExpired.selector)); - res.gt.repay(gtId, debtAmt, true); - - vm.stopPrank(); - } - - function testRevertByGtIsExpiredWhenFlashRepay() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.warp(marketConfig.maturity); - res.debt.mint(address(flashRepayer), debtAmt); - res.gt.approve(address(flashRepayer), gtId); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIsExpired.selector)); - flashRepayer.flashRepay(gtId, debtAmt, true, abi.encode(collateralAmt)); - } - - function testMerge() public { - uint40[3] memory debts = [100e8, 30e8, 5e8]; - uint64[3] memory collaterals = [1e18, 0.5e18, 0.05e18]; - - vm.startPrank(sender); - - uint256[] memory ids = new uint256[](3); - for (uint256 i = 0; i < ids.length; ++i) { - (ids[i],) = LoanUtils.fastMintGt(res, sender, debts[i], collaterals[i]); - } - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - vm.expectEmit(); - uint256 newId = ids[0]; - emit GearingTokenEvents.MergeGts(sender, newId, ids); - newId = res.gt.merge(ids); - StateChecker.checkMarketState(res, state); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(newId); - assert(owner == sender); - assert(d == debts[0] + debts[1] + debts[2]); - assert(collaterals[0] + collaterals[1] + collaterals[2] == abi.decode(cd, (uint256))); - for (uint256 i = 1; i < ids.length; i++) { - vm.expectRevert(abi.encodePacked(bytes4(keccak256("ERC721NonexistentToken(uint256)")), ids[i])); - res.gt.loanInfo(ids[i]); - } - - vm.stopPrank(); - } - - function testMergeEmptyArray() public { - uint256[] memory ids = new uint256[](0); - vm.startPrank(sender); - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIdArrayIsEmpty.selector)); - res.gt.merge(ids); - vm.stopPrank(); - } - - function testRevertByCanNotMergeLoanWithDiffOwnerWhenMerge() public { - uint40[3] memory debts = [100e8, 30e8, 5e8]; - uint64[3] memory collaterals = [1e18, 0.5e18, 0.005e18]; - - vm.startPrank(sender); - - uint256[] memory ids = new uint256[](3); - for (uint256 i = 0; i < ids.length; ++i) { - (ids[i],) = LoanUtils.fastMintGt(res, sender, debts[i], collaterals[i]); - } - vm.stopPrank(); - address other = vm.randomAddress(); - vm.prank(other); - vm.expectRevert(abi.encodeWithSignature("AuthorizationFailed(uint256,address)", ids[0], other)); - res.gt.merge(ids); - } - - function testMergeDuplicateId() public { - uint40[2] memory debts = [100e8, 30e8]; - uint64[2] memory collaterals = [1e18, 0.5e18]; - - vm.startPrank(sender); - - uint256[] memory ids = new uint256[](2); - for (uint256 i = 0; i < ids.length; ++i) { - (ids[i],) = LoanUtils.fastMintGt(res, sender, debts[i], collaterals[i]); - } - - // Create array with duplicate IDs - uint256[] memory duplicateIds = new uint256[](3); - duplicateIds[0] = ids[0]; - duplicateIds[1] = ids[1]; - duplicateIds[2] = ids[0]; // Duplicate of first ID - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.DuplicateIdInMerge.selector, ids[0])); - res.gt.merge(duplicateIds); - - vm.stopPrank(); - } - - function testAddCollateral() public { - uint128 debtAmt = 1700e8; - uint256 collateralAmt = 1e18; - uint256 addedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - // Add collateral by third address - address thirdPeople = vm.randomAddress(); - res.collateral.mint(thirdPeople, addedCollateral); - vm.startPrank(thirdPeople); - - res.collateral.approve(address(res.gt), addedCollateral); - - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - vm.expectEmit(); - emit GearingTokenEvents.AddCollateral(gtId, abi.encode(collateralAmt + addedCollateral)); - res.gt.addCollateral(gtId, abi.encode(addedCollateral)); - - state.collateralReserve += addedCollateral; - StateChecker.checkMarketState(res, state); - assert(res.debt.balanceOf(thirdPeople) == 0); - assert(res.collateral.balanceOf(thirdPeople) == 0); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assert(owner == sender); - assert(d == debtAmt); - assert(collateralAmt + addedCollateral == abi.decode(cd, (uint256))); - - // Add collateral by self - vm.startPrank(sender); - - res.collateral.mint(sender, addedCollateral); - res.collateral.approve(address(res.gt), addedCollateral); - - res.gt.addCollateral(gtId, abi.encode(addedCollateral)); - vm.stopPrank(); - } - - function testRevertByGtIsExpiredWhenAddCollateral() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint256 addedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - vm.stopPrank(); - - address thirdPeople = vm.randomAddress(); - vm.warp(marketConfig.maturity); - res.collateral.mint(thirdPeople, addedCollateral); - - vm.startPrank(thirdPeople); - res.collateral.approve(address(res.gt), addedCollateral); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIsExpired.selector)); - - res.gt.addCollateral(gtId, abi.encode(addedCollateral)); - vm.stopPrank(); - } - - function testRemoveCollateral() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - vm.expectRevert(GearingTokenErrorsV2.CannotRemoveCollateralWithDebt.selector); - res.gt.removeCollateral(gtId, abi.encode(removedCollateral)); - - vm.stopPrank(); - } - - function testRemoveCollateralZeroDebt(uint256 removedCollateral) public { - uint256 collateralAmt = 1e18; - uint128 debtAmt = 0; - vm.assume(removedCollateral > 0 && removedCollateral <= collateralAmt); - - vm.startPrank(sender); - res.collateral.mint(sender, collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - res.collateral.approve(address(res.gt), collateralAmt); - (uint256 gtId,) = res.market.issueFt(sender, debtAmt, collateralData); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - vm.expectEmit(); - emit GearingTokenEvents.RemoveCollateral(gtId, abi.encode(collateralAmt - removedCollateral)); - res.gt.removeCollateral(gtId, abi.encode(removedCollateral)); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - state.collateralReserve -= removedCollateral; - StateChecker.checkMarketState(res, state); - - assertEq( - collateralBalanceAfter - collateralBalanceBefore, - removedCollateral, - "sender should receive removed collateral" - ); - - (address owner, uint128 currentDebt, bytes memory currentCollateral) = res.gt.loanInfo(gtId); - assertEq(owner, sender, "owner should remain sender"); - assertEq(currentDebt, 0, "debt should remain zero"); - assertEq( - abi.decode(currentCollateral, (uint256)), - collateralAmt - removedCollateral, - "collateral should be reduced by removed amount" - ); - - vm.stopPrank(); - } - - function testRevertByCallerIsNotTheOwnerWhenRemoveCollateral() public { - // debt 1780 USD collaretal 2200USD - uint128 debtAmt = 1780e8; - uint256 collateralAmt = 1.1e18; - uint256 removedCollateral = 0.1e18; - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - - address thirdPeople = vm.randomAddress(); - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrors.AuthorizationFailed.selector, gtId, thirdPeople)); - vm.prank(thirdPeople); - res.gt.removeCollateral(gtId, abi.encode(removedCollateral)); - } - - function testRevertByGtIsExpiredWhenRemoveCollateral() public { - // debt 200 USD collaretal 2200USD - uint128 debtAmt = 200e8; - uint256 collateralAmt = 1.1e18; - uint256 removedCollateral = 0.1e18; - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - vm.stopPrank(); - - vm.warp(marketConfig.maturity); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIsExpired.selector)); - vm.prank(sender); - res.gt.removeCollateral(gtId, abi.encode(removedCollateral)); - } - - function testLiquidate() public { - uint128 debtAmt = 1000e8; - uint256 collateralAmt = 1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - vm.startPrank(deployer); - // update oracle - res.collateralOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_1000_DAI_1.eth")); - res.debtOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_1000_DAI_1.dai")); - vm.stopPrank(); - address liquidator = vm.randomAddress(); - vm.startPrank(liquidator); - - res.debt.mint(liquidator, debtAmt); - res.debt.approve(address(res.gt), debtAmt); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrors.GtDoNotSupportLiquidation.selector)); - res.gt.liquidate(gtId, debtAmt, true); - - vm.stopPrank(); - } - - function testLiquidatable() public { - uint128 debtAmt = 10000e8; - uint256 collateralAmt = 10e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - vm.startPrank(deployer); - // update oracle - res.collateralOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_1000_DAI_1.eth")); - res.debtOracle.updateRoundData(JSONLoader.getRoundDataFromJson(testdata, ".priceData.ETH_1000_DAI_1.dai")); - vm.stopPrank(); - - vm.warp(marketConfig.maturity - 1); - (bool isLiquidable,, uint128 maxRepayAmt) = res.gt.getLiquidationInfo(gtId); - assert(!isLiquidable); - assert(maxRepayAmt == 0); - - vm.warp(marketConfig.maturity); - (isLiquidable,, maxRepayAmt) = res.gt.getLiquidationInfo(gtId); - assert(!isLiquidable); - assert(maxRepayAmt == 0); - - vm.warp(marketConfig.maturity + Constants.LIQUIDATION_WINDOW); - (isLiquidable,, maxRepayAmt) = res.gt.getLiquidationInfo(gtId); - assert(!isLiquidable); - assert(maxRepayAmt == 0); - } - - function testAugmentGt(uint128 debtAmt, uint128 debtAmt2) public { - uint256 collateralAmt = 1e18; - vm.assume(debtAmt <= 1000e8); - vm.assume(debtAmt2 <= 600e8); - vm.startPrank(sender); - res.collateral.mint(sender, collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - res.collateral.approve(address(res.gt), collateralAmt); - (uint256 gtId,) = res.market.issueFt(sender, debtAmt, collateralData); - vm.expectRevert(GearingTokenErrorsV2.CannotAugmentDebtOnOnlyDeliveryGt.selector); - res.market.issueFtByExistedGt(sender, debtAmt2, gtId); - vm.stopPrank(); - } - - function testRepayZeroDebt() public { - uint256 collateralAmt = 1e18; - uint128 debtAmt = 0; - vm.startPrank(sender); - res.collateral.mint(sender, collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - res.collateral.approve(address(res.gt), collateralAmt); - (uint256 gtId,) = res.market.issueFt(sender, debtAmt, collateralData); - - res.gt.repay(gtId, 0, true); - assertEq(res.collateral.balanceOf(sender), collateralAmt); - vm.stopPrank(); - } - - function testRepayAndRemoveCollateral() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 50e8; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, repayAmt); - res.debt.approve(address(res.gt), repayAmt); - bool byDebtToken = true; - vm.expectRevert(GearingTokenErrorsV2.OnlyFullRepaySupported.selector); - GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, sender, abi.encode(removedCollateral) - ); - - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralFullRepay(uint256 removedAmt) public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - vm.assume(removedAmt <= collateralAmt); - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, debtAmt); - res.debt.approve(address(res.gt), debtAmt); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - uint256 debtBalanceBefore = res.debt.balanceOf(sender); - - bool byDebtToken = true; - vm.expectEmit(); - emit GearingTokenEventsV2.RepayAndRemoveCollateral(gtId, debtAmt, byDebtToken, abi.encode(removedAmt)); - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, debtAmt, byDebtToken, sender, abi.encode(removedAmt) - ); - - assertTrue(repayAll, "should repay all"); - assertEq(finalRepayAmt, debtAmt, "final repay amount should match debt amount"); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 debtBalanceAfter = res.debt.balanceOf(sender); - - assertEq(collateralBalanceAfter - collateralBalanceBefore, removedAmt, "sender should receive all collateral"); - assertEq(debtBalanceAfter + debtAmt, debtBalanceBefore, "sender debt balance should decrease by debt amount"); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assertEq(owner, sender, "owner should remain sender"); - assertEq(d, 0, "debt should be fully repaid"); - assertEq( - collateralAmt - removedAmt, abi.decode(cd, (uint256)), "collateral should be reduced by removed amount" - ); - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralByFt() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 100e8; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - // get FT token - uint128 debtAmtInForBuyFt = 100e8; - uint128 minFTOut = 0e8; - res.debt.mint(sender, debtAmtInForBuyFt); - res.debt.approve(address(res.order), debtAmtInForBuyFt); - res.order.swapExactTokenToToken( - res.debt, res.ft, sender, debtAmtInForBuyFt, minFTOut, block.timestamp + 1 hours - ); - - res.ft.approve(address(res.gt), repayAmt); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - uint256 ftBalanceBefore = res.ft.balanceOf(sender); - uint256 ftInMarketBefore = res.ft.balanceOf(address(res.market)); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - bool byDebtToken = false; - vm.expectEmit(); - emit GearingTokenEventsV2.RepayAndRemoveCollateral(gtId, repayAmt, byDebtToken, abi.encode(removedCollateral)); - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, sender, abi.encode(removedCollateral) - ); - - assertTrue(repayAll, "should repay all"); - assertEq(finalRepayAmt, repayAmt, "final repay amount should match"); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 ftBalanceAfter = res.ft.balanceOf(sender); - uint256 ftInMarketAfter = res.ft.balanceOf(address(res.market)); - state.collateralReserve -= removedCollateral; - StateChecker.checkMarketState(res, state); - - assertEq(ftInMarketAfter - repayAmt, ftInMarketBefore, "FT should be transferred to market"); - assertEq( - collateralBalanceAfter - collateralBalanceBefore, - removedCollateral, - "sender should receive removed collateral" - ); - assertEq(ftBalanceAfter + repayAmt, ftBalanceBefore, "sender FT balance should decrease by repay amount"); - - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralWithThirdPartyRecipient() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = debtAmt; - uint256 removedCollateral = 0.1e18; - address collateralRecipient = vm.randomAddress(); - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, repayAmt); - res.debt.approve(address(res.gt), repayAmt); - - uint256 senderCollateralBalanceBefore = res.collateral.balanceOf(sender); - uint256 recipientCollateralBalanceBefore = res.collateral.balanceOf(collateralRecipient); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - bool byDebtToken = true; - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, collateralRecipient, abi.encode(removedCollateral) - ); - - assertTrue(repayAll, "should repay all"); - assertEq(finalRepayAmt, repayAmt, "final repay amount should match"); - - uint256 senderCollateralBalanceAfter = res.collateral.balanceOf(sender); - uint256 recipientCollateralBalanceAfter = res.collateral.balanceOf(collateralRecipient); - state.debtReserve += repayAmt; - state.collateralReserve -= removedCollateral; - StateChecker.checkMarketState(res, state); - - assertEq( - senderCollateralBalanceAfter, senderCollateralBalanceBefore, "sender collateral balance should not change" - ); - assertEq( - recipientCollateralBalanceAfter - recipientCollateralBalanceBefore, - removedCollateral, - "recipient should receive removed collateral" - ); - - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralExceedsMaxRepayAmt() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 150e8; // More than debt amount - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, repayAmt); - res.debt.approve(address(res.gt), repayAmt); - - uint256 debtBalanceBefore = res.debt.balanceOf(sender); - - bool byDebtToken = true; - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, sender, abi.encode(removedCollateral) - ); - - assertTrue(repayAll, "should repay all when repay amount exceeds debt"); - assertEq(finalRepayAmt, debtAmt, "final repay amount should be capped at debt amount"); - assertEq( - res.debt.balanceOf(sender), - debtBalanceBefore - debtAmt, - "sender debt balance should decrease by actual debt amount" - ); - - vm.stopPrank(); - } - - function testRevertByCallerIsNotTheOwnerWhenRepayAndRemoveCollateral() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 50e8; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - vm.stopPrank(); - - address thirdPeople = vm.randomAddress(); - res.debt.mint(thirdPeople, repayAmt); - - vm.startPrank(thirdPeople); - res.debt.approve(address(res.gt), repayAmt); - - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrors.AuthorizationFailed.selector, gtId, thirdPeople)); - GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, true, thirdPeople, abi.encode(removedCollateral) - ); - - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralZeroRemoval() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 100e8; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, repayAmt); - res.debt.approve(address(res.gt), repayAmt); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - bool byDebtToken = true; - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, sender, abi.encode(0) - ); - - assertTrue(repayAll, "should repay all"); - assertEq(finalRepayAmt, repayAmt, "final repay amount should match"); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - state.debtReserve += repayAmt; - StateChecker.checkMarketState(res, state); - - assertEq( - collateralBalanceAfter, - collateralBalanceBefore, - "sender collateral balance should not change when removing zero" - ); - - (address owner, uint128 d, bytes memory cd) = res.gt.loanInfo(gtId); - assertEq(owner, sender, "owner should remain sender"); - assertEq(d, debtAmt - repayAmt, "debt should be reduced by repay amount"); - assertEq(collateralAmt, abi.decode(cd, (uint256)), "collateral should remain unchanged"); - - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralZeroDebt() public { - uint256 collateralAmt = 1e18; - uint128 debtAmt = 0; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - res.collateral.mint(sender, collateralAmt); - bytes memory collateralData = abi.encode(collateralAmt); - res.collateral.approve(address(res.gt), collateralAmt); - (uint256 gtId,) = res.market.issueFt(sender, debtAmt, collateralData); - - uint256 collateralBalanceBefore = res.collateral.balanceOf(sender); - StateChecker.MarketState memory state = StateChecker.getMarketState(res); - - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, 0, true, sender, abi.encode(removedCollateral) - ); - - assertTrue(repayAll, "should repay all when debt is zero"); - assertEq(finalRepayAmt, 0, "final repay amount should be zero"); - - uint256 collateralBalanceAfter = res.collateral.balanceOf(sender); - state.collateralReserve -= removedCollateral; - StateChecker.checkMarketState(res, state); - - assertEq( - collateralBalanceAfter - collateralBalanceBefore, - removedCollateral, - "sender should receive removed collateral" - ); - - (address owner, uint128 currentDebt, bytes memory currentCollateral) = res.gt.loanInfo(gtId); - assertEq(owner, sender, "owner should remain sender"); - assertEq(currentDebt, 0, "debt should remain zero"); - assertEq( - abi.decode(currentCollateral, (uint256)), collateralAmt - removedCollateral, "collateral should be reduced" - ); - vm.stopPrank(); - } - - function testRepayAndRemoveCollateralAfterMaturity() public { - uint128 debtAmt = 100e8; - uint256 collateralAmt = 1e18; - uint128 repayAmt = 50e8; - uint256 removedCollateral = 0.1e18; - - vm.startPrank(sender); - - (uint256 gtId,) = LoanUtils.fastMintGt(res, sender, debtAmt, collateralAmt); - - res.debt.mint(sender, repayAmt); - res.debt.approve(address(res.gt), repayAmt); - - vm.warp(marketConfig.maturity + 1); - - bool byDebtToken = true; - vm.expectRevert(abi.encodeWithSelector(GearingTokenErrorsV2.GtIsExpired.selector)); - (bool repayAll, uint128 finalRepayAmt) = GearingTokenWithERC20V2(address(res.gt)).repayAndRemoveCollateral( - gtId, repayAmt, byDebtToken, sender, abi.encode(removedCollateral) - ); - vm.stopPrank(); - } -} diff --git a/test/v2/RouterV2.t.sol b/test/v2/RouterV2.t.sol index 3e7d1617..ba5e23e3 100644 --- a/test/v2/RouterV2.t.sol +++ b/test/v2/RouterV2.t.sol @@ -131,7 +131,7 @@ contract RouterTestV2 is Test { res.ft.transfer(address(res.order), amount); res.xt.transfer(address(res.order), amount); - res.router = DeployUtils.deployRouter(deployer, res.whitelistManager); + res.router = DeployUtils.deployRouter(deployer, address(res.whitelistManager)); adapter = new MockSwapAdapterV2(pool); termMaxSwapAdapter = new TermMaxSwapAdapter(address(res.whitelistManager)); diff --git a/test/v2/VaultV2.t.sol b/test/v2/VaultV2.t.sol index 290efa9d..03e3caed 100644 --- a/test/v2/VaultV2.t.sol +++ b/test/v2/VaultV2.t.sol @@ -98,7 +98,8 @@ contract VaultTestV2 is Test { vm.label(address(res.market), "market"); MarketConfig memory marketConfig2 = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); marketConfig2.maturity = uint64(currentTime + 180 days); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer, res.whitelistManager); + TermMaxFactoryV2 factory = + DeployUtils.deployMarketFactory(address(res.accessManager), address(res.whitelistManager)); market2 = TermMaxMarketV2( factory.createMarket( DeployUtils.GT_ERC20, @@ -143,7 +144,7 @@ contract VaultTestV2 is Test { 0 ); - vault = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); + vault = DeployUtils.deployVault(res.vaultFactory, initialParams); vm.startPrank(deployer); vm.label(address(vault), "vault"); @@ -241,16 +242,22 @@ contract VaultTestV2 is Test { vm.stopPrank(); } + function _setWhitelist(address c, IWhitelistManager.ContractModule module, bool isWhitelist) internal { + address[] memory targets = new address[](1); + targets[0] = c; + res.whitelistManager.batchSetWhitelist(targets, module, isWhitelist); + } + function testMarketWhitelist() public { // check current timelock value assertEq(vault.timelock(), 86400); + res.accessManager.grantRole(res.accessManager.WHITELIST_ROLE(), curator); + // submit market vm.startPrank(curator); address market = address(0x123); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - market, IWhitelistManager.ContractModule.MARKET, true - ); + _setWhitelist(market, IWhitelistManager.ContractModule.MARKET, true); vault.submitMarket(market, false); assertEq(vault.marketWhitelist(market), false); @@ -266,18 +273,14 @@ contract VaultTestV2 is Test { vault.acceptMarket(market); assertEq(vault.marketWhitelist(market), true); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - market, IWhitelistManager.ContractModule.MARKET, false - ); + _setWhitelist(market, IWhitelistManager.ContractModule.MARKET, false); vault.submitMarket(market, false); assertEq(vault.marketWhitelist(market), false); vm.stopPrank(); // Test revoke market address newMarket = address(0x456); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newMarket, IWhitelistManager.ContractModule.MARKET, true - ); + _setWhitelist(newMarket, IWhitelistManager.ContractModule.MARKET, true); vm.prank(curator); vault.submitMarket(newMarket, true); @@ -289,6 +292,8 @@ contract VaultTestV2 is Test { function test_RevertSetMarketWhitelist() public { address market = address(0x123); + res.accessManager.grantRole(res.accessManager.WHITELIST_ROLE(), curator); + vm.prank(vm.randomAddress()); vm.expectRevert(VaultErrors.NotCuratorRole.selector); @@ -298,9 +303,7 @@ contract VaultTestV2 is Test { vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); vault.submitMarket(market, true); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - market, IWhitelistManager.ContractModule.MARKET, true - ); + _setWhitelist(market, IWhitelistManager.ContractModule.MARKET, true); vault.submitMarket(market, true); vm.expectRevert(VaultErrors.AlreadyPending.selector); @@ -490,7 +493,7 @@ contract VaultTestV2 is Test { function testDepositWhenNoOrders() public { initialParams.name = "Vault-DAI2"; initialParams.symbol = "Vault-DAI2"; - TermMaxVaultV2 vault2 = DeployUtils.deployVault(deployer, initialParams); + TermMaxVaultV2 vault2 = DeployUtils.deployVault(res.vaultFactory, initialParams); vm.startPrank(deployer); uint256 amount = 10000e8; res.debt.mint(deployer, amount); diff --git a/test/v2/VaultV2WithPool.t.sol b/test/v2/VaultV2WithPool.t.sol index 2a034df0..702979aa 100644 --- a/test/v2/VaultV2WithPool.t.sol +++ b/test/v2/VaultV2WithPool.t.sol @@ -100,14 +100,14 @@ contract VaultV2WithPoolTest is Test { vm.label(address(res.market), "market"); pool = new MockERC4626(res.debt); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - address(pool), IWhitelistManager.ContractModule.POOL, true - ); + _setWhitelist(address(pool), IWhitelistManager.ContractModule.POOL, true); + vm.label(address(pool), "pool"); { MarketConfig memory marketConfig2 = JSONLoader.getMarketConfigFromJson(treasurer, testdata, ".marketConfig"); marketConfig2.maturity = uint64(currentTime + 180 days); - TermMaxFactoryV2 factory = DeployUtils.deployFactory(deployer, res.whitelistManager); + TermMaxFactoryV2 factory = + DeployUtils.deployMarketFactory(address(res.accessManager), address(res.whitelistManager)); market2 = TermMaxMarketV2( factory.createMarket( DeployUtils.GT_ERC20, @@ -154,7 +154,7 @@ contract VaultV2WithPoolTest is Test { 0 ); - vault = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); + vault = DeployUtils.deployVault(res.vaultFactory, initialParams); vm.startPrank(deployer); vm.label(address(vault), "vault"); @@ -189,9 +189,17 @@ contract VaultV2WithPoolTest is Test { res.debt.mint(deployer, 10000e18); res.debt.approve(address(res.market), 10000e18); res.market.mint(deployer, 10000e18); + + res.accessManager.grantRole(res.accessManager.WHITELIST_ROLE(), curator); vm.stopPrank(); } + function _setWhitelist(address c, IWhitelistManager.ContractModule module, bool isWhitelist) internal { + address[] memory targets = new address[](1); + targets[0] = c; + res.whitelistManager.batchSetWhitelist(targets, module, isWhitelist); + } + function testDeposit() public { vm.warp(currentTime + 2 days); buyXt(48.219178e8, 1000e8); @@ -212,7 +220,7 @@ contract VaultV2WithPoolTest is Test { function testDepositWhenNoOrders() public { initialParams.name = "Vault-DAI2"; initialParams.symbol = "Vault-DAI2"; - TermMaxVaultV2 vault2 = DeployUtils.deployVault(deployer, initialParams, res.whitelistManager); + TermMaxVaultV2 vault2 = DeployUtils.deployVault(res.vaultFactory, initialParams); vm.startPrank(deployer); uint256 amount = 10000e8; res.debt.mint(deployer, amount); @@ -597,9 +605,8 @@ contract VaultV2WithPoolTest is Test { MockERC4626 newPool = new MockERC4626(res.debt); address newPoolAddress = address(newPool); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(curator); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, true); // Test unauthorized access vm.prank(vm.randomAddress()); @@ -624,9 +631,8 @@ contract VaultV2WithPoolTest is Test { // Test submitting another pool while one is pending should revert MockERC4626 anotherPool = new MockERC4626(res.debt); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - address(anotherPool), IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(curator); + _setWhitelist(address(anotherPool), IWhitelistManager.ContractModule.POOL, true); vm.prank(curator); vm.expectRevert(VaultErrors.AlreadyPending.selector); vaultV2.submitPendingPool(address(anotherPool)); @@ -639,9 +645,8 @@ contract VaultV2WithPoolTest is Test { MockERC4626 newPool = new MockERC4626(res.debt); address newPoolAddress = address(newPool); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(curator); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, true); // Submit pending pool vm.prank(curator); @@ -654,16 +659,14 @@ contract VaultV2WithPoolTest is Test { // Move time forward past timelock vm.warp(currentTime + timelock + 1); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, false - ); + vm.prank(curator); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, false); vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); vaultV2.acceptPool(); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(curator); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, true); // Get initial balances uint256 oldPoolBalance = pool.balanceOf(address(vault)); @@ -699,9 +702,7 @@ contract VaultV2WithPoolTest is Test { vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); vaultV2.submitPendingPool(newPoolAddress); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - newPoolAddress, IWhitelistManager.ContractModule.POOL, true - ); + _setWhitelist(newPoolAddress, IWhitelistManager.ContractModule.POOL, true); vaultV2.submitPendingPool(newPoolAddress); vm.stopPrank(); @@ -759,9 +760,8 @@ contract VaultV2WithPoolTest is Test { // Create a new pool MockERC4626 newPool = new MockERC4626(res.debt); - MockWhitelistManager(address(res.whitelistManager)).setWhitelist( - address(newPool), IWhitelistManager.ContractModule.POOL, true - ); + vm.prank(curator); + _setWhitelist(address(newPool), IWhitelistManager.ContractModule.POOL, true); // Test that only curator can submit vm.prank(guardian); diff --git a/test/v2/integration/ForkKodiakSwapAdapter.t.sol b/test/v2/integration/ForkKodiakSwapAdapter.t.sol index efea69e1..3d9c0c4a 100644 --- a/test/v2/integration/ForkKodiakSwapAdapter.t.sol +++ b/test/v2/integration/ForkKodiakSwapAdapter.t.sol @@ -27,6 +27,7 @@ import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "contracts/v2/router/TermMaxRouterV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {KodiakSwapAdapter, IKodiakRouter} from "contracts/v2/router/swapAdapters/KodiakSwapAdapter.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkKodiakSwapAdapter is ForkBaseTestV2 { @@ -61,12 +62,13 @@ contract ForkKodiakSwapAdapter is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(kodiakSwapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); } diff --git a/test/v2/integration/ForkOkxSwapAdapterV2.t.sol b/test/v2/integration/ForkOkxSwapAdapterV2.t.sol index 6707f7c1..753bc93f 100644 --- a/test/v2/integration/ForkOkxSwapAdapterV2.t.sol +++ b/test/v2/integration/ForkOkxSwapAdapterV2.t.sol @@ -27,6 +27,7 @@ import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "contracts/v2/router/TermMaxRouterV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {OkxSwapAdapter} from "contracts/v2/router/swapAdapters/OkxSwapAdapter.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkOkxSwapAdapterV2 is ForkBaseTestV2 { @@ -66,13 +67,15 @@ contract ForkOkxSwapAdapterV2 is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(okxSwapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); + // prepare swap data data = abi.encode(okxRouter, okxApprovalAddress, data); } diff --git a/test/v2/integration/ForkOneInchSwapAdapter.t.sol b/test/v2/integration/ForkOneInchSwapAdapter.t.sol index a8b0d2cb..cd12438a 100644 --- a/test/v2/integration/ForkOneInchSwapAdapter.t.sol +++ b/test/v2/integration/ForkOneInchSwapAdapter.t.sol @@ -27,6 +27,7 @@ import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "contracts/v2/router/TermMaxRouterV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {OneInchSwapAdapter, IOneInchRouter} from "contracts/v2/router/swapAdapters/OneInchSwapAdapter.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkOneInchSwapAdapter is ForkBaseTestV2 { @@ -66,12 +67,13 @@ contract ForkOneInchSwapAdapter is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(swapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); desc = IOneInchRouter.SwapDescription({ diff --git a/test/v2/integration/ForkPancakeAdapterV2.t.sol b/test/v2/integration/ForkPancakeAdapterV2.t.sol index f6481fa5..f8ec8b7d 100644 --- a/test/v2/integration/ForkPancakeAdapterV2.t.sol +++ b/test/v2/integration/ForkPancakeAdapterV2.t.sol @@ -28,6 +28,7 @@ import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "co import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {UniswapV3AdapterV2} from "contracts/v2/router/swapAdapters/UniswapV3AdapterV2.sol"; import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkPancakeAdapterV2 is ForkBaseTestV2 { @@ -61,12 +62,13 @@ contract ForkPancakeAdapterV2 is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(uniswapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); } diff --git a/test/v2/integration/ForkPancakeSmartAdapter.t.sol b/test/v2/integration/ForkPancakeSmartAdapter.t.sol index cd0b270a..cf933d2b 100644 --- a/test/v2/integration/ForkPancakeSmartAdapter.t.sol +++ b/test/v2/integration/ForkPancakeSmartAdapter.t.sol @@ -28,6 +28,7 @@ import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "co import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {PancakeSmartAdapter} from "contracts/v2/router/swapAdapters/PancakeSmartAdapter.sol"; import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkPancakeSmartAdapter is ForkBaseTestV2 { @@ -58,14 +59,13 @@ contract ForkPancakeSmartAdapter is ForkBaseTestV2 { vm.label(USDT, "USDT"); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); - console.log("router", address(router)); - console.log("whitelistManager", address(whitelistManager)); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(pancakeSmartAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); } diff --git a/test/v2/integration/ForkPrdFlashRepay.t.sol b/test/v2/integration/ForkPrdFlashRepay.t.sol index c950a91a..0f07b024 100644 --- a/test/v2/integration/ForkPrdFlashRepay.t.sol +++ b/test/v2/integration/ForkPrdFlashRepay.t.sol @@ -26,6 +26,7 @@ import { import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "contracts/v2/router/TermMaxRouterV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; interface TestOracle is IOracle { @@ -110,13 +111,15 @@ contract ForkPrdFlashRepay is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](2); adapters[0] = pendleAdapter; adapters[1] = odosAdapter; - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); } @@ -218,13 +221,7 @@ contract ForkPrdFlashRepay is ForkBaseTestV2 { address borrower; address admin = vm.randomAddress(); - vm.startPrank(admin); - (TermMaxRouterV2 router2, IWhitelistManager whitelistManager) = deployRouter(admin); - address[] memory adapters = new address[](2); - adapters[0] = pendleAdapter; - adapters[1] = odosAdapter; - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); - vm.stopPrank(); + TermMaxRouterV2 router2 = DeployUtils.deployRouter(admin, address(router.whitelistManager())); uint128 debt; uint256 collateralAmount; diff --git a/test/v2/integration/ForkPrdRollOver.t.sol b/test/v2/integration/ForkPrdRollOver.t.sol index 09d3211b..552d5213 100644 --- a/test/v2/integration/ForkPrdRollOver.t.sol +++ b/test/v2/integration/ForkPrdRollOver.t.sol @@ -32,6 +32,7 @@ import { import {TermMaxSwapData, TermMaxSwapAdapter} from "contracts/v2/router/swapAdapters/TermMaxSwapAdapter.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {console} from "forge-std/console.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {RouterErrorsV2} from "contracts/v2/errors/RouterErrorsV2.sol"; interface TestOracle is IOracle { @@ -118,10 +119,10 @@ contract ForkPrdRollover is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); + router = res.router; - TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(whitelistManager)); + TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(res.whitelistManager)); tmxAdapter = address(tmx); vm.label(tmxAdapter, "TermMaxAdapter"); @@ -129,12 +130,12 @@ contract ForkPrdRollover is ForkBaseTestV2 { adapters[0] = pendleAdapter; adapters[1] = odosAdapter; adapters[2] = tmxAdapter; - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); address[] memory callbacks = new address[](2); callbacks[0] = address(ITermMaxOrder(o_may_30).orderConfig().swapTrigger); callbacks[1] = address(ITermMaxOrder(o_aug_1).orderConfig().swapTrigger); - whitelistManager.batchSetWhitelist(callbacks, IWhitelistManager.ContractModule.ORDER_CALLBACK, true); + res.whitelistManager.batchSetWhitelist(callbacks, IWhitelistManager.ContractModule.ORDER_CALLBACK, true); vm.stopPrank(); } diff --git a/test/v2/integration/ForkPrdRollOverToThird.t.sol b/test/v2/integration/ForkPrdRollOverToThird.t.sol index cfa5f104..08bf62dd 100644 --- a/test/v2/integration/ForkPrdRollOverToThird.t.sol +++ b/test/v2/integration/ForkPrdRollOverToThird.t.sol @@ -36,6 +36,7 @@ import {IAaveV3Pool} from "contracts/v2/extensions/aave/IAaveV3Pool.sol"; import {ICreditDelegationToken} from "contracts/v2/extensions/aave/ICreditDelegationToken.sol"; import {IMorpho, Id, MarketParams, Authorization, Signature} from "contracts/v2/extensions/morpho/IMorpho.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; interface TestOracle is IOracle { function acceptPendingOracle(address asset) external; @@ -100,10 +101,10 @@ contract ForkPrdRollOverToThird is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); + router = res.router; - TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(whitelistManager)); + TermMaxSwapAdapter tmx = new TermMaxSwapAdapter(address(res.whitelistManager)); tmxAdapter = address(tmx); vm.label(tmxAdapter, "TermMaxAdapter"); @@ -112,7 +113,7 @@ contract ForkPrdRollOverToThird is ForkBaseTestV2 { adapters[1] = odosAdapter; adapters[2] = tmxAdapter; adapters[3] = vaultAdapter; - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); vm.stopPrank(); IAaveV3Pool.ReserveData memory rd = IAaveV3Pool(address(aave)).getReserveData(usdc); diff --git a/test/v2/integration/ForkStrataVaultAdapter.t.sol b/test/v2/integration/ForkStrataVaultAdapter.t.sol index 57f01d9c..7482943d 100644 --- a/test/v2/integration/ForkStrataVaultAdapter.t.sol +++ b/test/v2/integration/ForkStrataVaultAdapter.t.sol @@ -29,6 +29,7 @@ import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; import {StrataVaultAdapter} from "contracts/v2/router/swapAdapters/StrataVaultAdapter.sol"; import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkStrataVaultAdapter is ForkBaseTestV2 { @@ -61,12 +62,13 @@ contract ForkStrataVaultAdapter is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(strataAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + + router = res.router; vm.stopPrank(); } diff --git a/test/v2/integration/ForkTerminal.t.sol b/test/v2/integration/ForkTerminal.t.sol index 0c35a70a..4e56831c 100644 --- a/test/v2/integration/ForkTerminal.t.sol +++ b/test/v2/integration/ForkTerminal.t.sol @@ -28,6 +28,7 @@ import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "co import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {TerminalVaultAdapter} from "contracts/v2/router/swapAdapters/TerminalVaultAdapter.sol"; import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkTerminalTest is ForkBaseTestV2 { @@ -71,12 +72,12 @@ contract ForkTerminalTest is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(terminalAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + router = res.router; vm.stopPrank(); } diff --git a/test/v2/integration/ForkUniswapAdapterV2.t.sol b/test/v2/integration/ForkUniswapAdapterV2.t.sol index 7ec9fbae..7354dcac 100644 --- a/test/v2/integration/ForkUniswapAdapterV2.t.sol +++ b/test/v2/integration/ForkUniswapAdapterV2.t.sol @@ -28,6 +28,7 @@ import {ITermMaxRouterV2, TermMaxRouterV2, SwapPath, FlashRepayOptions} from "co import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {UniswapV3AdapterV2} from "contracts/v2/router/swapAdapters/UniswapV3AdapterV2.sol"; import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {DeployUtils} from "test/v2/utils/DeployUtils.sol"; import {console} from "forge-std/console.sol"; contract ForkUniswapAdapterV2 is ForkBaseTestV2 { @@ -61,12 +62,12 @@ contract ForkUniswapAdapterV2 is ForkBaseTestV2 { address admin = vm.randomAddress(); vm.startPrank(admin); - IWhitelistManager whitelistManager; - (router, whitelistManager) = deployRouter(admin); + DeployUtils.Res memory res = DeployUtils.deployRes(admin); address[] memory adapters = new address[](1); adapters[0] = address(uniswapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + res.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + router = res.router; vm.stopPrank(); } diff --git a/test/v2/invariant/TermMaxVaultV2Invariant.t.sol b/test/v2/invariant/TermMaxVaultV2Invariant.t.sol index b29f93fc..d317cb79 100644 --- a/test/v2/invariant/TermMaxVaultV2Invariant.t.sol +++ b/test/v2/invariant/TermMaxVaultV2Invariant.t.sol @@ -590,7 +590,7 @@ contract TermMaxVaultV2InvariantTest is StdInvariant, Test { }); // Use DeployUtils to properly create the vault - vault = DeployUtils.deployVault(owner, vaultParams); + vault = DeployUtils.deployVault(res.vaultFactory, vaultParams); // Setup initial liquidity by depositing assets uint256 initialAmount = 100_000e18; diff --git a/test/v2/mainnet-fork/ForkBaseTestV2.sol b/test/v2/mainnet-fork/ForkBaseTestV2.sol index 2070d9fb..d3937801 100644 --- a/test/v2/mainnet-fork/ForkBaseTestV2.sol +++ b/test/v2/mainnet-fork/ForkBaseTestV2.sol @@ -141,56 +141,7 @@ abstract contract ForkBaseTestV2 is Test { priceFeed.updateRoundData(roundData); } - /// @dev Etches MockWhitelistManager bytecode onto `admin` if it has no code, - /// so the address can serve as an IWhitelistRegistry implementation. - function _etchMockWhitelistManager(address admin) internal { - if (admin.code.length == 0) { - vm.etch(admin, address(new MockWhitelistManager()).code); - } - } - - function deployFactory(address admin) public returns (TermMaxFactoryV2 factory) { - _etchMockWhitelistManager(admin); - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new TermMaxOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(admin); - factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); - } - - function deployFactoryWithMockOrder(address admin) public returns (TermMaxFactoryV2 factory) { - _etchMockWhitelistManager(admin); - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new MockOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(admin); - factory = new TermMaxFactoryV2(admin, address(m), address(whitelistManager)); - } - - function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { - _etchMockWhitelistManager(admin); - OrderManagerV2 orderManager = new OrderManagerV2(); - IWhitelistManager whitelistManager = deployWhitelistManager(admin); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = new TermMaxVaultFactoryV2(admin, address(implementation), address(whitelistManager)); - } - - function deployOracleAggregator(address admin) public returns (OracleAggregatorV2 oracle) { - oracle = new OracleAggregatorV2(admin, 0); - } - function deployMockPriceFeed(address admin) public returns (MockPriceFeed priceFeed) { priceFeed = new MockPriceFeed(admin); } - - function deployRouter(address admin) public returns (TermMaxRouterV2, IWhitelistManager) { - return DeployUtils.deployRouter(admin); - } - - function deployWhitelistManager(address admin) internal returns (IWhitelistManager whitelistManager) { - WhitelistManager implementation = new WhitelistManager(); - bytes memory data = abi.encodeCall(WhitelistManager.initialize, admin); - ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); - whitelistManager = IWhitelistManager(address(proxy)); - } } diff --git a/test/v2/mainnet-fork/GtBaseTestV2.t.sol b/test/v2/mainnet-fork/GtBaseTestV2.t.sol index 7d4c267f..b3fc7734 100644 --- a/test/v2/mainnet-fork/GtBaseTestV2.t.sol +++ b/test/v2/mainnet-fork/GtBaseTestV2.t.sol @@ -107,9 +107,10 @@ abstract contract GtBaseTestV2 is ForkBaseTestV2 { vm.startPrank(res.marketInitialParams.admin); - res.oracle = deployOracleAggregator(res.marketInitialParams.admin); - res.collateralPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); - res.debtPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); + DeployUtils.Res memory deployRes = DeployUtils.deployRes(res.marketInitialParams.admin); + res.oracle = deployRes.oracle; + res.router = deployRes.router; + res.oracle.submitPendingOracle( address(res.marketInitialParams.collateral), IOracleV2.Oracle(res.collateralPriceFeed, res.collateralPriceFeed, 0, 0, 0, 0) @@ -126,9 +127,7 @@ abstract contract GtBaseTestV2 is ForkBaseTestV2 { res.marketInitialParams.loanConfig.oracle = IOracle(address(res.oracle)); res.market = TermMaxMarketV2( - deployFactory(res.marketInitialParams.admin).createMarket( - keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0 - ) + deployRes.factory.createMarket(keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0) ); (res.ft, res.xt, res.gt,,) = res.market.tokens(); @@ -156,16 +155,15 @@ abstract contract GtBaseTestV2 is ForkBaseTestV2 { res.swapAdapters.odosAdapter = address(new OdosV2AdapterV2(vm.parseJsonAddress(jsonData, ".routers.odosRouter"))); res.swapAdapters.vaultAdapter = address(new ERC4626VaultAdapterV2()); - IWhitelistManager whitelistManager; - (res.router, whitelistManager) = deployRouter(res.marketInitialParams.admin); + address[] memory adapters = new address[](5); adapters[0] = res.swapAdapters.uniswapAdapter; adapters[1] = res.swapAdapters.pendleAdapter; adapters[2] = res.swapAdapters.odosAdapter; adapters[3] = res.swapAdapters.vaultAdapter; - res.termMaxSwapAdapter = new TermMaxSwapAdapter(address(whitelistManager)); + res.termMaxSwapAdapter = new TermMaxSwapAdapter(address(deployRes.whitelistManager)); adapters[4] = address(res.termMaxSwapAdapter); - whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); + deployRes.whitelistManager.batchSetWhitelist(adapters, IWhitelistManager.ContractModule.ADAPTER, true); res.swapData = _readSwapData(key); res.orderInitialAmount = vm.parseJsonUint(jsonData, string.concat(key, ".orderInitialAmount")); diff --git a/test/v2/mainnet-fork/MarketBaseTestV2.t.sol b/test/v2/mainnet-fork/MarketBaseTestV2.t.sol index 718f1512..0797ba14 100644 --- a/test/v2/mainnet-fork/MarketBaseTestV2.t.sol +++ b/test/v2/mainnet-fork/MarketBaseTestV2.t.sol @@ -81,7 +81,10 @@ abstract contract MarketBaseTestV2 is ForkBaseTestV2 { vm.startPrank(res.marketInitialParams.admin); - res.oracle = deployOracleAggregator(res.marketInitialParams.admin); + DeployUtils.Res memory deployRes = DeployUtils.deployRes(res.marketInitialParams.admin); + res.oracle = deployRes.oracle; + res.router = deployRes.router; + res.collateralPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); res.debtPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); res.oracle.submitPendingOracle( @@ -99,9 +102,7 @@ abstract contract MarketBaseTestV2 is ForkBaseTestV2 { res.marketInitialParams.loanConfig.oracle = IOracle(address(res.oracle)); res.market = TermMaxMarketV2( - deployFactory(res.marketInitialParams.admin).createMarket( - keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0 - ) + deployRes.factory.createMarket(keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0) ); (res.ft, res.xt, res.gt,,) = res.market.tokens(); @@ -123,8 +124,6 @@ abstract contract MarketBaseTestV2 is ForkBaseTestV2 { res.order = res.market.createOrder(res.maker, res.maxXtReserve, ISwapCallback(address(0)), res.orderConfig.curveCuts); - (res.router,) = deployRouter(res.marketInitialParams.admin); - res.orderInitialAmount = vm.parseJsonUint(jsonData, string.concat(key, ".orderInitialAmount")); deal(address(res.debtToken), res.marketInitialParams.admin, res.orderInitialAmount); diff --git a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol index f22ea2be..88fa9127 100644 --- a/test/v2/mainnet-fork/VaultBaseTestV2.t.sol +++ b/test/v2/mainnet-fork/VaultBaseTestV2.t.sol @@ -96,7 +96,9 @@ abstract contract VaultBaseTestV2 is ForkBaseTestV2 { vm.startPrank(res.marketInitialParams.admin); - res.oracle = deployOracleAggregator(res.marketInitialParams.admin); + DeployUtils.Res memory deployRes = DeployUtils.deployRes(res.marketInitialParams.admin); + res.oracle = deployRes.oracle; + res.collateralPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); res.debtPriceFeed = deployMockPriceFeed(res.marketInitialParams.admin); res.oracle.submitPendingOracle( @@ -114,9 +116,7 @@ abstract contract VaultBaseTestV2 is ForkBaseTestV2 { res.marketInitialParams.loanConfig.oracle = IOracle(address(res.oracle)); res.market = TermMaxMarketV2( - deployFactoryWithMockOrder(res.marketInitialParams.admin).createMarket( - keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0 - ) + deployRes.factory.createMarket(keccak256("GearingTokenWithERC20"), res.marketInitialParams, 0) ); (res.ft, res.xt, res.gt,,) = res.market.tokens(); @@ -135,8 +135,7 @@ abstract contract VaultBaseTestV2 is ForkBaseTestV2 { MockPriceFeed.RoundData(1, 1e8, block.timestamp, block.timestamp, 0) ); - res.vault = - ITermMaxVault(deployVaultFactory(res.marketInitialParams.admin).createVault(res.vaultInitialParams, 0)); + res.vault = ITermMaxVault(deployRes.vaultFactory.createVault(res.vaultInitialParams, 0)); res.vault.submitMarket(address(res.market), true); vm.warp(res.currentTime + res.vaultInitialParams.timelock + 1); diff --git a/test/v2/utils/DeployUtils.sol b/test/v2/utils/DeployUtils.sol index 97fabe4f..0ceb8877 100644 --- a/test/v2/utils/DeployUtils.sol +++ b/test/v2/utils/DeployUtils.sol @@ -35,8 +35,16 @@ import {VaultInitialParamsV2} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {TermMaxVaultFactoryV2} from "contracts/v2/factory/TermMaxVaultFactoryV2.sol"; import {MockAave} from "contracts/v2/test/MockAave.sol"; import {MockWhitelistManager, IWhitelistManager} from "contracts/v2/test/MockWhitelistManager.sol"; -import {OnlyDeliveryGearingToken} from "contracts/v2/tokens/OnlyDeliveryGearingToken.sol"; +import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; import {AccessManagerV2} from "contracts/v2/access/AccessManagerV2.sol"; +import { + TermMax4626Factory, + StableERC4626For4626, + StableERC4626ForAave, + VariableERC4626ForAave, + StableERC4626ForVenus, + StableERC4626ForCustomize +} from "contracts/v2/factory/TermMax4626Factory.sol"; library DeployUtils { Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); @@ -56,8 +64,10 @@ library DeployUtils { struct Res { TermMaxVaultV2 vault; - IVaultFactory vaultFactory; + AccessManagerV2 accessManager; + TermMaxVaultFactoryV2 vaultFactory; TermMaxFactoryV2 factory; + TermMax4626Factory poolFactory; TermMaxOrderV2 order; TermMaxRouterV2 router; MarketConfig marketConfig; @@ -73,23 +83,44 @@ library DeployUtils { MockERC20 debt; SwapRange swapRange; MockAave aave; - IWhitelistManager whitelistManager; + WhitelistManager whitelistManager; } - function deployMarket(address admin, MarketConfig memory marketConfig, uint32 maxLtv, uint32 liquidationLtv) - internal - returns (Res memory res) - { - res.factory = deployFactory(admin); - res.whitelistManager = res.factory.whitelistManager(); + function grantAllRoles(address to, AccessManagerV2 accessManager) internal { + accessManager.grantRole(accessManager.MARKET_ROLE(), to); + accessManager.grantRole(accessManager.ORACLE_ROLE(), to); + accessManager.grantRole(accessManager.VAULT_ROLE(), to); + accessManager.grantRole(accessManager.WHITELIST_ROLE(), to); + accessManager.grantRole(accessManager.UPGRADER_ROLE(), to); + accessManager.grantRole(accessManager.TERMMAX_MARKET_FACTORY_ROLE(), to); + accessManager.grantRole(accessManager.TERMMAX_4626_FACTORY_ROLE(), to); + accessManager.grantRole(accessManager.POOL_DEPLOYER_ROLE(), to); + accessManager.grantRole(accessManager.VAULT_DEPLOYER_ROLE(), to); + accessManager.grantRole(accessManager.PAUSER_ROLE(), to); + accessManager.grantRole(accessManager.CONFIGURATOR_ROLE(), to); + } + + function deployAccessControl(address admin) internal returns (Res memory res) { + AccessManagerV2 accessImpl = new AccessManagerV2(); + res.accessManager = AccessManagerV2( + address(new ERC1967Proxy(address(accessImpl), abi.encodeCall(AccessManager.initialize, admin))) + ); + res.accessManager.grantRole(res.accessManager.DEFAULT_ADMIN_ROLE(), address(this)); + // grant all roles to the admin + grantAllRoles(admin, res.accessManager); + grantAllRoles(address(this), res.accessManager); + res.whitelistManager = deployWhitelistManager(address(res.accessManager)); + res.oracle = deployOracle(admin, 0); + } + + function deployMockTokens(Res memory res, address admin) internal returns (Res memory) { res.collateral = new MockERC20("ETH", "ETH", 18); res.debt = new MockERC20("DAI", "DAI", 8); - res.debtOracle = new MockPriceFeed(admin); res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); + // set test prices res.oracle.submitPendingOracle( address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) ); @@ -108,66 +139,94 @@ library DeployUtils { answeredInRound: 0 }); res.collateralOracle.updateRoundData(roundData); + } - MarketInitialParams memory initialParams = MarketInitialParams({ - collateral: address(res.collateral), - debtToken: res.debt, - admin: admin, - gtImplementation: address(0), - marketConfig: marketConfig, - loanConfig: LoanConfig({ - oracle: IOracle(address(res.oracle)), - liquidationLtv: liquidationLtv, - maxLtv: maxLtv, - liquidatable: true - }), - gtInitalParams: abi.encode(type(uint256).max), - tokenName: "DAI-ETH", - tokenSymbol: "DAI-ETH" - }); - - res.marketConfig = marketConfig; - res.market = TermMaxMarketV2(res.factory.createMarket(GT_ERC20, initialParams, 0)); + function deployMarketFactory(address accessManager, address whitelistManager, address orderImplementation) + internal + returns (TermMaxFactoryV2 factory) + { + address tokenImplementation = address(new MintableERC20V2()); + TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); + // use whitelist manager do automatically set whitelist for new market + factory = new TermMaxFactoryV2(address(accessManager), address(m), whitelistManager); + // grant MARKET_ROLE to factory so it can set whitelist for new market + grantWhitelistRoleTo(accessManager, address(factory)); + } - (res.ft, res.xt, res.gt,,) = res.market.tokens(); + function deployMarketFactory(address accessManager, address whitelistManager) + internal + returns (TermMaxFactoryV2 factory) + { + return deployMarketFactory(accessManager, whitelistManager, address(new TermMaxOrderV2())); } - function deployMarket( - address admin, - AccessManagerV2 accessManager, - MarketConfig memory marketConfig, - uint32 maxLtv, - uint32 liquidationLtv, - IWhitelistManager whitelistManager - ) internal returns (Res memory res) { - res.factory = deployFactory(admin, accessManager, whitelistManager); - res.whitelistManager = whitelistManager; + function grantWhitelistRoleTo(address managerAddress, address to) internal { + AccessManagerV2 manager = AccessManagerV2(managerAddress); + manager.grantRole(manager.WHITELIST_ROLE(), to); + } - res.collateral = new MockERC20("ETH", "ETH", 18); - res.debt = new MockERC20("DAI", "DAI", 8); + function deployVaultFactory(address accessManager, address whitelistManager, address admin) + internal + returns (TermMaxVaultFactoryV2 vaultFactory) + { + OrderManagerV2 orderManager = new OrderManagerV2(); + TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), whitelistManager); + vaultFactory = + new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); + grantWhitelistRoleTo(accessManager, address(vaultFactory)); + } - res.debtOracle = new MockPriceFeed(admin); - res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); + function deployPoolFactory(address accessManager, address whitelistManager, address aave_pool) + internal + returns (TermMax4626Factory factory) + { + // deploy 4626 factory - res.oracle.submitPendingOracle( - address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) - ); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) + address stableERC4626ForAave; + address variableERC4626ForAave; + if (aave_pool != address(0)) { + stableERC4626ForAave = address(new StableERC4626ForAave(aave_pool, 0)); + variableERC4626ForAave = address(new VariableERC4626ForAave(aave_pool, 0)); + } + StableERC4626For4626 stableERC4626For4626 = new StableERC4626For4626(); + StableERC4626ForVenus stableERC4626ForVenus = new StableERC4626ForVenus(); + StableERC4626ForCustomize stableERC4626ForCustomize = new StableERC4626ForCustomize(); + + factory = new TermMax4626Factory( + address(accessManager), + address(stableERC4626For4626), + stableERC4626ForAave, + address(stableERC4626ForVenus), + variableERC4626ForAave, + address(stableERC4626ForCustomize), + address(whitelistManager) ); - res.oracle.acceptPendingOracle(address(res.debt)); - res.oracle.acceptPendingOracle(address(res.collateral)); + // grant POOL_DEPLOYER_ROLE to factory so it can set whitelist for new pool + grantWhitelistRoleTo(accessManager, address(factory)); + } - MockPriceFeed.RoundData memory roundData = MockPriceFeed.RoundData({ - roundId: 1, - answer: int256(1e1 ** res.collateralOracle.decimals()), - startedAt: 0, - updatedAt: 0, - answeredInRound: 0 - }); - res.collateralOracle.updateRoundData(roundData); + function deployRes(address admin) internal returns (Res memory res) { + res = deployAccessControl(admin); + res.factory = deployMarketFactory( + address(res.accessManager), address(res.whitelistManager), address(new TermMaxOrderV2()) + ); + res.vaultFactory = deployVaultFactory(address(res.accessManager), address(res.whitelistManager), admin); + res.poolFactory = deployPoolFactory(address(res.accessManager), address(res.whitelistManager), address(0)); + res.router = deployRouter(admin, address(res.whitelistManager)); + } + + function deployMarket(address admin, MarketConfig memory marketConfig, uint32 maxLtv, uint32 liquidationLtv) + internal + returns (Res memory res) + { + res = deployAccessControl(admin); + deployMockTokens(res, admin); + res.factory = deployMarketFactory( + address(res.accessManager), address(res.whitelistManager), address(new TermMaxOrderV2()) + ); + res.vaultFactory = deployVaultFactory(address(res.accessManager), address(res.whitelistManager), admin); + res.poolFactory = deployPoolFactory(address(res.accessManager), address(res.whitelistManager), address(0)); MarketInitialParams memory initialParams = MarketInitialParams({ collateral: address(res.collateral), @@ -185,7 +244,6 @@ library DeployUtils { tokenName: "DAI-ETH", tokenSymbol: "DAI-ETH" }); - res.marketConfig = marketConfig; res.market = TermMaxMarketV2(res.factory.createMarket(GT_ERC20, initialParams, 0)); @@ -200,134 +258,18 @@ library DeployUtils { address collateral, address debt ) internal returns (Res memory res) { - res.factory = deployFactory(admin); + res = deployAccessControl(admin); + res.factory = deployMarketFactory( + address(res.accessManager), address(res.whitelistManager), address(new TermMaxOrderV2()) + ); + res.vaultFactory = deployVaultFactory(address(res.accessManager), address(res.whitelistManager), admin); + res.poolFactory = deployPoolFactory(address(res.accessManager), address(res.whitelistManager), address(0)); res.collateral = MockERC20(collateral); res.debt = MockERC20(debt); res.debtOracle = new MockPriceFeed(admin); res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); - - res.oracle.submitPendingOracle( - address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) - ); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) - ); - res.oracle.acceptPendingOracle(address(res.debt)); - res.oracle.acceptPendingOracle(address(res.collateral)); - - MockPriceFeed.RoundData memory roundData = MockPriceFeed.RoundData({ - roundId: 1, - answer: int256(1e1 ** res.collateralOracle.decimals()), - startedAt: 0, - updatedAt: 0, - answeredInRound: 0 - }); - res.collateralOracle.updateRoundData(roundData); - - MarketInitialParams memory initialParams = MarketInitialParams({ - collateral: address(res.collateral), - debtToken: res.debt, - admin: admin, - gtImplementation: address(0), - marketConfig: marketConfig, - loanConfig: LoanConfig({ - oracle: IOracle(address(res.oracle)), - liquidationLtv: liquidationLtv, - maxLtv: maxLtv, - liquidatable: true - }), - gtInitalParams: abi.encode(type(uint256).max), - tokenName: "DAI-ETH", - tokenSymbol: "DAI-ETH" - }); - - res.marketConfig = marketConfig; - res.market = TermMaxMarketV2(res.factory.createMarket(GT_ERC20, initialParams, 0)); - - (res.ft, res.xt, res.gt,,) = res.market.tokens(); - } - - function deployOnlyDeliveryMarket( - address admin, - MarketConfig memory marketConfig, - uint32 maxLtv, - uint32 liquidationLtv - ) internal returns (Res memory res) { - res.factory = deployFactory(admin); - OnlyDeliveryGearingToken gtImplementation = new OnlyDeliveryGearingToken(); - string memory name = "OnlyDeliveryGearingToken"; - bytes32 key = keccak256(bytes(name)); - res.factory.setGtImplement(name, address(gtImplementation)); - res.collateral = new MockERC20("ETH", "ETH", 18); - res.debt = new MockERC20("DAI", "DAI", 8); - - res.debtOracle = new MockPriceFeed(admin); - res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); - - res.oracle.submitPendingOracle( - address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) - ); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) - ); - - res.oracle.acceptPendingOracle(address(res.debt)); - res.oracle.acceptPendingOracle(address(res.collateral)); - - MockPriceFeed.RoundData memory roundData = MockPriceFeed.RoundData({ - roundId: 1, - answer: int256(1e1 ** res.collateralOracle.decimals()), - startedAt: 0, - updatedAt: 0, - answeredInRound: 0 - }); - res.collateralOracle.updateRoundData(roundData); - - MarketInitialParams memory initialParams = MarketInitialParams({ - collateral: address(res.collateral), - debtToken: res.debt, - admin: admin, - gtImplementation: address(0), - marketConfig: marketConfig, - loanConfig: LoanConfig({ - oracle: IOracle(address(res.oracle)), - liquidationLtv: liquidationLtv, - maxLtv: maxLtv, - liquidatable: false - }), - gtInitalParams: abi.encode(type(uint256).max), - tokenName: "DAI-ETH", - tokenSymbol: "DAI-ETH" - }); - - res.marketConfig = marketConfig; - res.market = TermMaxMarketV2(res.factory.createMarket(key, initialParams, 0)); - - (res.ft, res.xt, res.gt,,) = res.market.tokens(); - } - - function deployMockMarket2( - address admin, - IERC20 debt, - uint256 duration, - MarketConfig memory mc, - uint32 maxLtv, - uint32 liquidationLtv - ) internal returns (Res memory res) { - (res.factory, res.whitelistManager) = deployFactoryWithMockOrder(admin); - res.debt = MockERC20(address(debt)); - MarketConfig memory marketConfig = mc; - marketConfig.maturity += uint64(duration * 1 days); - - res.collateral = new MockERC20("ETH", "ETH", 18); - - res.debtOracle = new MockPriceFeed(admin); - res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); res.oracle.submitPendingOracle( address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) @@ -374,32 +316,12 @@ library DeployUtils { internal returns (Res memory res) { - (res.factory, res.whitelistManager) = deployFactoryWithMockOrder(admin); - - res.collateral = new MockERC20("ETH", "ETH", 18); - res.debt = new MockERC20("DAI", "DAI", 8); - - res.debtOracle = new MockPriceFeed(admin); - res.collateralOracle = new MockPriceFeed(admin); - res.oracle = deployOracle(admin, 0); - - res.oracle.submitPendingOracle( - address(res.debt), IOracleV2.Oracle(res.debtOracle, res.debtOracle, 0, 0, 365 days, 0) - ); - res.oracle.submitPendingOracle( - address(res.collateral), IOracleV2.Oracle(res.collateralOracle, res.collateralOracle, 0, 0, 365 days, 0) - ); - res.oracle.acceptPendingOracle(address(res.debt)); - res.oracle.acceptPendingOracle(address(res.collateral)); - - MockPriceFeed.RoundData memory roundData = MockPriceFeed.RoundData({ - roundId: 1, - answer: int256(1e1 ** res.collateralOracle.decimals()), - startedAt: 0, - updatedAt: 0, - answeredInRound: 0 - }); - res.collateralOracle.updateRoundData(roundData); + res = deployAccessControl(admin); + deployMockTokens(res, admin); + res.factory = + deployMarketFactory(address(res.accessManager), address(res.whitelistManager), address(new MockOrderV2())); + res.vaultFactory = deployVaultFactory(address(res.accessManager), address(res.whitelistManager), admin); + res.poolFactory = deployPoolFactory(address(res.accessManager), address(res.whitelistManager), address(0)); MarketInitialParams memory initialParams = MarketInitialParams({ collateral: address(res.collateral), @@ -417,7 +339,6 @@ library DeployUtils { tokenName: "DAI-ETH", tokenSymbol: "DAI-ETH" }); - res.marketConfig = marketConfig; res.market = TermMaxMarketV2(res.factory.createMarket(GT_ERC20, initialParams, 0)); @@ -434,149 +355,29 @@ library DeployUtils { order = market.createOrder(maker, maxXtReserve, swapTrigger, curveCuts); } - function deployFactory(address admin) public returns (TermMaxFactoryV2 factory) { - AccessManagerV2 accessManager = deployAccessManagerV2(admin); - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new TermMaxOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - IWhitelistManager whitelistManager = deployWhitelistManager(); - factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); - _grantFactoryRoles(accessManager, admin, factory); - } - - function deployFactory(address admin, IWhitelistManager whitelistManager) - public - returns (TermMaxFactoryV2 factory) - { - AccessManagerV2 accessManager = deployAccessManagerV2(admin); - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new TermMaxOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); - _grantFactoryRoles(accessManager, admin, factory); - } - - function deployFactory(address admin, AccessManagerV2 accessManager, IWhitelistManager whitelistManager) - public - returns (TermMaxFactoryV2 factory) - { - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new TermMaxOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); - _grantFactoryRoles(accessManager, admin, factory); - } - - function deployFactoryWithMockOrder(address admin) - public - returns (TermMaxFactoryV2 factory, IWhitelistManager whitelistManager) - { - AccessManagerV2 accessManager = deployAccessManagerV2(admin); - address tokenImplementation = address(new MintableERC20V2()); - address orderImplementation = address(new MockOrderV2()); - TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); - whitelistManager = deployWhitelistManager(); - factory = new TermMaxFactoryV2(address(accessManager), address(m), address(whitelistManager)); - _grantFactoryRoles(accessManager, admin, factory); - } - - function deployVaultFactory(address admin) public returns (TermMaxVaultFactoryV2 vaultFactory) { - AccessManagerV2 accessManager = deployAccessManagerV2(admin); - OrderManagerV2 orderManager = new OrderManagerV2(); - IWhitelistManager whitelistManager = deployWhitelistManager(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = - new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); - _grantVaultFactoryRoles(accessManager, admin, vaultFactory); - } - - function deployVaultFactory(address admin, IWhitelistManager whitelistManager) - public - returns (TermMaxVaultFactoryV2 vaultFactory) - { - AccessManagerV2 accessManager = deployAccessManagerV2(admin); - OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = - new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); - _grantVaultFactoryRoles(accessManager, admin, vaultFactory); - } - - function deployVaultFactory(address admin, AccessManagerV2 accessManager, IWhitelistManager whitelistManager) - public - returns (TermMaxVaultFactoryV2 vaultFactory) - { - OrderManagerV2 orderManager = new OrderManagerV2(); - TermMaxVaultV2 implementation = new TermMaxVaultV2(address(orderManager), address(whitelistManager)); - vaultFactory = - new TermMaxVaultFactoryV2(address(accessManager), address(implementation), address(whitelistManager)); - _grantVaultFactoryRoles(accessManager, admin, vaultFactory); - } - - function deployOracle(address admin, uint256 timeLock) public returns (OracleAggregatorV2 oracle) { - oracle = new OracleAggregatorV2(admin, timeLock); - } - - function deployRouter(address admin) public returns (TermMaxRouterV2 router, IWhitelistManager whitelistManager) { - whitelistManager = deployWhitelistManager(); - TermMaxRouterV2 implementation = new TermMaxRouterV2(address(whitelistManager)); - bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); - ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); - router = TermMaxRouterV2(address(proxy)); - } - - function deployRouter(address admin, IWhitelistManager whitelistManager) public returns (TermMaxRouterV2 router) { - TermMaxRouterV2 implementation = new TermMaxRouterV2(address(whitelistManager)); + function deployRouter(address admin, address whitelistManager) public returns (TermMaxRouterV2 router) { + TermMaxRouterV2 implementation = new TermMaxRouterV2(whitelistManager); bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); router = TermMaxRouterV2(address(proxy)); } - function deployVault(address admin, VaultInitialParamsV2 memory initialParams) + function deployVault(TermMaxVaultFactoryV2 vaultFactory, VaultInitialParamsV2 memory initialParams) public returns (TermMaxVaultV2 vault) { - TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin); - (VmSafe.CallerMode callerMode,,) = vm.readCallers(); - if (callerMode == VmSafe.CallerMode.None) { - vm.startPrank(admin); - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - vm.stopPrank(); - } else { - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - } + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); } - function deployVault(address admin, VaultInitialParamsV2 memory initialParams, IWhitelistManager whitelistManager) + function deployVault(TermMaxVaultFactoryV2 vaultFactory, VaultInitialParamsV2 memory initialParams, uint256 salt) public returns (TermMaxVaultV2 vault) { - TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin, whitelistManager); - (VmSafe.CallerMode callerMode,,) = vm.readCallers(); - if (callerMode == VmSafe.CallerMode.None) { - vm.startPrank(admin); - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - vm.stopPrank(); - } else { - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - } + vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, salt)); } - function deployVault( - address admin, - AccessManagerV2 accessManager, - VaultInitialParamsV2 memory initialParams, - IWhitelistManager whitelistManager - ) public returns (TermMaxVaultV2 vault) { - TermMaxVaultFactoryV2 vaultFactory = deployVaultFactory(admin, accessManager, whitelistManager); - (VmSafe.CallerMode callerMode,,) = vm.readCallers(); - if (callerMode == VmSafe.CallerMode.None) { - vm.startPrank(admin); - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - vm.stopPrank(); - } else { - vault = TermMaxVaultV2(vaultFactory.createVault(initialParams, 0)); - } + function deployOracle(address admin, uint256 timeLock) public returns (OracleAggregatorV2 oracle) { + oracle = new OracleAggregatorV2(admin, timeLock); } function deployAccessManager(address admin) internal returns (AccessManager accessManager) { @@ -586,44 +387,17 @@ library DeployUtils { accessManager = AccessManager(address(proxy)); } - function deployAccessManagerV2(address admin) internal returns (AccessManagerV2 accessManager) { - AccessManagerV2 implementation = new AccessManagerV2(); - bytes memory data = abi.encodeCall(AccessManager.initialize, admin); - ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); - accessManager = AccessManagerV2(address(proxy)); - } - - function _grantFactoryRoles(AccessManagerV2 accessManager, address admin, TermMaxFactoryV2 factory) private { - (VmSafe.CallerMode callerMode,,) = vm.readCallers(); - if (callerMode == VmSafe.CallerMode.None) { - vm.startPrank(admin); - accessManager.grantRole(accessManager.MARKET_ROLE(), admin); - accessManager.grantRole(accessManager.TERMMAX_MARKET_FACTORY_ROLE(), admin); - accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(factory)); - vm.stopPrank(); - } else { - accessManager.grantRole(accessManager.MARKET_ROLE(), admin); - accessManager.grantRole(accessManager.TERMMAX_MARKET_FACTORY_ROLE(), admin); - accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(factory)); - } - } - - function _grantVaultFactoryRoles(AccessManagerV2 accessManager, address admin, TermMaxVaultFactoryV2 vaultFactory) - private + function deployWhitelistManager(address accessManagerAddress) + internal + returns (WhitelistManager whitelistManager) { - (VmSafe.CallerMode callerMode,,) = vm.readCallers(); - if (callerMode == VmSafe.CallerMode.None) { - vm.startPrank(admin); - accessManager.grantRole(accessManager.VAULT_DEPLOYER_ROLE(), admin); - accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(vaultFactory)); - vm.stopPrank(); - } else { - accessManager.grantRole(accessManager.VAULT_DEPLOYER_ROLE(), admin); - accessManager.grantRole(accessManager.WHITELIST_ROLE(), address(vaultFactory)); - } - } - - function deployWhitelistManager() internal returns (IWhitelistManager whitelistManager) { - whitelistManager = new MockWhitelistManager(); + WhitelistManager whitelistManagerImpl = new WhitelistManager(accessManagerAddress); + whitelistManager = WhitelistManager( + address( + new ERC1967Proxy( + address(whitelistManagerImpl), abi.encodeCall(WhitelistManager.initialize, (accessManagerAddress)) + ) + ) + ); } } From 079adb784e0baedc2dc08e3089e9cb725b92e5c8 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 20:06:43 +0800 Subject: [PATCH 16/21] add stable ERC4626 functionality with access control and mock implementation --- contracts/v2/access/AccessManagerV2.sol | 38 +++++++++ contracts/v2/access/Roles.sol | 4 + .../v2/test/MockStableERC4626For4626.sol | 44 ++++++++++ contracts/v2/tokens/IStableERC4626For4626.sol | 13 +++ test/v2/AccessManagerV2.t.sol | 82 +++++++++++++++++++ 5 files changed, 181 insertions(+) create mode 100644 contracts/v2/test/MockStableERC4626For4626.sol create mode 100644 contracts/v2/tokens/IStableERC4626For4626.sol diff --git a/contracts/v2/access/AccessManagerV2.sol b/contracts/v2/access/AccessManagerV2.sol index 10deccd4..d9200139 100644 --- a/contracts/v2/access/AccessManagerV2.sol +++ b/contracts/v2/access/AccessManagerV2.sol @@ -5,6 +5,8 @@ import "../../v1/access/AccessManager.sol"; import {IOracleV2} from "../oracle/IOracleV2.sol"; import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "../vault/ITermMaxVaultV2.sol"; import {IWhitelistManager} from "./IWhitelistManager.sol"; +import {IStableERC4626For4626, StakingBuffer} from "../tokens/IStableERC4626For4626.sol"; +import {TransferUtilsV2} from "../lib/TransferUtilsV2.sol"; import {VersionV2} from "../VersionV2.sol"; /** @@ -14,6 +16,8 @@ import {VersionV2} from "../VersionV2.sol"; * @dev Inherits from AccessManager V1 and adds V2-specific functionality for managing oracles and batch operations */ contract AccessManagerV2 is AccessManager, VersionV2 { + using TransferUtilsV2 for *; + error CannotRenounceRole(); function upgradeSubContract(UUPSUpgradeable proxy, address newImplementation, bytes memory data) @@ -101,6 +105,40 @@ contract AccessManagerV2 is AccessManager, VersionV2 { vault.revokePendingPool(); } + /** + * @notice Update stable ERC4626 buffer config and add reserves + * @param stableERC4626 The stable ERC4626 contract to update + * @param additionalReserves Additional reserves transferred into the stable ERC4626 contract + * @param bufferConfig_ New buffer configuration + * @custom:access Requires STABLE_ERC4626_BUFFER_ROLE + */ + function updateBufferConfigAndAddReserves( + IStableERC4626For4626 stableERC4626, + uint256 additionalReserves, + StakingBuffer.BufferConfig memory bufferConfig_ + ) external onlyRole(STABLE_ERC4626_BUFFER_ROLE) { + if (additionalReserves != 0) { + stableERC4626.safeTransferFrom(msg.sender, address(this), additionalReserves); + stableERC4626.safeApprove(address(stableERC4626), additionalReserves); + } + stableERC4626.updateBufferConfigAndAddReserves(additionalReserves, bufferConfig_); + } + + /** + * @notice Withdraw stable ERC4626 income assets + * @param stableERC4626 The stable ERC4626 contract to withdraw from + * @param asset Asset address to withdraw (underlying or thirdPool token) + * @param to Recipient address + * @param amount Amount of income assets to withdraw + * @custom:access Requires STABLE_ERC4626_INCOME_WITHDRAW_ROLE + */ + function withdrawIncomeAssets(IStableERC4626For4626 stableERC4626, address asset, address to, uint256 amount) + external + onlyRole(STABLE_ERC4626_INCOME_WITHDRAW_ROLE) + { + stableERC4626.withdrawIncomeAssets(asset, to, amount); + } + /// @notice Forbid renouncing roles function renounceRole(bytes32 role, address callerConfirmation) public override { revert CannotRenounceRole(); diff --git a/contracts/v2/access/Roles.sol b/contracts/v2/access/Roles.sol index ff2de333..ba236568 100644 --- a/contracts/v2/access/Roles.sol +++ b/contracts/v2/access/Roles.sol @@ -26,4 +26,8 @@ abstract contract Roles { bytes32 public constant POOL_DEPLOYER_ROLE = keccak256("POOL_DEPLOYER_ROLE"); /// @notice Role to deploy vaults bytes32 public constant VAULT_DEPLOYER_ROLE = keccak256("VAULT_DEPLOYER_ROLE"); + /// @notice Role to update stable ERC4626 buffer config and add reserves + bytes32 public constant STABLE_ERC4626_BUFFER_ROLE = keccak256("STABLE_ERC4626_BUFFER_ROLE"); + /// @notice Role to withdraw stable ERC4626 income assets + bytes32 public constant STABLE_ERC4626_INCOME_WITHDRAW_ROLE = keccak256("STABLE_ERC4626_INCOME_WITHDRAW_ROLE"); } diff --git a/contracts/v2/test/MockStableERC4626For4626.sol b/contracts/v2/test/MockStableERC4626For4626.sol new file mode 100644 index 00000000..72a9bb8e --- /dev/null +++ b/contracts/v2/test/MockStableERC4626For4626.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IStableERC4626For4626} from "../tokens/IStableERC4626For4626.sol"; +import {StakingBuffer} from "../tokens/StakingBuffer.sol"; + +contract MockStableERC4626For4626 is ERC20, IStableERC4626For4626 { + bool public updateCalled; + bool public withdrawCalled; + + uint256 public lastAdditionalReserves; + uint256 public lastMinimumBuffer; + uint256 public lastMaximumBuffer; + uint256 public lastBuffer; + + address public lastAsset; + address public lastTo; + uint256 public lastAmount; + + constructor() ERC20("MockStableERC4626For4626", "mS4626") {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } + + function updateBufferConfigAndAddReserves( + uint256 additionalReserves, + StakingBuffer.BufferConfig memory bufferConfig_ + ) external { + updateCalled = true; + lastAdditionalReserves = additionalReserves; + lastMinimumBuffer = bufferConfig_.minimumBuffer; + lastMaximumBuffer = bufferConfig_.maximumBuffer; + lastBuffer = bufferConfig_.buffer; + } + + function withdrawIncomeAssets(address asset, address to, uint256 amount) external { + withdrawCalled = true; + lastAsset = asset; + lastTo = to; + lastAmount = amount; + } +} diff --git a/contracts/v2/tokens/IStableERC4626For4626.sol b/contracts/v2/tokens/IStableERC4626For4626.sol new file mode 100644 index 00000000..a428da20 --- /dev/null +++ b/contracts/v2/tokens/IStableERC4626For4626.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {StakingBuffer, IERC20} from "./StakingBuffer.sol"; + +interface IStableERC4626For4626 is IERC20 { + function updateBufferConfigAndAddReserves( + uint256 additionalReserves, + StakingBuffer.BufferConfig memory bufferConfig_ + ) external; + + function withdrawIncomeAssets(address asset, address to, uint256 amount) external; +} diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index a4b09d7f..296eed34 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -33,6 +33,9 @@ import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "contracts/ import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; +import {IStableERC4626For4626} from "contracts/v2/tokens/IStableERC4626For4626.sol"; +import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; +import {MockStableERC4626For4626} from "contracts/v2/test/MockStableERC4626For4626.sol"; contract AccessManagerTestV2 is Test { using JSONLoader for *; @@ -822,6 +825,85 @@ contract AccessManagerTestV2 is Test { assertEq(vaultV2.pendingPool().validAt, 0); } + function testUpdateBufferConfigAndAddReservesAccessControl() public { + MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); + address operator = vm.randomAddress(); + StakingBuffer.BufferConfig memory newConfig = + StakingBuffer.BufferConfig({minimumBuffer: 100e6, maximumBuffer: 500e6, buffer: 300e6}); + uint256 additionalReserves = 42e6; + + vm.prank(deployer); + manager.grantRole(manager.STABLE_ERC4626_BUFFER_ROLE(), operator); + + stable4626.mint(operator, additionalReserves); + vm.prank(operator); + stable4626.approve(address(manager), additionalReserves); + + vm.prank(operator); + manager.updateBufferConfigAndAddReserves( + IStableERC4626For4626(address(stable4626)), additionalReserves, newConfig + ); + + assertTrue(stable4626.updateCalled()); + assertEq(stable4626.lastAdditionalReserves(), additionalReserves); + assertEq(stable4626.lastMinimumBuffer(), newConfig.minimumBuffer); + assertEq(stable4626.lastMaximumBuffer(), newConfig.maximumBuffer); + assertEq(stable4626.lastBuffer(), newConfig.buffer); + } + + function testUpdateBufferConfigAndAddReservesWithoutRole() public { + MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); + address unauthorized = vm.randomAddress(); + StakingBuffer.BufferConfig memory newConfig = + StakingBuffer.BufferConfig({minimumBuffer: 100e6, maximumBuffer: 500e6, buffer: 300e6}); + + vm.startPrank(unauthorized); + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, + unauthorized, + manager.STABLE_ERC4626_BUFFER_ROLE() + ) + ); + manager.updateBufferConfigAndAddReserves(IStableERC4626For4626(address(stable4626)), 1e6, newConfig); + vm.stopPrank(); + } + + function testWithdrawIncomeAssetsAccessControl() public { + MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); + address operator = vm.randomAddress(); + address asset = vm.randomAddress(); + address to = vm.randomAddress(); + uint256 amount = 99e6; + + vm.prank(deployer); + manager.grantRole(manager.STABLE_ERC4626_INCOME_WITHDRAW_ROLE(), operator); + + vm.prank(operator); + manager.withdrawIncomeAssets(IStableERC4626For4626(address(stable4626)), asset, to, amount); + + assertTrue(stable4626.withdrawCalled()); + assertEq(stable4626.lastAsset(), asset); + assertEq(stable4626.lastTo(), to); + assertEq(stable4626.lastAmount(), amount); + } + + function testWithdrawIncomeAssetsWithoutRole() public { + MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); + address unauthorized = vm.randomAddress(); + + vm.startPrank(unauthorized); + vm.expectRevert( + abi.encodeWithSelector( + IAccessControl.AccessControlUnauthorizedAccount.selector, + unauthorized, + manager.STABLE_ERC4626_INCOME_WITHDRAW_ROLE() + ) + ); + manager.withdrawIncomeAssets(IStableERC4626For4626(address(stable4626)), address(1), address(2), 1e6); + vm.stopPrank(); + } + // Import the events for testing event RevokePendingMinApy(address indexed caller); event RevokePendingPool(address indexed caller); From d6f0b1ed603596fe3a2606bbe74f03ce276c56b9 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 20:15:20 +0800 Subject: [PATCH 17/21] update contracts to use VersionV2_0_1 for improved functionality and consistency --- contracts/v2/access/AccessManagerV2.sol | 4 ++-- contracts/v2/access/WhitelistManager.sol | 4 ++-- contracts/v2/factory/TermMax4626Factory.sol | 4 ++-- contracts/v2/factory/TermMaxFactoryV2.sol | 4 ++-- contracts/v2/factory/TermMaxVaultFactoryV2.sol | 4 ++-- contracts/v2/router/TermMaxRouterV2.sol | 4 ++-- contracts/v2/vault/TermMaxVaultV2.sol | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/contracts/v2/access/AccessManagerV2.sol b/contracts/v2/access/AccessManagerV2.sol index d9200139..b93618fd 100644 --- a/contracts/v2/access/AccessManagerV2.sol +++ b/contracts/v2/access/AccessManagerV2.sol @@ -7,7 +7,7 @@ import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "../vault/I import {IWhitelistManager} from "./IWhitelistManager.sol"; import {IStableERC4626For4626, StakingBuffer} from "../tokens/IStableERC4626For4626.sol"; import {TransferUtilsV2} from "../lib/TransferUtilsV2.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** * @title TermMax Access Manager V2 @@ -15,7 +15,7 @@ import {VersionV2} from "../VersionV2.sol"; * @notice Extended access manager for TermMax V2 protocol with additional oracle and batch operations * @dev Inherits from AccessManager V1 and adds V2-specific functionality for managing oracles and batch operations */ -contract AccessManagerV2 is AccessManager, VersionV2 { +contract AccessManagerV2 is AccessManager, VersionV2_0_1 { using TransferUtilsV2 for *; error CannotRenounceRole(); diff --git a/contracts/v2/access/WhitelistManager.sol b/contracts/v2/access/WhitelistManager.sol index 8337cd51..49808203 100644 --- a/contracts/v2/access/WhitelistManager.sol +++ b/contracts/v2/access/WhitelistManager.sol @@ -8,7 +8,7 @@ import { } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol"; import {IWhitelistManager} from "./IWhitelistManager.sol"; import {WithAccessManagerRole} from "./WithAccessManagerRole.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** * TODO add with access manager role and whitelist check @@ -22,7 +22,7 @@ contract WhitelistManager is UUPSUpgradeable, Ownable2StepUpgradeable, WithAccessManagerRole, - VersionV2 + VersionV2_0_1 { mapping(ContractModule => mapping(address => bool)) private whitelists; diff --git a/contracts/v2/factory/TermMax4626Factory.sol b/contracts/v2/factory/TermMax4626Factory.sol index b8cec096..f559f4e0 100644 --- a/contracts/v2/factory/TermMax4626Factory.sol +++ b/contracts/v2/factory/TermMax4626Factory.sol @@ -12,9 +12,9 @@ import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {FactoryErrorsV2} from "../errors/FactoryErrorsV2.sol"; import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; -contract TermMax4626Factory is VersionV2, WithWhitelistCheck, WithAccessManagerRole { +contract TermMax4626Factory is VersionV2_0_1, WithWhitelistCheck, WithAccessManagerRole { using Clones for address; bytes32 public constant STABLE_ERC4626_FOR_4626 = keccak256("StableERC4626For4626"); diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index 624a941d..949aa27b 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -11,7 +11,7 @@ import {ITermMaxFactory} from "../../v1/factory/ITermMaxFactory.sol"; import {FactoryEventsV2} from "../events/FactoryEventsV2.sol"; import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** * @title TermMax Factory V2 @@ -20,7 +20,7 @@ import {VersionV2} from "../VersionV2.sol"; * @dev Manages market deployment, gearing token implementations, and market configuration validation * Inherits from V1 factory interface while adding V2-specific features for improved market creation */ -contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2, WithWhitelistCheck, WithAccessManagerRole { +contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2_0_1, WithWhitelistCheck, WithAccessManagerRole { /// @notice Constant key for the default ERC20 gearing token implementation bytes32 constant GT_ERC20 = keccak256("GearingTokenWithERC20"); diff --git a/contracts/v2/factory/TermMaxVaultFactoryV2.sol b/contracts/v2/factory/TermMaxVaultFactoryV2.sol index 61de53f1..4cda0fb4 100644 --- a/contracts/v2/factory/TermMaxVaultFactoryV2.sol +++ b/contracts/v2/factory/TermMaxVaultFactoryV2.sol @@ -8,13 +8,13 @@ import {ITermMaxVaultFactoryV2} from "./ITermMaxVaultFactoryV2.sol"; import {VaultInitialParamsV2} from "../storage/TermMaxStorageV2.sol"; import {WithAccessManagerRole} from "../access/WithAccessManagerRole.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** * @title The TermMax vault factory v2 * @author Term Structure Labs */ -contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2, WithWhitelistCheck, WithAccessManagerRole { +contract TermMaxVaultFactoryV2 is ITermMaxVaultFactoryV2, VersionV2_0_1, WithWhitelistCheck, WithAccessManagerRole { /** * @notice The implementation of TermMax Vault contract v2 */ diff --git a/contracts/v2/router/TermMaxRouterV2.sol b/contracts/v2/router/TermMaxRouterV2.sol index 81af84fc..2634e099 100644 --- a/contracts/v2/router/TermMaxRouterV2.sol +++ b/contracts/v2/router/TermMaxRouterV2.sol @@ -32,7 +32,7 @@ import {RouterErrorsV2} from "../errors/RouterErrorsV2.sol"; import {RouterEventsV2} from "../events/RouterEventsV2.sol"; import {ArrayUtilsV2} from "../lib/ArrayUtilsV2.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** * @title TermMax Router V2 @@ -48,7 +48,7 @@ contract TermMaxRouterV2 is ITermMaxRouterV2, RouterErrors, RouterEvents, - VersionV2, + VersionV2_0_1, ReentrancyGuardUpgradeable, WithWhitelistCheck { diff --git a/contracts/v2/vault/TermMaxVaultV2.sol b/contracts/v2/vault/TermMaxVaultV2.sol index 41227fc0..f4fbed7f 100644 --- a/contracts/v2/vault/TermMaxVaultV2.sol +++ b/contracts/v2/vault/TermMaxVaultV2.sol @@ -35,7 +35,7 @@ import {Constants} from "../../v1/lib/Constants.sol"; import {ITermMaxVaultV2} from "./ITermMaxVaultV2.sol"; import {VaultErrorsV2} from "../errors/VaultErrorsV2.sol"; import {TransactionReentrancyGuard} from "../lib/TransactionReentrancyGuard.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; contract TermMaxVaultV2 is @@ -47,7 +47,7 @@ contract TermMaxVaultV2 is ISwapCallback, ITermMaxVaultV2, TransactionReentrancyGuard, - VersionV2, + VersionV2_0_1, WithWhitelistCheck { using SafeCast for uint256; From 1d9cc6e0944ce7c352ea524088f04369206ff8a5 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 7 Apr 2026 20:50:58 +0800 Subject: [PATCH 18/21] remove todo comment --- contracts/v2/access/WhitelistManager.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/v2/access/WhitelistManager.sol b/contracts/v2/access/WhitelistManager.sol index 49808203..66b12031 100644 --- a/contracts/v2/access/WhitelistManager.sol +++ b/contracts/v2/access/WhitelistManager.sol @@ -11,7 +11,6 @@ import {WithAccessManagerRole} from "./WithAccessManagerRole.sol"; import {VersionV2_0_1} from "../VersionV2_0_1.sol"; /** - * TODO add with access manager role and whitelist check * @title WhitelistManager * @author Term Structure Labs * @notice Manages whitelists for different contract modules such as adapters, order callbacks, and markets From 4a10d392302d5fd88c034984bc0b3fa51a7dfc10 Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 9 Apr 2026 17:26:19 +0800 Subject: [PATCH 19/21] fix: The logic issue when adding reserve via acess manager; Setting up permission consistency issues in gt implementation --- contracts/v1/access/AccessManager.sol | 2 +- contracts/v2/access/AccessManagerV2.sol | 9 ++- .../v2/test/MockStableERC4626For4626.sol | 44 ----------- test/v2/AccessManagerV2.t.sol | 77 ++++++++++--------- 4 files changed, 46 insertions(+), 86 deletions(-) delete mode 100644 contracts/v2/test/MockStableERC4626For4626.sol diff --git a/contracts/v1/access/AccessManager.sol b/contracts/v1/access/AccessManager.sol index df0b97d0..39a09612 100644 --- a/contracts/v1/access/AccessManager.sol +++ b/contracts/v1/access/AccessManager.sol @@ -40,7 +40,7 @@ contract AccessManager is AccessControlUpgradeable, UUPSUpgradeable, Roles { /// @notice Set GT implementation to the factory function setGtImplement(ITermMaxFactory factory, string memory gtImplementName, address gtImplement) external - onlyRole(MARKET_ROLE) + onlyRole(TERMMAX_MARKET_FACTORY_ROLE) { factory.setGtImplement(gtImplementName, gtImplement); } diff --git a/contracts/v2/access/AccessManagerV2.sol b/contracts/v2/access/AccessManagerV2.sol index b93618fd..639a7240 100644 --- a/contracts/v2/access/AccessManagerV2.sol +++ b/contracts/v2/access/AccessManagerV2.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.27; import "../../v1/access/AccessManager.sol"; import {IOracleV2} from "../oracle/IOracleV2.sol"; -import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "../vault/ITermMaxVaultV2.sol"; +import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts, IERC4626} from "../vault/ITermMaxVaultV2.sol"; import {IWhitelistManager} from "./IWhitelistManager.sol"; -import {IStableERC4626For4626, StakingBuffer} from "../tokens/IStableERC4626For4626.sol"; +import {IStableERC4626For4626, StakingBuffer, IERC20} from "../tokens/IStableERC4626For4626.sol"; import {TransferUtilsV2} from "../lib/TransferUtilsV2.sol"; import {VersionV2_0_1} from "../VersionV2_0_1.sol"; @@ -118,8 +118,9 @@ contract AccessManagerV2 is AccessManager, VersionV2_0_1 { StakingBuffer.BufferConfig memory bufferConfig_ ) external onlyRole(STABLE_ERC4626_BUFFER_ROLE) { if (additionalReserves != 0) { - stableERC4626.safeTransferFrom(msg.sender, address(this), additionalReserves); - stableERC4626.safeApprove(address(stableERC4626), additionalReserves); + IERC20 asset = IERC20(IERC4626(address(stableERC4626)).asset()); + asset.safeTransferFrom(msg.sender, address(this), additionalReserves); + asset.safeApprove(address(stableERC4626), additionalReserves); } stableERC4626.updateBufferConfigAndAddReserves(additionalReserves, bufferConfig_); } diff --git a/contracts/v2/test/MockStableERC4626For4626.sol b/contracts/v2/test/MockStableERC4626For4626.sol deleted file mode 100644 index 72a9bb8e..00000000 --- a/contracts/v2/test/MockStableERC4626For4626.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import {IStableERC4626For4626} from "../tokens/IStableERC4626For4626.sol"; -import {StakingBuffer} from "../tokens/StakingBuffer.sol"; - -contract MockStableERC4626For4626 is ERC20, IStableERC4626For4626 { - bool public updateCalled; - bool public withdrawCalled; - - uint256 public lastAdditionalReserves; - uint256 public lastMinimumBuffer; - uint256 public lastMaximumBuffer; - uint256 public lastBuffer; - - address public lastAsset; - address public lastTo; - uint256 public lastAmount; - - constructor() ERC20("MockStableERC4626For4626", "mS4626") {} - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } - - function updateBufferConfigAndAddReserves( - uint256 additionalReserves, - StakingBuffer.BufferConfig memory bufferConfig_ - ) external { - updateCalled = true; - lastAdditionalReserves = additionalReserves; - lastMinimumBuffer = bufferConfig_.minimumBuffer; - lastMaximumBuffer = bufferConfig_.maximumBuffer; - lastBuffer = bufferConfig_.buffer; - } - - function withdrawIncomeAssets(address asset, address to, uint256 amount) external { - withdrawCalled = true; - lastAsset = asset; - lastTo = to; - lastAmount = amount; - } -} diff --git a/test/v2/AccessManagerV2.t.sol b/test/v2/AccessManagerV2.t.sol index 296eed34..7b9a5d08 100644 --- a/test/v2/AccessManagerV2.t.sol +++ b/test/v2/AccessManagerV2.t.sol @@ -2,7 +2,6 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; import {DeployUtils} from "./utils/DeployUtils.sol"; import {JSONLoader} from "./utils/JSONLoader.sol"; import {IAccessControl} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; @@ -15,7 +14,6 @@ import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/acces import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import {GearingTokenWithERC20} from "contracts/v1/tokens/GearingTokenWithERC20.sol"; import {ITermMaxMarket} from "contracts/v1/ITermMaxMarket.sol"; -import {MockERC20} from "contracts/v1/test/MockERC20.sol"; import {MockPriceFeed} from "contracts/v1/test/MockPriceFeed.sol"; import {ITermMaxFactory} from "contracts/v1/factory/ITermMaxFactory.sol"; import {MarketConfig, FeeConfig, MarketInitialParams} from "contracts/v1/storage/TermMaxStorage.sol"; @@ -31,11 +29,10 @@ import {VaultInitialParamsV2} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {TermMaxOrderV2} from "contracts/v2/TermMaxOrderV2.sol"; import {ITermMaxVaultV2, OrderV2ConfigurationParams, CurveCuts} from "contracts/v2/vault/ITermMaxVaultV2.sol"; import {VaultEventsV2} from "contracts/v2/events/VaultEventsV2.sol"; -import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; -import {WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; +import {IWhitelistManager, WhitelistManager} from "contracts/v2/access/WhitelistManager.sol"; import {IStableERC4626For4626} from "contracts/v2/tokens/IStableERC4626For4626.sol"; -import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; -import {MockStableERC4626For4626} from "contracts/v2/test/MockStableERC4626For4626.sol"; +import {StableERC4626For4626, StakingBuffer} from "contracts/v2/tokens/StableERC4626For4626.sol"; +import {MockERC4626} from "contracts/v2/test/MockERC4626.sol"; contract AccessManagerTestV2 is Test { using JSONLoader for *; @@ -55,6 +52,8 @@ contract AccessManagerTestV2 is Test { TermMaxOrderV2 vaultOrder; WhitelistManager whitelistManager; + IStableERC4626For4626 stable4626; + function setUp() public { vm.startPrank(deployer); testdata = vm.readFile(string.concat(vm.projectRoot(), "/test/testdata/testdata.json")); @@ -66,6 +65,15 @@ contract AccessManagerTestV2 is Test { orderConfig = JSONLoader.getOrderConfigFromJson(testdata, ".orderConfig"); res = DeployUtils.deployMarket(deployer, marketConfig, maxLtv, liquidationLtv); + stable4626 = IStableERC4626For4626( + address( + res.poolFactory.createStableERC4626For4626( + address(res.accessManager), + address(new MockERC4626(res.debt)), + StakingBuffer.BufferConfig({minimumBuffer: 100e6, maximumBuffer: 500e6, buffer: 300e6}) + ) + ) + ); whitelistManager = res.whitelistManager; manager = res.accessManager; res.order = TermMaxOrderV2( @@ -477,7 +485,7 @@ contract AccessManagerTestV2 is Test { vm.startPrank(sender); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, sender, manager.MARKET_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, sender, manager.TERMMAX_MARKET_FACTORY_ROLE() ) ); manager.setGtImplement(ITermMaxFactory(address(res.factory)), gtImplementName, newImplement); @@ -826,7 +834,6 @@ contract AccessManagerTestV2 is Test { } function testUpdateBufferConfigAndAddReservesAccessControl() public { - MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); address operator = vm.randomAddress(); StakingBuffer.BufferConfig memory newConfig = StakingBuffer.BufferConfig({minimumBuffer: 100e6, maximumBuffer: 500e6, buffer: 300e6}); @@ -835,28 +842,29 @@ contract AccessManagerTestV2 is Test { vm.prank(deployer); manager.grantRole(manager.STABLE_ERC4626_BUFFER_ROLE(), operator); - stable4626.mint(operator, additionalReserves); + res.debt.mint(operator, additionalReserves); vm.prank(operator); - stable4626.approve(address(manager), additionalReserves); + res.debt.approve(address(manager), additionalReserves); + uint256 initialReserves = res.debt.balanceOf(address(stable4626)); vm.prank(operator); manager.updateBufferConfigAndAddReserves( IStableERC4626For4626(address(stable4626)), additionalReserves, newConfig ); - assertTrue(stable4626.updateCalled()); - assertEq(stable4626.lastAdditionalReserves(), additionalReserves); - assertEq(stable4626.lastMinimumBuffer(), newConfig.minimumBuffer); - assertEq(stable4626.lastMaximumBuffer(), newConfig.maximumBuffer); - assertEq(stable4626.lastBuffer(), newConfig.buffer); - } + StableERC4626For4626 stc = StableERC4626For4626(address(stable4626)); + (uint256 minimumBuffer, uint256 maximumBuffer, uint256 buffer) = stc.bufferConfig(); + assertEq(minimumBuffer, newConfig.minimumBuffer, "Minimum buffer should be updated in the vault"); + assertEq(maximumBuffer, newConfig.maximumBuffer, "Maximum buffer should be updated in the vault"); + assertEq(buffer, newConfig.buffer, "Buffer should be updated in the vault"); + uint256 expectedTotalReserves = initialReserves + additionalReserves; + assertEq( + res.debt.balanceOf(address(stable4626)), + expectedTotalReserves, + "Additional reserves should be added to the vault" + ); - function testUpdateBufferConfigAndAddReservesWithoutRole() public { - MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); address unauthorized = vm.randomAddress(); - StakingBuffer.BufferConfig memory newConfig = - StakingBuffer.BufferConfig({minimumBuffer: 100e6, maximumBuffer: 500e6, buffer: 300e6}); - vm.startPrank(unauthorized); vm.expectRevert( abi.encodeWithSelector( @@ -870,26 +878,25 @@ contract AccessManagerTestV2 is Test { } function testWithdrawIncomeAssetsAccessControl() public { - MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); address operator = vm.randomAddress(); - address asset = vm.randomAddress(); - address to = vm.randomAddress(); uint256 amount = 99e6; + res.debt.mint(address(stable4626), amount); + vm.prank(deployer); manager.grantRole(manager.STABLE_ERC4626_INCOME_WITHDRAW_ROLE(), operator); vm.prank(operator); - manager.withdrawIncomeAssets(IStableERC4626For4626(address(stable4626)), asset, to, amount); - - assertTrue(stable4626.withdrawCalled()); - assertEq(stable4626.lastAsset(), asset); - assertEq(stable4626.lastTo(), to); - assertEq(stable4626.lastAmount(), amount); - } + manager.withdrawIncomeAssets(IStableERC4626For4626(address(stable4626)), address(res.debt), operator, amount); + + // Verify the asset was transferred to the recipient + assertEq(res.debt.balanceOf(operator), amount, "Income asset should be transferred to the recipient"); + assertEq( + res.debt.balanceOf(address(stable4626)), + 0, + "The withdrawn amount should be deducted from the vault's balance" + ); - function testWithdrawIncomeAssetsWithoutRole() public { - MockStableERC4626For4626 stable4626 = new MockStableERC4626For4626(); address unauthorized = vm.randomAddress(); vm.startPrank(unauthorized); @@ -903,8 +910,4 @@ contract AccessManagerTestV2 is Test { manager.withdrawIncomeAssets(IStableERC4626For4626(address(stable4626)), address(1), address(2), 1e6); vm.stopPrank(); } - - // Import the events for testing - event RevokePendingMinApy(address indexed caller); - event RevokePendingPool(address indexed caller); } From 080ec32893d1cc9d7244065c57813c17786aa61e Mon Sep 17 00:00:00 2001 From: Evan Date: Thu, 9 Apr 2026 17:59:19 +0800 Subject: [PATCH 20/21] feat: Integrate whitelist checks in MakerHelper --- contracts/v2/router/MakerHelper.sol | 22 ++++++++++--- script/deploy/DeployBaseV2.s.sol | 15 +++++---- test/v2/MakerHelper.t.sol | 51 ++++++++++++++++++++++++++++- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/contracts/v2/router/MakerHelper.sol b/contracts/v2/router/MakerHelper.sol index de04d507..e18e169c 100644 --- a/contracts/v2/router/MakerHelper.sol +++ b/contracts/v2/router/MakerHelper.sol @@ -16,18 +16,23 @@ import {TransferUtilsV2} from "../lib/TransferUtilsV2.sol"; import {IGearingToken} from "../../v1/tokens/IGearingToken.sol"; import {CurveCuts, OrderConfig} from "../../v1/storage/TermMaxStorage.sol"; import {OrderInitialParams} from "../ITermMaxOrderV2.sol"; -import {VersionV2} from "../VersionV2.sol"; +import {VersionV2_0_1} from "../VersionV2_0_1.sol"; import {DelegateAble} from "../lib/DelegateAble.sol"; import {MakerHelperEvents} from "../events/MakerHelperEvents.sol"; import {MakerHelperErrors} from "../errors/MakerHelperErrors.sol"; +import {WithWhitelistCheck, IWhitelistManager} from "../access/WithWhitelistCheck.sol"; /** * @title MakerHelper * @notice Helper contract for placing orders and other operations for the maker in the TermMax protocol */ -contract MakerHelper is UUPSUpgradeable, Ownable2StepUpgradeable, IERC721Receiver, VersionV2 { +contract MakerHelper is UUPSUpgradeable, Ownable2StepUpgradeable, IERC721Receiver, WithWhitelistCheck, VersionV2_0_1 { using TransferUtilsV2 for IERC20; + constructor(address _whitelistManager) + WithWhitelistCheck(_whitelistManager, IWhitelistManager.ContractModule.MARKET) + {} + function _authorizeUpgrade(address newImplementation) internal virtual override onlyOwner {} function initialize(address admin) public initializer { @@ -56,7 +61,7 @@ contract MakerHelper is UUPSUpgradeable, Ownable2StepUpgradeable, IERC721Receive uint128 ftToDeposit, uint128 xtToDeposit, OrderConfig memory orderConfig - ) external returns (ITermMaxOrder order, uint256 gtId) { + ) external onlyWhitelisted(address(market)) returns (ITermMaxOrder order, uint256 gtId) { (IERC20 ft, IERC20 xt, IGearingToken gt, address collateral, IERC20 debtToken) = market.tokens(); if (collateralToMintGt > 0) { IERC20(collateral).safeTransferFrom(msg.sender, address(this), collateralToMintGt); @@ -102,7 +107,16 @@ contract MakerHelper is UUPSUpgradeable, Ownable2StepUpgradeable, IERC721Receive OrderInitialParams memory initialParams, DelegateAble.DelegateParameters memory delegateParams, DelegateAble.Signature memory delegateSignature - ) external returns (ITermMaxOrder, uint256) { + ) external onlyWhitelisted(address(market)) returns (ITermMaxOrder, uint256) { + if (address(initialParams.pool) != address(0)) { + _checkWhitelisted(address(initialParams.pool), IWhitelistManager.ContractModule.POOL); + } + if (address(initialParams.orderConfig.swapTrigger) != address(0)) { + _checkWhitelisted( + address(initialParams.orderConfig.swapTrigger), IWhitelistManager.ContractModule.ORDER_CALLBACK + ); + } + (IERC20 ft, IERC20 xt, IGearingToken gt, address collateral, IERC20 debtToken) = market.tokens(); if (collateralToMintGt > 0) { IERC20(collateral).safeTransferFrom(msg.sender, address(this), collateralToMintGt); diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index a97b630a..e12b1d01 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -345,18 +345,21 @@ contract DeployBaseV2 is Script { router = TermMaxRouterV2(routerProxy); } - function deployMakerHelper(address admin) public returns (MakerHelper makerHelper) { - address implementation = address(new MakerHelper()); - bytes memory data = abi.encodeCall(MakerHelper.initialize, (admin)); + function deployMakerHelper(address accessManager, address whitelistManager) + public + returns (MakerHelper makerHelper) + { + address implementation = address(new MakerHelper(whitelistManager)); + bytes memory data = abi.encodeCall(MakerHelper.initialize, (accessManager)); address proxy = address(new ERC1967Proxy(address(implementation), data)); makerHelper = MakerHelper(proxy); } - function upgradeMakerHelper(AccessManagerV2 manager, address makerHelperProxy) + function upgradeMakerHelper(AccessManagerV2 manager, address makerHelperProxy, address whitelistManager) public returns (MakerHelper makerHelper) { - address implementation = address(new MakerHelper()); + address implementation = address(new MakerHelper(whitelistManager)); bytes memory data = bytes(""); manager.upgradeSubContract(UUPSUpgradeable(makerHelperProxy), address(implementation), data); makerHelper = MakerHelper(makerHelperProxy); @@ -447,7 +450,7 @@ contract DeployBaseV2 is Script { upgradeRouter(contracts.accessManager, address(contracts.router), address(contracts.whitelistManager)); } // deploy maker helper - contracts.makerHelper = deployMakerHelper(address(contracts.accessManager)); + contracts.makerHelper = deployMakerHelper(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy faucet if (address(contracts.faucet) == address(0)) { contracts.faucet = new Faucet(params.deployerAddr); diff --git a/test/v2/MakerHelper.t.sol b/test/v2/MakerHelper.t.sol index b75a7060..c3e3d76e 100644 --- a/test/v2/MakerHelper.t.sol +++ b/test/v2/MakerHelper.t.sol @@ -9,6 +9,7 @@ import {StateChecker} from "./utils/StateChecker.sol"; import {SwapUtils} from "./utils/SwapUtils.sol"; import {LoanUtils} from "./utils/LoanUtils.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -59,6 +60,7 @@ import { import {ITermMaxRouter} from "contracts/v1/router/ITermMaxRouter.sol"; import {MockSwapAdapterV2} from "contracts/v2/test/MockSwapAdapterV2.sol"; import {ITermMaxOrder} from "contracts/v1/ITermMaxOrder.sol"; +import {ITermMaxMarket} from "contracts/v1/ITermMaxMarket.sol"; import {TermMaxSwapData, TermMaxSwapAdapter} from "contracts/v2/router/swapAdapters/TermMaxSwapAdapter.sol"; import {TermMaxOrderV2, OrderInitialParams} from "contracts/v2/TermMaxOrderV2.sol"; import {MakerHelper, MakerHelperErrors} from "contracts/v2/router/MakerHelper.sol"; @@ -124,7 +126,7 @@ contract MakerHelperTest is Test { res.ft.transfer(address(res.order), amount); res.xt.transfer(address(res.order), amount); - address implementation = address(new MakerHelper()); + address implementation = address(new MakerHelper(address(res.whitelistManager))); bytes memory data = abi.encodeCall(MakerHelper.initialize, deployer); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); makerHelper = MakerHelper(address(proxy)); @@ -204,6 +206,53 @@ contract MakerHelperTest is Test { vm.stopPrank(); } + function testPlaceOrderForV1RevertIfMarketNotWhitelisted() public { + vm.startPrank(sender); + + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + makerHelper.placeOrderForV1(ITermMaxMarket(vm.randomAddress()), sender, 0, 0, 0, 0, orderConfig); + + vm.stopPrank(); + } + + function testPlaceOrderForV2RevertIfPoolNotWhitelisted(uint256 salt) public { + vm.startPrank(sender); + + OrderInitialParams memory initialParams; + initialParams.maker = sender; + initialParams.orderConfig = orderConfig; + initialParams.orderConfig.gtId = 1; + initialParams.virtualXtReserve = 1e8; + initialParams.pool = IERC4626(vm.randomAddress()); + + DelegateAble.DelegateParameters memory delegateParams; + DelegateAble.Signature memory delegateSignature; + + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + makerHelper.placeOrderForV2(res.market, salt, 0, 0, 0, 0, initialParams, delegateParams, delegateSignature); + + vm.stopPrank(); + } + + function testPlaceOrderForV2RevertIfSwapTriggerNotWhitelisted(uint256 salt) public { + vm.startPrank(sender); + + OrderInitialParams memory initialParams; + initialParams.maker = sender; + initialParams.orderConfig = orderConfig; + initialParams.orderConfig.gtId = 1; + initialParams.orderConfig.swapTrigger = ISwapCallback(vm.randomAddress()); + initialParams.virtualXtReserve = 1e8; + + DelegateAble.DelegateParameters memory delegateParams; + DelegateAble.Signature memory delegateSignature; + + vm.expectRevert(abi.encodeWithSignature("TargetNotWhitelisted()")); + makerHelper.placeOrderForV2(res.market, salt, 0, 0, 0, 0, initialParams, delegateParams, delegateSignature); + + vm.stopPrank(); + } + function testPlaceOrderForV2AndDelegateWithSignature(uint256 salt) public { // Set up delegator and delegatee uint256 delegatorPrivateKey = 0x1234567890123456789012345678901234567890123456789012345678901234; From c08bb0f2412d158a3b5145f26a6e9f966f7c02e0 Mon Sep 17 00:00:00 2001 From: Evan Date: Tue, 14 Apr 2026 09:51:20 +0800 Subject: [PATCH 21/21] merge scripts from v2/deployment --- contracts/v2/factory/TermMaxFactoryV2.sol | 8 +- script/LiquidateLoanBatch.s.sol | 154 ++++++++ script/PlaceB2Order.s.sol | 172 +++++++++ script/UpdateAlphaFeeConfig.s.sol | 128 +++++++ script/UpdateTreasurer.s.sol | 94 +++++ script/deploy/DeployAllAdapter.s.sol | 331 ++++++++++++++++++ script/deploy/DeployB2BTCUSDOracle.s.sol | 123 +++++++ script/deploy/DeployBaseV2.s.sol | 133 ++++++- .../DeployBeefySharePriceFeedAdapter.s.sol | 180 ++++++++++ script/deploy/DeployCoreV2.s.sol | 4 +- .../deploy/DeployDUSDPriceFeedAdapter.s.sol | 146 ++++++++ script/deploy/DeployMakerHelper.s.sol | 103 ++++++ script/deploy/DeployMarkets.s.sol | 3 +- .../deploy/DeployMidasVaultSwapAdapter.s.sol | 134 +++++++ .../DeployOndoPriceFeedAdapterFactory.s.sol | 122 +++++++ script/deploy/DeployOracleAggregatorV2.s.sol | 126 +++++++ script/deploy/DeployOtherPool.s.sol | 184 ---------- ...pter.s.sol => DeployPTReUSDeAdapter.s.sol} | 20 +- script/deploy/DeployPancakeOracle.s.sol | 15 +- script/deploy/DeployPreTMX.s.sol | 103 ++++++ script/deploy/DeployPriceFeedFactory.s.sol | 98 ++++++ script/deploy/DeployTermMaxViewer.s.sol | 99 ++++++ .../deploy/DeployUSPCPriceFeedAdapter.s.sol | 146 ++++++++ script/deploy/DeployUniswapPriceFeed.s.sol | 158 +++++++++ script/deploy/DeployVault.s.sol | 8 +- script/deploy/DeployWhitelistFeature.s.sol | 283 +++++++++++++++ script/deploy/PlaceOrder.s.sol | 157 +++++++++ script/deploy/UpdateTreasurer.s.sol | 88 ----- script/utils/JsonLoader.sol | 42 +++ script/utils/StringHelper.sol | 19 + 30 files changed, 3071 insertions(+), 310 deletions(-) create mode 100644 script/LiquidateLoanBatch.s.sol create mode 100644 script/PlaceB2Order.s.sol create mode 100644 script/UpdateAlphaFeeConfig.s.sol create mode 100644 script/UpdateTreasurer.s.sol create mode 100644 script/deploy/DeployAllAdapter.s.sol create mode 100644 script/deploy/DeployB2BTCUSDOracle.s.sol create mode 100644 script/deploy/DeployBeefySharePriceFeedAdapter.s.sol create mode 100644 script/deploy/DeployDUSDPriceFeedAdapter.s.sol create mode 100644 script/deploy/DeployMakerHelper.s.sol create mode 100644 script/deploy/DeployMidasVaultSwapAdapter.s.sol create mode 100644 script/deploy/DeployOndoPriceFeedAdapterFactory.s.sol create mode 100644 script/deploy/DeployOracleAggregatorV2.s.sol delete mode 100644 script/deploy/DeployOtherPool.s.sol rename script/deploy/{DeploySrUSDeAdapter.s.sol => DeployPTReUSDeAdapter.s.sol} (88%) create mode 100644 script/deploy/DeployPreTMX.s.sol create mode 100644 script/deploy/DeployPriceFeedFactory.s.sol create mode 100644 script/deploy/DeployTermMaxViewer.s.sol create mode 100644 script/deploy/DeployUSPCPriceFeedAdapter.s.sol create mode 100644 script/deploy/DeployUniswapPriceFeed.s.sol create mode 100644 script/deploy/DeployWhitelistFeature.s.sol create mode 100644 script/deploy/PlaceOrder.s.sol delete mode 100644 script/deploy/UpdateTreasurer.s.sol diff --git a/contracts/v2/factory/TermMaxFactoryV2.sol b/contracts/v2/factory/TermMaxFactoryV2.sol index 949aa27b..b01b05d9 100644 --- a/contracts/v2/factory/TermMaxFactoryV2.sol +++ b/contracts/v2/factory/TermMaxFactoryV2.sol @@ -20,7 +20,13 @@ import {VersionV2_0_1} from "../VersionV2_0_1.sol"; * @dev Manages market deployment, gearing token implementations, and market configuration validation * Inherits from V1 factory interface while adding V2-specific features for improved market creation */ -contract TermMaxFactoryV2 is ITermMaxFactory, FactoryEventsV2, VersionV2_0_1, WithWhitelistCheck, WithAccessManagerRole { +contract TermMaxFactoryV2 is + ITermMaxFactory, + FactoryEventsV2, + VersionV2_0_1, + WithWhitelistCheck, + WithAccessManagerRole +{ /// @notice Constant key for the default ERC20 gearing token implementation bytes32 constant GT_ERC20 = keccak256("GearingTokenWithERC20"); diff --git a/script/LiquidateLoanBatch.s.sol b/script/LiquidateLoanBatch.s.sol new file mode 100644 index 00000000..0e900f49 --- /dev/null +++ b/script/LiquidateLoanBatch.s.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {console2} from "forge-std/console2.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface ITermMaxMarketLike { + function tokens() + external + view + returns (address ft, address xt, address gt, address collateral, address underlying); +} + +interface IGearingTokenLike { + function loanInfo(uint256 id) external view returns (address owner, uint128 debtAmt, bytes memory collateralData); + function getLiquidationInfo(uint256 id) + external + view + returns (bool isLiquidable, uint128 ltv, uint128 maxRepayAmt); + function liquidate(uint256 id, uint128 repayAmt, bool byDebtToken) external; +} + +contract LiquidateLoanBatch is Script { + uint256 deployerPrivateKey; + address liquidator; + + struct LoanTask { + address marketAddress; + uint256 loanId; + } + + function setUp() public { + string memory network = vm.envString("NETWORK"); + string memory networkUpper = _networkToEnvPrefix(network); + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + liquidator = vm.addr(deployerPrivateKey); + } + + function run() external { + LoanTask[] memory tasks = _buildLoanTasks(); + + console2.log("Total tasks:", tasks.length); + console2.log("Liquidator:", liquidator); + + vm.startBroadcast(deployerPrivateKey); + + uint256 successCount = 0; + uint256 skippedCount = 0; + + for (uint256 i = 0; i < tasks.length; i++) { + LoanTask memory task = tasks[i]; + console2.log("=============================="); + console2.log("Task index:", i); + console2.log("Market:", task.marketAddress); + console2.log("LoanId:", task.loanId); + + (,, address marketGt,, address underlying) = ITermMaxMarketLike(task.marketAddress).tokens(); + + address actualOwner; + uint128 debtAmt; + try IGearingTokenLike(marketGt).loanInfo(task.loanId) returns ( + address owner, uint128 onchainDebtAmt, bytes memory + ) { + actualOwner = owner; + debtAmt = onchainDebtAmt; + } catch { + console2.log("Skip: loanInfo reverted"); + skippedCount++; + continue; + } + + if (debtAmt == 0) { + console2.log("Skip: debt already zero"); + skippedCount++; + continue; + } + + bool isLiquidable; + uint128 maxRepayAmtNow; + try IGearingTokenLike(marketGt).getLiquidationInfo(task.loanId) returns ( + bool liquidable, uint128, uint128 maxRepayAmt + ) { + isLiquidable = liquidable; + maxRepayAmtNow = maxRepayAmt; + } catch { + console2.log("Skip: getLiquidationInfo reverted"); + skippedCount++; + continue; + } + + if (!isLiquidable || maxRepayAmtNow == 0) { + console2.log("Skip: no longer liquidable"); + skippedCount++; + continue; + } + + uint128 repayAmt = uint128(maxRepayAmtNow); + uint256 bal = IERC20(underlying).balanceOf(liquidator); + if (bal < repayAmt) { + console2.log("Skip: insufficient debt token balance"); + console2.log("Underlying:", underlying); + console2.log("Need:", repayAmt); + console2.log("Have:", bal); + skippedCount++; + continue; + } + + uint256 allowance = IERC20(underlying).allowance(liquidator, marketGt); + if (allowance < repayAmt) { + IERC20(underlying).approve(marketGt, type(uint256).max); + } + + try IGearingTokenLike(marketGt).liquidate(task.loanId, repayAmt, true) { + console2.log("Success: liquidated loan"); + console2.log("RepayAmt:", repayAmt); + successCount++; + } catch { + console2.log("Failed: liquidate reverted"); + skippedCount++; + } + } + + vm.stopBroadcast(); + + console2.log("=============================="); + console2.log("Liquidation finished"); + console2.log("Success:", successCount); + console2.log("Skipped/Failed:", skippedCount); + } + + function _networkToEnvPrefix(string memory str) internal pure returns (string memory) { + bytes memory b = bytes(str); + for (uint256 i = 0; i < b.length; i++) { + uint8 c = uint8(b[i]); + if (c >= 97 && c <= 122) { + b[i] = bytes1(c - 32); + } else if (c == 45) { + b[i] = bytes1(uint8(95)); + } + } + return string(b); + } + + function _buildLoanTasks() internal pure returns (LoanTask[] memory tasks) { + tasks = new LoanTask[](10); + + for (uint256 i = 0; i < 10; i++) { + tasks[i] = LoanTask({marketAddress: 0x47ae790a999263bF8F3ED95eAD318d6397036D39, loanId: 2 + i}); + } + } +} diff --git a/script/PlaceB2Order.s.sol b/script/PlaceB2Order.s.sol new file mode 100644 index 00000000..a02083cf --- /dev/null +++ b/script/PlaceB2Order.s.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./deploy/DeployBaseV2.s.sol"; +import {DelegateAble} from "contracts/v2/lib/DelegateAble.sol"; +import {CurveCuts, CurveCut, OrderConfig} from "contracts/v1/storage/TermMaxStorage.sol"; +import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; +import {ITermMaxOrder, ITermMaxMarket} from "contracts/v1/ITermMaxOrder.sol"; +import {IGearingToken} from "contracts/v1/tokens/IGearingToken.sol"; + +interface IWBTC { + function deposit() external payable; + function withdraw(uint256 wad) external; +} + +contract PlaceOrder is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + uint256 salt = 0; + uint256 collateralToMintGt = 0.0001e18; + uint256 debtTokenToDeposit = 0; + uint128 ftToDeposit = 0; + uint128 xtToDeposit = 0; + address marketAddr = 0x5022B6563f6bc9f0D47F407ba32B64e1f438213a; + IWBTC wbtc = IWBTC(0x4200000000000000000000000000000000000006); + IERC20 uBTC = IERC20(0x796e4D53067FF374B89b2Ac101ce0c1f72ccaAc2); + address gt = 0xDfB3959DAD26dFce3E9646c92b086E7fe4D12793; + + function exe() internal { + uBTC.approve(address(coreContracts.makerHelper), collateralToMintGt); + OrderInitialParams memory initialParams; + + initialParams.maker = coreParams.deployerAddr; + initialParams.virtualXtReserve = 0; + initialParams.orderConfig.maxXtReserve = 1e18; + initialParams.orderConfig.curveCuts.borrowCurveCuts = new CurveCut[](1); + initialParams.orderConfig.curveCuts.borrowCurveCuts[0] = CurveCut({ + liqSquare: 40000060000017500001000000000000000000000, + xtReserve: 0, + offset: 2000000499999875000100 + }); + + DelegateAble.DelegateParameters memory delegateParams; + address orderAddr = ITermMaxMarketV2(marketAddr).predictOrderAddress(initialParams, salt); + console.log("Predicted order address:", orderAddr); + delegateParams = DelegateAble.DelegateParameters({ + delegator: coreParams.deployerAddr, + delegatee: orderAddr, + isDelegate: true, + nonce: 0, + deadline: block.timestamp + 1 hours + }); + + DelegateAble.Signature memory delegateSignature = generateSignature( + DelegateAble(gt), // placeholder, will be replaced in the function call + deployerPrivateKey, + delegateParams + ); + + (ITermMaxOrder order, uint256 gtId) = coreContracts.makerHelper.placeOrderForV2( + ITermMaxMarket(marketAddr), + salt, + collateralToMintGt, + debtTokenToDeposit, + ftToDeposit, + xtToDeposit, + initialParams, + delegateParams, + delegateSignature + ); + console.log("Order created at address:", address(order)); + console.log("Minted GT ID:", gtId); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + exe(); + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + } + + function generateSignature( + DelegateAble delegateableGt, + uint256 delegatorPrivateKey, + DelegateAble.DelegateParameters memory params + ) public view returns (DelegateAble.Signature memory signature) { + // Create signature + bytes32 domainSeparator = delegateableGt.DOMAIN_SEPARATOR(); + bytes32 structHash = keccak256( + abi.encode( + keccak256( + "DelegationWithSig(address delegator,address delegatee,bool isDelegate,uint256 nonce,uint256 deadline)" + ), + params.delegator, + params.delegatee, + params.isDelegate, + params.nonce, + params.deadline + ) + ); + bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(delegatorPrivateKey, digest); + signature = DelegateAble.Signature({v: v, r: r, s: s}); + } +} diff --git a/script/UpdateAlphaFeeConfig.s.sol b/script/UpdateAlphaFeeConfig.s.sol new file mode 100644 index 00000000..55b4936f --- /dev/null +++ b/script/UpdateAlphaFeeConfig.s.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./deploy/DeployBaseV2.s.sol"; + +contract UpdateAlphaFeeConfig is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + address[] alphaMarkets; + + FeeConfig alphaFeeConfig; + uint32 mintGtFeeRatio = 0.1e8; + uint32 mintGtFeeRef = 5e8; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + + // Define alpha markets to update + // Read markets from JSON file + string memory marketsPath = string.concat( + vm.projectRoot(), "/script/deploy/deploydata/", coreParams.network, "-alpha-market-addresses.json" + ); + if (vm.exists(marketsPath)) { + string memory marketsJson = vm.readFile(marketsPath); + + // Read alpha markets + uint256 alphaTotal = vm.parseJsonUint(marketsJson, ".total"); + for (uint256 i = 0; i < alphaTotal; i++) { + string memory key = string.concat(".market_", vm.toString(i), ".address"); + address marketAddr = vm.parseJsonAddress(marketsJson, key); + alphaMarkets.push(marketAddr); + } + console.log("Loaded", alphaMarkets.length, "alpha markets from JSON"); + } else { + console.log("Markets JSON file not found:", marketsPath); + } + alphaFeeConfig.mintGtFeeRatio = mintGtFeeRatio; + alphaFeeConfig.mintGtFeeRef = mintGtFeeRef; + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + + // Update stable markets fee config + console.log("Updating fee config for", alphaMarkets.length, "alpha markets"); + for (uint256 i = 0; i < alphaMarkets.length; i++) { + address market = alphaMarkets[i]; + console.log("Update alpha market:", market); + MarketConfig memory config = TermMaxMarketV2(market).config(); + // check current fee config equals alphaFeeConfig to avoid unnecessary updates + if (areFeeConfigsEqual(config.feeConfig, alphaFeeConfig)) { + console.log("Fee config already up to date, skipping"); + continue; + } + config.feeConfig = alphaFeeConfig; + coreContracts.accessManager.updateMarketConfig(TermMaxMarketV2(market), config); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + } + + function areFeeConfigsEqual(FeeConfig memory a, FeeConfig memory b) internal pure returns (bool) { + return keccak256(abi.encode(a)) == keccak256(abi.encode(b)); + } +} diff --git a/script/UpdateTreasurer.s.sol b/script/UpdateTreasurer.s.sol new file mode 100644 index 00000000..7ae20c80 --- /dev/null +++ b/script/UpdateTreasurer.s.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./deploy/DeployBaseV2.s.sol"; + +contract UpdateTreasurer is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + address newTreasurer = 0x70e992E94474e4E9B2D964F6876c05cDE45f8E89; + address market = 0x39256Ad46B721F47d48D1e0918a986cAc0c210ed; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + console.log("Updating treasurer for market:", market); + MarketConfig memory config = TermMaxMarketV2(market).config(); + console.log("Current treasurer:", config.treasurer); + config.treasurer = newTreasurer; + coreContracts.accessManager.updateMarketConfig(TermMaxMarketV2(market), config); + console.log("Updated treasurer to:", newTreasurer); + config = TermMaxMarketV2(market).config(); + require(config.treasurer == newTreasurer, "Treasurer update failed"); + console.log("New treasurer from market config:", config.treasurer); + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + } +} diff --git a/script/deploy/DeployAllAdapter.s.sol b/script/deploy/DeployAllAdapter.s.sol new file mode 100644 index 00000000..829a68df --- /dev/null +++ b/script/deploy/DeployAllAdapter.s.sol @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {DeployBaseV2, AccessManagerV2, UUPSUpgradeable} from "./DeployBaseV2.s.sol"; +import {TermMaxRouter} from "contracts/v1/router/TermMaxRouter.sol"; +import {TermMaxRouterV2} from "contracts/v2/router/TermMaxRouterV2.sol"; +import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {KodiakSwapAdapter} from "contracts/v2/router/swapAdapters/KodiakSwapAdapter.sol"; +import {LifiSwapAdapter} from "contracts/v2/router/swapAdapters/LifiSwapAdapter.sol"; +import {OdosV2AdapterV2} from "contracts/v2/router/swapAdapters/OdosV2AdapterV2.sol"; +import {OkxSwapAdapter} from "contracts/v2/router/swapAdapters/OkxSwapAdapter.sol"; +import {OndoSwapAdapter} from "contracts/v2/router/swapAdapters/OndoSwapAdapter.sol"; +import {OneInchSwapAdapter} from "contracts/v2/router/swapAdapters/OneInchSwapAdapter.sol"; +import {PancakeSmartAdapter} from "contracts/v2/router/swapAdapters/PancakeSmartAdapter.sol"; +import {PendleSwapV3AdapterV2} from "contracts/v2/router/swapAdapters/PendleSwapV3AdapterV2.sol"; +import {TermMaxSwapAdapter} from "contracts/v2/router/swapAdapters/TermMaxSwapAdapter.sol"; +import {UniswapV3AdapterV2} from "contracts/v2/router/swapAdapters/UniswapV3AdapterV2.sol"; +import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; + +contract DeployAllAdapter is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + string[] adapterNames; + address[] adapters; + string adaptersJson; + bool isBroadcast = vm.envBool("IS_BROADCAST"); + + string deploymentPath; + + address ondoGmTokenManager; + address lifiRouter; + address odosV2Router; + address pendleRouter; + address oneInchRouter; + address pancakeRouter; + + bool isEth; + bool isArb; + bool isBnb; + bool isBera; + bool isHyper; + bool isXlayer; + bool isBase; + bool isB2; + bool isPharos; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + _getNetWork(); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + { + ondoGmTokenManager = vm.envOr(string.concat(networkUpper, "_ONDO_GM_MANAGER_ADDRESS"), address(0)); + console.log("Ondo GM Token Manager address:", ondoGmTokenManager); + lifiRouter = vm.envOr(string.concat(networkUpper, "_LIFI_ROUTER_ADDRESS"), address(0)); + console.log("Lifi router address:", lifiRouter); + odosV2Router = vm.envOr(string.concat(networkUpper, "_ODOS_V2_ROUTER_ADDRESS"), address(0)); + console.log("Odos V2 router address:", odosV2Router); + pendleRouter = vm.envOr(string.concat(networkUpper, "_PENDLE_SWAP_V3_ROUTER_ADDRESS"), address(0)); + console.log("Pendle Swap V3 router address:", pendleRouter); + pancakeRouter = vm.envOr(string.concat(networkUpper, "_PANCAKE_ROUTER_ADDRESS"), address(0)); + console.log("Pancake router address:", pancakeRouter); + oneInchRouter = vm.envOr(string.concat(networkUpper, "_ONE_INCH_ROUTER_ADDRESS"), address(0)); + console.log("1inch router address:", oneInchRouter); + } + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + + deploymentPath = + string.concat(vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core.json"); + + console.log("Using existing RouterV1 at:", address(coreContracts.routerV1)); + console.log("Using existing RouterV2 at:", address(coreContracts.router)); + + coreParams.adminAddr = adminAddr; + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + { + // termmax swap adapter + TermMaxSwapAdapter termMaxSwapAdapter = new TermMaxSwapAdapter(address(coreContracts.whitelistManager)); + coreContracts.termMaxSwapAdapter = termMaxSwapAdapter; + console.log("termMaxSwapAdapter deploy at:", address(termMaxSwapAdapter)); + adapters.push(address(termMaxSwapAdapter)); + adapterNames.push("termMaxSwapAdapter"); + + // erc4626 vault adapter + ERC4626VaultAdapterV2 erc4626Adapter = new ERC4626VaultAdapterV2(); + coreContracts.vaultAdapter = erc4626Adapter; + console.log("ERC4626VaultAdapterV2 deploy at:", address(erc4626Adapter)); + adapters.push(address(erc4626Adapter)); + adapterNames.push("erc4626VaultAdapterV2"); + + // kodiak swap adapter + if (isBera) { + KodiakSwapAdapter kodiakAdapter = new KodiakSwapAdapter(); + console.log("KodiakSwapAdapter deploy at:", address(kodiakAdapter)); + adapters.push(address(kodiakAdapter)); + adapterNames.push("kodiakSwapAdapter"); + } + + // lifi swap adapter + if (isEth || isArb || isBnb || isBase) { + require(lifiRouter != address(0), "Lifi router address is not set for this network"); + LifiSwapAdapter lifiAdapter = new LifiSwapAdapter(lifiRouter); + console.log("LifiSwapAdapter deploy at:", address(lifiAdapter)); + adapters.push(address(lifiAdapter)); + adapterNames.push("lifiSwapAdapter"); + } + + // odos v2 adapter + if (isEth || isArb || isBnb || isBase) { + require(odosV2Router != address(0), "Odos V2 router address is not set for this network"); + OdosV2AdapterV2 odosAdapter = new OdosV2AdapterV2(odosV2Router); + coreContracts.odosV2Adapter = odosAdapter; + console.log("OdosV2AdapterV2 deploy at:", address(odosAdapter)); + adapters.push(address(odosAdapter)); + adapterNames.push("odosV2AdapterV2"); + } + + // okx swap adapter + if (isEth || isArb || isBnb || isBase || isXlayer) { + OkxSwapAdapter okxAdapter = new OkxSwapAdapter(); + console.log("OkxSwapAdapter deploy at:", address(okxAdapter)); + adapters.push(address(okxAdapter)); + adapterNames.push("okxSwapAdapter"); + } + + // ondo swap adapter + if (isEth || isBnb) { + require(ondoGmTokenManager != address(0), "Ondo GM Token Manager address is not set for this network"); + OndoSwapAdapter ondoAdapter = new OndoSwapAdapter(ondoGmTokenManager); + console.log("OndoSwapAdapter deploy at:", address(ondoAdapter)); + adapters.push(address(ondoAdapter)); + adapterNames.push("ondoSwapAdapter"); + } + // one inch swap adapter + if (isEth || isArb || isBnb || isBase) { + require(oneInchRouter != address(0), "1inch router address is not set for this network"); + OneInchSwapAdapter oneInchAdapter = new OneInchSwapAdapter(oneInchRouter); + console.log("OneInchSwapAdapter deploy at:", address(oneInchAdapter)); + adapters.push(address(oneInchAdapter)); + adapterNames.push("oneInchSwapAdapter"); + } + + // pancake smart adapter + if (isEth || isBnb) { + require(pancakeRouter != address(0), "Pancake router address is not set for this network"); + PancakeSmartAdapter pancakeAdapter = new PancakeSmartAdapter(pancakeRouter); + console.log("PancakeSmartAdapter deploy at:", address(pancakeAdapter)); + adapters.push(address(pancakeAdapter)); + adapterNames.push("pancakeSmartAdapter"); + } + + // pendle swap v3 adapter + if (isEth || isArb || isBnb || isBase || isHyper || isBera) { + require(pendleRouter != address(0), "Pendle router address is not set for this network"); + PendleSwapV3AdapterV2 pendleAdapter = new PendleSwapV3AdapterV2(pendleRouter); + coreContracts.pendleSwapV3Adapter = pendleAdapter; + console.log("PendleSwapV3AdapterV2 deploy at:", address(pendleAdapter)); + adapters.push(address(pendleAdapter)); + adapterNames.push("pendleSwapV3AdapterV2"); + } + + // uniswap v3 adapter only for b2 network + if (isB2) { + UniswapV3AdapterV2 uniswapV3Adapter = new UniswapV3AdapterV2(); + coreContracts.uniswapV3Adapter = uniswapV3Adapter; + console.log("UniswapV3AdapterV2 deploy at:", address(uniswapV3Adapter)); + adapters.push(address(uniswapV3Adapter)); + adapterNames.push("uniswapV3AdapterV2"); + } + } + + console.log("Whitelist adapters in AccessManagerV2"); + + adaptersJson = "[\n"; + for (uint256 i = 0; i < adapters.length; i++) { + adaptersJson = string.concat( + adaptersJson, + " {\n", + ' "name": "', + adapterNames[i], + '",\n', + ' "address": "', + vm.toString(adapters[i]), + '"\n', + " }" + ); + if (i != adapters.length - 1) { + adaptersJson = string.concat(adaptersJson, ",\n"); + } else { + adaptersJson = string.concat(adaptersJson, "\n"); + } + coreContracts.accessManager.setAdapterWhitelist( + TermMaxRouter(address(coreContracts.routerV1)), adapters[i], true + ); + } + adaptersJson = string.concat(adaptersJson, " ]"); + coreContracts.accessManager.batchSetWhitelist( + coreContracts.whitelistManager, adapters, IWhitelistManager.ContractModule.ADAPTER, true + ); + + console.log("All adapters whitelisted in AccessManagerV2"); + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + + string memory deploymentJson = string( + abi.encodePacked( + "{\n", + ' "network": "', + coreParams.network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + getGitBranch(), + '",\n', + ' "gitCommitHash": "', + vm.toString(getGitCommitHash()), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "contracts": {\n', + ' "routerV1": "', + vm.toString(address(coreContracts.routerV1)), + '",\n', + ' "router": "', + vm.toString(address(coreContracts.router)), + '",\n', + ' "accessManager": "', + vm.toString(address(coreContracts.accessManager)), + '",\n', + ' "adapters": ', + adaptersJson, + "\n }\n", + "}" + ) + ); + string memory path = + string.concat(vm.projectRoot(), "/deployments/", coreParams.network, "/", "all-adapters", ".json"); + + vm.writeFile(path, deploymentJson); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + writeAsJson(deploymentPath, coreParams, coreContracts); + } + + function _getNetWork() internal { + isEth = keccak256(bytes(coreParams.network)) == keccak256(bytes("eth-mainnet")); + isArb = keccak256(bytes(coreParams.network)) == keccak256(bytes("arb-mainnet")); + isBnb = keccak256(bytes(coreParams.network)) == keccak256(bytes("bnb-mainnet")); + isBera = keccak256(bytes(coreParams.network)) == keccak256(bytes("bera-mainnet")); + isHyper = keccak256(bytes(coreParams.network)) == keccak256(bytes("hyperevm-mainnet")); + isXlayer = keccak256(bytes(coreParams.network)) == keccak256(bytes("xlayer-mainnet")); + isBase = keccak256(bytes(coreParams.network)) == keccak256(bytes("base-mainnet")); + isB2 = keccak256(bytes(coreParams.network)) == keccak256(bytes("b2-mainnet")); + isPharos = keccak256(bytes(coreParams.network)) == keccak256(bytes("pharos-mainnet")); + } +} diff --git a/script/deploy/DeployB2BTCUSDOracle.s.sol b/script/deploy/DeployB2BTCUSDOracle.s.sol new file mode 100644 index 00000000..613271f7 --- /dev/null +++ b/script/deploy/DeployB2BTCUSDOracle.s.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {console} from "forge-std/console.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; +import {TermMaxB2TokenPriceFeedAdapter} from "contracts/v2/oracle/adapters/b2/TermMaxB2TokenPriceFeedAdapter.sol"; + +/** + * @title DeployB2BTCUSDOracle + * @notice Deploy script for TermMax B2 BTC/USD oracle adapter + * @dev Deploys TermMaxB2TokenPriceFeedAdapter with fixed BTC/USD pair settings + */ +contract DeployB2BTCUSDOracle is DeployBaseV2 { + uint256 internal constant BTC_USD_INDEX = 18; + address internal constant SUPRA_SVALUE_FEED = 0xD02cc7a670047b6b012556A88e275c685d25e0c9; + + string internal network; + address internal deployerAddr; + uint256 internal deployerPrivateKey; + + function setUp() public { + network = vm.envOr("NETWORK", string("b2-mainnet")); + string memory networkUpper = StringHelper.toUpper(network); + + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + deployerPrivateKey = vm.envUint(privateKeyVar); + deployerAddr = vm.addr(deployerPrivateKey); + + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", network); + if (!vm.exists(deploymentsDir)) { + vm.createDir(deploymentsDir, true); + } + + console.log("===== Deployment Configuration ====="); + console.log("Network:", network); + console.log("Deployer:", deployerAddr); + console.log("Deployer balance:", deployerAddr.balance); + console.log("BTC/USD index:", BTC_USD_INDEX); + console.log("Supra value feed:", SUPRA_SVALUE_FEED); + } + + function run() public { + vm.startBroadcast(deployerPrivateKey); + + TermMaxB2TokenPriceFeedAdapter adapter = new TermMaxB2TokenPriceFeedAdapter(BTC_USD_INDEX, SUPRA_SVALUE_FEED); + + vm.stopBroadcast(); + + console.log("\n===== Deployment Successful ====="); + console.log("TermMaxB2TokenPriceFeedAdapter deployed at:", address(adapter)); + + (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + adapter.latestRoundData(); + + console.log("\n===== Oracle Data ====="); + console.log("Decimals:", adapter.decimals()); + console.log("Description:", adapter.description()); + console.log("Round ID:", roundId); + console.log("BTC/USD Price:", answer); + console.log("Started At (sec):", startedAt); + console.log("Updated At (sec):", updatedAt); + console.log("Answered In Round:", answeredInRound); + + _saveDeploymentInfo(address(adapter)); + } + + function _saveDeploymentInfo(address adapterAddress) internal { + string memory json = string( + abi.encodePacked( + "{\n", + ' "network": "', + network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + getGitBranch(), + '",\n', + ' "gitCommitHash": "', + vm.toString(getGitCommitHash()), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "deployer": "', + vm.toString(deployerAddr), + '",\n', + ' "contracts": {\n', + ' "termMaxB2BTCUSDOracle": "', + vm.toString(adapterAddress), + '",\n', + ' "supraSValueFeed": "', + vm.toString(SUPRA_SVALUE_FEED), + '",\n', + ' "pairIndex": "', + vm.toString(BTC_USD_INDEX), + '"\n', + " }\n", + "}" + ) + ); + + string memory jsonPath = string.concat( + vm.projectRoot(), + "/deployments/", + network, + "/", + network, + "-b2-btc-usd-oracle-", + vm.toString(block.timestamp), + ".json" + ); + vm.writeFile(jsonPath, json); + console.log("Deployment info saved to:", jsonPath); + } +} diff --git a/script/deploy/DeployBaseV2.s.sol b/script/deploy/DeployBaseV2.s.sol index e12b1d01..483d605d 100644 --- a/script/deploy/DeployBaseV2.s.sol +++ b/script/deploy/DeployBaseV2.s.sol @@ -10,6 +10,7 @@ import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IER import {AggregatorV3Interface} from "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; import {TermMaxFactoryV2, ITermMaxFactory} from "contracts/v2/factory/TermMaxFactoryV2.sol"; import {TermMaxRouterV2} from "contracts/v2/router/TermMaxRouterV2.sol"; +import {TermMaxRouter_V1_1_2} from "contracts/v1/router/TermMaxRouter_V1_1_2.sol"; import {MakerHelper} from "contracts/v2/router/MakerHelper.sol"; import {MarketViewer} from "contracts/v1/router/MarketViewer.sol"; import {ITermMaxRouter} from "contracts/v1/router/ITermMaxRouter.sol"; @@ -55,6 +56,7 @@ import { StableERC4626ForVenus, StableERC4626ForCustomize } from "contracts/v2/factory/TermMax4626Factory.sol"; +import {TermMaxViewer} from "contracts/v2/router/TermMaxViewer.sol"; contract DeployBaseV2 is Script { struct DeployedContracts { @@ -62,6 +64,8 @@ contract DeployBaseV2 is Script { WhitelistManager whitelistManager; TermMaxFactoryV2 factory; TermMaxVaultFactoryV2 vaultFactory; + TermMaxFactoryV2 alphaFactory; + TermMaxVaultFactoryV2 alphaVaultFactory; TermMaxPriceFeedFactoryV2 priceFeedFactory; TermMax4626Factory tmx4626Factory; IOracle oracle; @@ -76,6 +80,8 @@ contract DeployBaseV2 is Script { ERC4626VaultAdapterV2 vaultAdapter; TermMaxSwapAdapter termMaxSwapAdapter; TerminalVaultAdapter terminalVaultAdapter; + TermMaxViewer termMaxViewer; + TermMaxRouter_V1_1_2 routerV1; } struct CoreParams { @@ -110,6 +116,13 @@ contract DeployBaseV2 is Script { if (vm.keyExistsJson(json, ".contracts.vaultFactoryV2")) { contracts.vaultFactory = TermMaxVaultFactoryV2(vm.parseJsonAddress(json, ".contracts.vaultFactoryV2")); } + if (vm.keyExistsJson(json, ".contracts.alphaFactory")) { + contracts.alphaFactory = TermMaxFactoryV2(vm.parseJsonAddress(json, ".contracts.alphaFactory")); + } + if (vm.keyExistsJson(json, ".contracts.alphaVaultFactory")) { + contracts.alphaVaultFactory = + TermMaxVaultFactoryV2(vm.parseJsonAddress(json, ".contracts.alphaVaultFactory")); + } if (vm.keyExistsJson(json, ".contracts.priceFeedFactoryV2")) { contracts.priceFeedFactory = TermMaxPriceFeedFactoryV2(vm.parseJsonAddress(json, ".contracts.priceFeedFactoryV2")); @@ -120,6 +133,9 @@ contract DeployBaseV2 is Script { if (vm.keyExistsJson(json, ".contracts.oracleAggregatorV2")) { contracts.oracle = IOracle(vm.parseJsonAddress(json, ".contracts.oracleAggregatorV2")); } + if (vm.keyExistsJson(json, ".contracts.routerV1")) { + contracts.routerV1 = TermMaxRouter_V1_1_2(vm.parseJsonAddress(json, ".contracts.routerV1")); + } if (vm.keyExistsJson(json, ".contracts.routerV2")) { contracts.router = TermMaxRouterV2(vm.parseJsonAddress(json, ".contracts.routerV2")); } @@ -159,6 +175,9 @@ contract DeployBaseV2 is Script { contracts.terminalVaultAdapter = TerminalVaultAdapter(vm.parseJsonAddress(json, ".contracts.swapAdapterV2.terminalVaultAdapter")); } + if (vm.keyExistsJson(json, ".contracts.termMaxViewer")) { + contracts.termMaxViewer = TermMaxViewer(vm.parseJsonAddress(json, ".contracts.termMaxViewer")); + } } function writeAsJson(string memory filePath, CoreParams memory coreParams, DeployedContracts memory coreContracts) @@ -211,11 +230,25 @@ contract DeployBaseV2 is Script { ' "vaultFactoryV2": "', vm.toString(address(coreContracts.vaultFactory)), '",\n', + ' "alphaFactory": "', + vm.toString(address(coreContracts.alphaFactory)), + '",\n', + ' "alphaVaultFactory": "', + vm.toString(address(coreContracts.alphaVaultFactory)), + '",\n', ' "priceFeedFactoryV2": "', vm.toString(address(coreContracts.priceFeedFactory)), '",\n', ' "termMax4626Factory": "', - vm.toString(address(coreContracts.tmx4626Factory)), + vm.toString(address(coreContracts.tmx4626Factory)) + ) + ); + } + + { + deploymentJson = string( + abi.encodePacked( + deploymentJson, '",\n', ' "whitelistManager": "', vm.toString(address(coreContracts.whitelistManager)), @@ -223,12 +256,18 @@ contract DeployBaseV2 is Script { ' "oracleAggregatorV2": "', vm.toString(address(coreContracts.oracle)), '",\n', + ' "routerV1": "', + vm.toString(address(coreContracts.routerV1)), + '",\n', ' "routerV2": "', vm.toString(address(coreContracts.router)), '",\n', ' "marketViewer": "', vm.toString(address(coreContracts.marketViewer)), '",\n', + ' "termMaxViewer": "', + vm.toString(address(coreContracts.termMaxViewer)), + '",\n', ' "makerHelper": "', vm.toString(address(coreContracts.makerHelper)), '",\n', @@ -294,6 +333,17 @@ contract DeployBaseV2 is Script { factory = new TermMaxFactoryV2(admin, address(m), whitelistManager); } + function deployMarketFactories(address admin, address whitelistManager) + public + returns (TermMaxFactoryV2 factory, TermMaxFactoryV2 alphaFactory) + { + address tokenImplementation = address(new MintableERC20V2()); + address orderImplementation = address(new TermMaxOrderV2()); + TermMaxMarketV2 m = new TermMaxMarketV2(tokenImplementation, orderImplementation); + factory = new TermMaxFactoryV2(admin, address(m), whitelistManager); + alphaFactory = new TermMaxFactoryV2(admin, address(m), whitelistManager); + } + function deployVaultFactory(address admin, address whitelistManager) public returns (TermMaxVaultFactoryV2 vaultFactory) @@ -316,12 +366,35 @@ contract DeployBaseV2 is Script { oracle = new OracleAggregatorWithSequencerV2(admin, oracleTimelock, sequencerUpPriceFeed, gracePeriod); } - function deployRouter(address admin, address whitelistManager) public returns (TermMaxRouterV2 router) { + function deployRouter(address admin, address whitelistManager, bool onlyV2) + public + returns (TermMaxRouter_V1_1_2 routerV1, TermMaxRouterV2 router) + { + if (!onlyV2) { + TermMaxRouter_V1_1_2 implementationV1 = new TermMaxRouter_V1_1_2(whitelistManager); + bytes memory dataV1 = abi.encodeCall(TermMaxRouter_V1_1_2.initialize, (admin)); + ERC1967Proxy proxyV1 = new ERC1967Proxy(address(implementationV1), dataV1); + routerV1 = TermMaxRouter_V1_1_2(address(proxyV1)); + } TermMaxRouterV2 implementation = new TermMaxRouterV2(whitelistManager); bytes memory data = abi.encodeCall(TermMaxRouterV2.initialize, (admin)); + ERC1967Proxy proxyV2 = new ERC1967Proxy(address(implementation), data); + router = TermMaxRouterV2(address(proxyV2)); + } + + function deployMarketViewer(address admin) public returns (TermMaxViewer marketViewer) { + TermMaxViewer implementation = new TermMaxViewer(); + + bytes memory data = abi.encodeCall(TermMaxViewer.initialize, (admin)); ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), data); - router = TermMaxRouterV2(address(proxy)); + marketViewer = TermMaxViewer(address(proxy)); + } + + function upgradeMarketViewer(AccessManagerV2 manager, address proxy) public returns (TermMaxViewer viewer) { + TermMaxViewer implementation = new TermMaxViewer(); + manager.upgradeSubContract(UUPSUpgradeable(proxy), address(implementation), ""); + viewer = TermMaxViewer(proxy); } function upgradeRouter(AccessManagerV2 manager, address routerProxy, address whitelistManager) @@ -442,13 +515,20 @@ contract DeployBaseV2 is Script { // deploy price feed factory contracts.priceFeedFactory = new TermMaxPriceFeedFactoryV2(); - // deploy or upgrade router - if (address(contracts.router) == address(0)) { - contracts.router = deployRouter(address(contracts.accessManager), address(contracts.whitelistManager)); + bool onlyV2 = address(contracts.routerV1) != address(0); + if (onlyV2) { + (, contracts.router) = + deployRouter(address(contracts.accessManager), address(contracts.whitelistManager), onlyV2); } else { - contracts.router = - upgradeRouter(contracts.accessManager, address(contracts.router), address(contracts.whitelistManager)); + (contracts.routerV1, contracts.router) = + deployRouter(address(contracts.accessManager), address(contracts.whitelistManager), onlyV2); } + + if (contracts.termMaxViewer == TermMaxViewer(address(0))) { + TermMaxViewer termMaxViewer = deployMarketViewer(address(contracts.accessManager)); + contracts.termMaxViewer = termMaxViewer; + } + // deploy maker helper contracts.makerHelper = deployMakerHelper(address(contracts.accessManager), address(contracts.whitelistManager)); // deploy faucet @@ -492,9 +572,30 @@ contract DeployBaseV2 is Script { adapters[1] = address(contracts.termMaxSwapAdapter); } // whitelist swap adapters + // filter address 0 + uint256 validAdapterCount; + for (uint256 i = 0; i < adapters.length; i++) { + if (adapters[i] != address(0)) { + validAdapterCount++; + } + } + address[] memory validAdapters = new address[](validAdapterCount); + uint256 index; + for (uint256 i = 0; i < adapters.length; i++) { + if (adapters[i] != address(0)) { + validAdapters[index] = adapters[i]; + index++; + } + } + console.log("Whitelisting adapters for router v2..."); contracts.accessManager.batchSetWhitelist( - contracts.whitelistManager, adapters, IWhitelistManager.ContractModule.ADAPTER, true + contracts.whitelistManager, validAdapters, IWhitelistManager.ContractModule.ADAPTER, true ); + console.log("Whitelisting adapters for router v1..."); + for (uint256 i = 0; i < validAdapters.length; i++) { + contracts.accessManager.setAdapterWhitelist(contracts.routerV1, validAdapters[i], true); + } + console.log("Adapters whitelisted"); return contracts; } @@ -514,16 +615,20 @@ contract DeployBaseV2 is Script { TerminalVaultAdapter terminalVaultAdapter ) { - // deploy access manager + // access manager AccessManagerV2 accessManager = AccessManagerV2(accessManagerAddr); // deploy and whitelist swap adapter - uniswapV3Adapter = new UniswapV3AdapterV2(); - odosV2Adapter = new OdosV2AdapterV2(odosV2Router); - pendleSwapV3Adapter = new PendleSwapV3AdapterV2(address(pendleSwapV3Router)); + // uniswapV3Adapter = new UniswapV3AdapterV2(); + if (odosV2Router != address(0)) { + odosV2Adapter = new OdosV2AdapterV2(odosV2Router); + } + if (pendleSwapV3Router != address(0)) { + pendleSwapV3Adapter = new PendleSwapV3AdapterV2(address(pendleSwapV3Router)); + } vaultAdapter = new ERC4626VaultAdapterV2(); termMaxSwapAdapter = new TermMaxSwapAdapter(whitelistManagerAddr); - terminalVaultAdapter = new TerminalVaultAdapter(); + // terminalVaultAdapter = new TerminalVaultAdapter(); } function deployWhitelistManager(address accessManager) public returns (WhitelistManager whitelistManager) { diff --git a/script/deploy/DeployBeefySharePriceFeedAdapter.s.sol b/script/deploy/DeployBeefySharePriceFeedAdapter.s.sol new file mode 100644 index 00000000..c568b4b4 --- /dev/null +++ b/script/deploy/DeployBeefySharePriceFeedAdapter.s.sol @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {console} from "forge-std/console.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; +import {TermMaxBeefySharePriceFeedAdapter} from + "contracts/v2/oracle/adapters/beefy/TermMaxBeefySharePriceFeedAdapter.sol"; + +/** + * @title DeployBeefySharePriceFeedAdapter + * @notice Script to deploy TermMaxBeefySharePriceFeedAdapter + * @dev Env vars: + * - NETWORK (default: eth-mainnet) + * - {NETWORK}_DEPLOYER_PRIVATE_KEY + * - {NETWORK}_BEEFY_ADAPTER_COUNT (optional, default: 1) + * + * Single deploy mode (count = 1): + * - {NETWORK}_BEEFY_VAULT (optional, fallback to fork-test value) + * - {NETWORK}_TOKEN0_PRICE_FEED (optional, fallback to fork-test value) + * - {NETWORK}_TOKEN1_PRICE_FEED (optional, fallback to fork-test value) + * + * Batch deploy mode (count > 1): + * - {NETWORK}_BEEFY_VAULT_{i} + * - {NETWORK}_TOKEN0_PRICE_FEED_{i} + * - {NETWORK}_TOKEN1_PRICE_FEED_{i} + * where i = 0..count-1 + */ +contract DeployBeefySharePriceFeedAdapter is DeployBaseV2 { + address constant DEFAULT_BEEFY_VAULT = 0xAf92a4C7FCBc0Af09CfFf66d36C615fB40Ac1eEE; + address constant DEFAULT_TOKEN0_PRICE_FEED = 0xbbF121624c3b85C929Ac83872bf6c86b0976A55e; // usde/usd + address constant DEFAULT_TOKEN1_PRICE_FEED = 0x2D4f3199a80b848F3d094745F3Bbd4224892654e; // honey/usd + + address constant DEFAULT_BEEFY_VAULT_1 = 0x64606Bee7e4F5f67414765C4290315d3830ae0e2; + address constant DEFAULT_TOKEN0_PRICE_FEED_1 = 0xEC352BC99BD444E0AC7f00e9B7D581B4b100CA3e; // susde/usd + address constant DEFAULT_TOKEN1_PRICE_FEED_1 = 0x2D4f3199a80b848F3d094745F3Bbd4224892654e; // honey/usd + uint256 public adapterCount = 2; + + string public network; + address public deployerAddr; + uint256 public deployerPrivateKey; + + address[] public beefyVaults; + address[] public token0PriceFeeds; + address[] public token1PriceFeeds; + address[] public deployedAdapters; + + function setUp() public { + network = vm.envOr("NETWORK", string("eth-mainnet")); + string memory networkUpper = StringHelper.toUpper(network); + + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + deployerPrivateKey = vm.envUint(privateKeyVar); + deployerAddr = vm.addr(deployerPrivateKey); + + beefyVaults = new address[](adapterCount); + token0PriceFeeds = new address[](adapterCount); + token1PriceFeeds = new address[](adapterCount); + deployedAdapters = new address[](adapterCount); + + beefyVaults[0] = vm.envOr(string.concat(networkUpper, "_BEEFY_VAULT"), DEFAULT_BEEFY_VAULT); + token0PriceFeeds[0] = vm.envOr(string.concat(networkUpper, "_TOKEN0_PRICE_FEED"), DEFAULT_TOKEN0_PRICE_FEED); + token1PriceFeeds[0] = vm.envOr(string.concat(networkUpper, "_TOKEN1_PRICE_FEED"), DEFAULT_TOKEN1_PRICE_FEED); + + beefyVaults[1] = vm.envOr(string.concat(networkUpper, "_BEEFY_VAULT_1"), DEFAULT_BEEFY_VAULT_1); + token0PriceFeeds[1] = vm.envOr(string.concat(networkUpper, "_TOKEN0_PRICE_FEED_1"), DEFAULT_TOKEN0_PRICE_FEED_1); + token1PriceFeeds[1] = vm.envOr(string.concat(networkUpper, "_TOKEN1_PRICE_FEED_1"), DEFAULT_TOKEN1_PRICE_FEED_1); + + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", network); + if (!vm.exists(deploymentsDir)) { + vm.createDir(deploymentsDir, true); + } + + console.log("===== Deployment Configuration ====="); + console.log("Network:", network); + console.log("Deployer:", deployerAddr); + console.log("Deployer balance:", deployerAddr.balance); + console.log("Adapter count:", adapterCount); + for (uint256 i = 0; i < adapterCount; i++) { + console.log("--- Adapter index:", i); + console.log("Beefy Vault:", beefyVaults[i]); + console.log("Token0 Price Feed:", token0PriceFeeds[i]); + console.log("Token1 Price Feed:", token1PriceFeeds[i]); + } + } + + function run() public { + vm.startBroadcast(deployerPrivateKey); + for (uint256 i = 0; i < adapterCount; i++) { + TermMaxBeefySharePriceFeedAdapter adapter = + new TermMaxBeefySharePriceFeedAdapter(beefyVaults[i], token0PriceFeeds[i], token1PriceFeeds[i]); + deployedAdapters[i] = address(adapter); + } + vm.stopBroadcast(); + + console.log("===== Deployment Successful ====="); + for (uint256 i = 0; i < adapterCount; i++) { + TermMaxBeefySharePriceFeedAdapter adapter = TermMaxBeefySharePriceFeedAdapter(deployedAdapters[i]); + console.log("--- Adapter index:", i); + console.log("TermMaxBeefySharePriceFeedAdapter:", address(adapter)); + console.log("Description:", adapter.description()); + console.log("Decimals:", adapter.decimals()); + + (, int256 answer,, uint256 updatedAt,) = adapter.latestRoundData(); + console.log("Latest Price:", answer); + console.log("Updated At:", updatedAt); + } + + saveDeploymentInfo(); + } + + function saveDeploymentInfo() internal { + string memory adaptersJson = ""; + for (uint256 i = 0; i < adapterCount; i++) { + if (i > 0) { + adaptersJson = string.concat(adaptersJson, ",\n"); + } + adaptersJson = string.concat( + adaptersJson, + " {\n", + ' "index": "', + vm.toString(i), + '",\n', + ' "termMaxBeefySharePriceFeedAdapter": "', + vm.toString(deployedAdapters[i]), + '",\n', + ' "beefyVault": "', + vm.toString(beefyVaults[i]), + '",\n', + ' "token0PriceFeed": "', + vm.toString(token0PriceFeeds[i]), + '",\n', + ' "token1PriceFeed": "', + vm.toString(token1PriceFeeds[i]), + '"\n', + " }" + ); + } + + string memory json = string.concat( + "{\n", + ' "network": "', + network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + getGitBranch(), + '",\n', + ' "gitCommitHash": "', + vm.toString(getGitCommitHash()), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "deployer": "', + vm.toString(deployerAddr), + '",\n', + ' "adapterCount": "', + vm.toString(adapterCount), + '",\n', + ' "contracts": [\n', + adaptersJson, + "\n ]\n", + "}" + ); + + string memory jsonPath = string.concat( + vm.projectRoot(), "/deployments/", network, "/", network, "-beefy-share-price-feed-adapter.json" + ); + vm.writeFile(jsonPath, json); + console.log("Deployment info saved to:", jsonPath); + } +} diff --git a/script/deploy/DeployCoreV2.s.sol b/script/deploy/DeployCoreV2.s.sol index 69fd20db..1705cbe1 100644 --- a/script/deploy/DeployCoreV2.s.sol +++ b/script/deploy/DeployCoreV2.s.sol @@ -73,7 +73,7 @@ contract DeployCoreV2 is DeployBaseV2 { if (vm.keyExistsJson(json, ".contracts.router")) { address routerAddr = vm.parseJsonAddress(json, ".contracts.router"); console.log("Router already deployed at:", routerAddr); - coreContracts.router = TermMaxRouterV2(routerAddr); + coreContracts.routerV1 = TermMaxRouter_V1_1_2(routerAddr); } if (vm.keyExistsJson(json, ".contracts.faucet")) { address faucetAddr = vm.parseJsonAddress(json, ".contracts.faucet"); @@ -120,6 +120,8 @@ contract DeployCoreV2 is DeployBaseV2 { console.log("RouterV2 deployed at:", address(coreContracts.router)); console.log("MakerHelper deployed at:", address(coreContracts.makerHelper)); console.log("MarketViewer deployed at:", address(coreContracts.marketViewer)); + console.log("TermMaxRouterV1.1.2 deployed at:", address(coreContracts.routerV1)); + console.log("TermMaxViewer deployed at:", address(coreContracts.termMaxViewer)); if (coreParams.isMainnet) { console.log("UniswapV3AdapterV2 deployed at:", address(coreContracts.uniswapV3Adapter)); console.log("OdosV2AdapterV2 deployed at:", address(coreContracts.odosV2Adapter)); diff --git a/script/deploy/DeployDUSDPriceFeedAdapter.s.sol b/script/deploy/DeployDUSDPriceFeedAdapter.s.sol new file mode 100644 index 00000000..101d99b4 --- /dev/null +++ b/script/deploy/DeployDUSDPriceFeedAdapter.s.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {TermMaxDUSDPriceFeedAdapter} from "contracts/v2/oracle/priceFeeds/TermMaxDUSDPriceFeedAdapter.sol"; +import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; + +/** + * @title DeployDUSDPriceFeedAdapter + * @notice Script to deploy TermMaxDUSDPriceFeedAdapter on Ethereum mainnet + * @dev This script deploys an adapter that wraps the DUSD oracle + * + * Usage: + * forge script script/deploy/DeployDUSDPriceFeedAdapter.s.sol:DeployDUSDPriceFeedAdapter \ + * --rpc-url $ETH_MAINNET_RPC_URL \ + * --private-key $ETH_MAINNET_DEPLOYER_PRIVATE_KEY \ + * --broadcast \ + * --verify + */ +contract DeployDUSDPriceFeedAdapter is DeployBaseV2 { + // Mainnet DUSD oracle + asset addresses (matching fork test) + address constant DUSD_ORACLE = 0x49fba73738461835fefB19351b161Bde4BcD6b5A; + address constant DUSD_ASSET = 0x871aB8E36CaE9AF35c6A3488B049965233DeB7ed; + + // Network configuration + string network; + address deployerAddr; + uint256 deployerPrivateKey; + + function setUp() public { + // Load network configuration from environment variables + network = vm.envOr("NETWORK", string("eth-mainnet")); + string memory networkUpper = StringHelper.toUpper(network); + + // Load deployer private key + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + deployerPrivateKey = vm.envUint(privateKeyVar); + deployerAddr = vm.addr(deployerPrivateKey); + + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", network); + if (!vm.exists(deploymentsDir)) { + vm.createDir(deploymentsDir, true); + } + + console.log("===== Deployment Configuration ====="); + console.log("Network:", network); + console.log("Deployer:", deployerAddr); + console.log("Deployer balance:", deployerAddr.balance); + console.log("DUSD Oracle:", DUSD_ORACLE); + console.log("DUSD Asset:", DUSD_ASSET); + } + + function run() public { + console.log("\n===== Starting Deployment ====="); + + vm.startBroadcast(deployerPrivateKey); + + // Deploy TermMaxDUSDPriceFeedAdapter + TermMaxDUSDPriceFeedAdapter adapter = new TermMaxDUSDPriceFeedAdapter(DUSD_ORACLE, DUSD_ASSET); + + vm.stopBroadcast(); + + console.log("\n===== Deployment Successful ====="); + console.log("TermMaxDUSDPriceFeedAdapter deployed at:", address(adapter)); + console.log("Wrapped DUSD oracle:", DUSD_ORACLE); + console.log("Asset tracked:", DUSD_ASSET); + + // Verify adapter configuration + console.log("\n===== Verifying Adapter Configuration ====="); + console.log("Decimals:", adapter.decimals()); + console.log("Description:", adapter.description()); + + // Get price data + (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + adapter.latestRoundData(); + console.log("\n===== Price Data ====="); + console.log("Round ID:", roundId); + console.log("Answer (DUSD/USDC with 18 decimals):", answer); + console.log("Price (human readable):", uint256(answer) / 1e18); + console.log("Started At:", startedAt); + console.log("Updated At:", updatedAt); + console.log("Answered In Round:", answeredInRound); + + // Save deployment info + saveDeploymentInfo(address(adapter)); + } + + function saveDeploymentInfo(address adapterAddress) internal { + console.log("\n===== Saving Deployment Info ====="); + + // Get git info + string memory gitBranch = getGitBranch(); + bytes memory gitCommitHash = getGitCommitHash(); + + // Create JSON output + string memory json = string( + abi.encodePacked( + "{\n", + ' "network": "', + network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + gitBranch, + '",\n', + ' "gitCommitHash": "', + vm.toString(gitCommitHash), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "deployer": "', + vm.toString(deployerAddr), + '",\n', + ' "contracts": {\n', + ' "termMaxDETHPriceFeedAdapter": "', + vm.toString(adapterAddress), + '",\n', + ' "dethOracle": "', + vm.toString(DUSD_ORACLE), + '",\n', + ' "dethAsset": "', + vm.toString(DUSD_ASSET), + '"\n', + " }\n", + "}" + ) + ); + + // Save to JSON file + string memory jsonPath = + string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-deth-price-feed-adapter" ".json"); + vm.writeFile(jsonPath, json); + console.log("Deployment info saved to:", jsonPath); + } +} diff --git a/script/deploy/DeployMakerHelper.s.sol b/script/deploy/DeployMakerHelper.s.sol new file mode 100644 index 00000000..9e4371cd --- /dev/null +++ b/script/deploy/DeployMakerHelper.s.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; + +contract DeployMakerHelper is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + bool isBroadcast; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + isBroadcast = vm.envBool("IS_BROADCAST"); + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + coreParams.adminAddr = adminAddr; + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + if (coreContracts.makerHelper == MakerHelper(address(0))) { + coreContracts.makerHelper = + deployMakerHelper(address(coreContracts.accessManager), address(coreContracts.whitelistManager)); + if (isBroadcast) { + writeAsJson( + string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ), + coreParams, + coreContracts + ); + } + console.log("Deployed MakerHelper at:", address(coreContracts.makerHelper)); + } else { + // upgrade + upgradeMakerHelper( + coreContracts.accessManager, address(coreContracts.makerHelper), address(coreContracts.whitelistManager) + ); + console.log("Upgrading existing MakerHelper at:", address(coreContracts.makerHelper)); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + } +} diff --git a/script/deploy/DeployMarkets.s.sol b/script/deploy/DeployMarkets.s.sol index afe1cb1d..7d300778 100644 --- a/script/deploy/DeployMarkets.s.sol +++ b/script/deploy/DeployMarkets.s.sol @@ -26,11 +26,12 @@ contract DeployMarketsScript is DeployBaseV2 { DeployedContracts coreContracts; address[] markets; - string configPath = "script/deploy/deploydata/hyperevm-mainnet-markets.json"; + string configPath = "-markets.json"; function setUp() public { // Load network from environment variable network = vm.envString("NETWORK"); + configPath = string.concat(vm.projectRoot(), "/script/deploy/deploydata/", network, configPath); // Load network-specific configuration { string memory networkUpper = toUpper(network); diff --git a/script/deploy/DeployMidasVaultSwapAdapter.s.sol b/script/deploy/DeployMidasVaultSwapAdapter.s.sol new file mode 100644 index 00000000..d5266bf9 --- /dev/null +++ b/script/deploy/DeployMidasVaultSwapAdapter.s.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {DeployBaseV2, AccessManagerV2, UUPSUpgradeable} from "./DeployBaseV2.s.sol"; +import {TermMaxRouter} from "contracts/v1/router/TermMaxRouter.sol"; +import {TermMaxRouterV2} from "contracts/v2/router/TermMaxRouterV2.sol"; +import {ERC4626VaultAdapterV2} from "contracts/v2/router/swapAdapters/ERC4626VaultAdapterV2.sol"; +import {KodiakSwapAdapter} from "contracts/v2/router/swapAdapters/KodiakSwapAdapter.sol"; +import {LifiSwapAdapter} from "contracts/v2/router/swapAdapters/LifiSwapAdapter.sol"; +import {OdosV2AdapterV2} from "contracts/v2/router/swapAdapters/OdosV2AdapterV2.sol"; +import {OkxSwapAdapter} from "contracts/v2/router/swapAdapters/OkxSwapAdapter.sol"; +import {OndoSwapAdapter} from "contracts/v2/router/swapAdapters/OndoSwapAdapter.sol"; +import {OneInchSwapAdapter} from "contracts/v2/router/swapAdapters/OneInchSwapAdapter.sol"; +import {PancakeSmartAdapter} from "contracts/v2/router/swapAdapters/PancakeSmartAdapter.sol"; +import {PendleSwapV3AdapterV2} from "contracts/v2/router/swapAdapters/PendleSwapV3AdapterV2.sol"; +import {TermMaxSwapAdapter} from "contracts/v2/router/swapAdapters/TermMaxSwapAdapter.sol"; +import {UniswapV3AdapterV2} from "contracts/v2/router/swapAdapters/UniswapV3AdapterV2.sol"; +import {IWhitelistManager} from "contracts/v2/access/IWhitelistManager.sol"; +import {TerminalVaultAdapter} from "contracts/v2/router/swapAdapters/TerminalVaultAdapter.sol"; + +contract DeployMidasVaultSwapAdapter is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + address adapter; + bool isBroadcast = vm.envBool("IS_BROADCAST"); + + string deploymentPath; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + + deploymentPath = + string.concat(vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core.json"); + + console.log("Using existing RouterV1 at:", address(coreContracts.routerV1)); + console.log("Using existing RouterV2 at:", address(coreContracts.router)); + + coreParams.adminAddr = adminAddr; + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + { + TerminalVaultAdapter terminalVaultAdapter = new TerminalVaultAdapter(); + console.log("TerminalVaultAdapter deploy at:", address(terminalVaultAdapter)); + adapter = address(terminalVaultAdapter); + coreContracts.terminalVaultAdapter = terminalVaultAdapter; + } + + console.log("Whitelist adapters in AccessManagerV2"); + + coreContracts.accessManager.setAdapterWhitelist(TermMaxRouter(address(coreContracts.routerV1)), adapter, true); + + address[] memory adapters = new address[](1); + adapters[0] = adapter; + + coreContracts.accessManager.batchSetWhitelist( + coreContracts.whitelistManager, adapters, IWhitelistManager.ContractModule.ADAPTER, true + ); + + console.log("All adapters whitelisted in AccessManagerV2"); + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + writeAsJson(deploymentPath, coreParams, coreContracts); + } +} diff --git a/script/deploy/DeployOndoPriceFeedAdapterFactory.s.sol b/script/deploy/DeployOndoPriceFeedAdapterFactory.s.sol new file mode 100644 index 00000000..405a35be --- /dev/null +++ b/script/deploy/DeployOndoPriceFeedAdapterFactory.s.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {console} from "forge-std/console.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; +import {TermMaxOndoPriceFeedAdapterFactory} from + "contracts/v2/oracle/adapters/ondo/TermMaxOndoPriceFeedAdapterFactory.sol"; + +/** + * @title DeployOndoPriceFeedAdapterFactory + * @notice Script to deploy TermMaxOndoPriceFeedAdapterFactory + * @dev Env vars: + * - NETWORK (default: eth-mainnet) + * - {NETWORK}_DEPLOYER_PRIVATE_KEY + * - {NETWORK}_ONDO_ORACLE (optional, fallback to fork-test value) + * - {NETWORK}_PRICE_FEED_FACTORY_V2 (optional, fallback to deployments/{network}/{network}-core-v2.json) + */ +contract DeployOndoPriceFeedAdapterFactory is DeployBaseV2 { + error PriceFeedFactoryNotConfigured(); + + string public network; + address public deployerAddr; + uint256 public deployerPrivateKey; + + address public ondoOracle; + DeployedContracts coreContracts; + + function setUp() public { + network = vm.envOr("NETWORK", string("eth-mainnet")); + string memory networkUpper = StringHelper.toUpper(network); + + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + deployerPrivateKey = vm.envUint(privateKeyVar); + deployerAddr = vm.addr(deployerPrivateKey); + + ondoOracle = vm.envAddress(string.concat(networkUpper, "_ONDO_ORACLE")); + + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", network); + if (!vm.exists(deploymentsDir)) { + vm.createDir(deploymentsDir, true); + } + + string memory deploymentPath = + string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-core-v2.json"); + string memory json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + + console.log("===== Deployment Configuration ====="); + console.log("Network:", network); + console.log("Deployer:", deployerAddr); + console.log("Deployer balance:", deployerAddr.balance); + console.log("Ondo Oracle:", ondoOracle); + console.log("PriceFeedFactoryV2:", address(coreContracts.priceFeedFactory)); + + require(ondoOracle != address(0), "Ondo Oracle address must be set"); + require(address(coreContracts.priceFeedFactory) != address(0), "PriceFeedFactoryV2 address must be set"); + } + + function run() public { + vm.startBroadcast(deployerPrivateKey); + TermMaxOndoPriceFeedAdapterFactory factory = + new TermMaxOndoPriceFeedAdapterFactory(ondoOracle, address(coreContracts.priceFeedFactory)); + vm.stopBroadcast(); + + console.log("===== Deployment Successful ====="); + console.log("TermMaxOndoPriceFeedAdapterFactory:", address(factory)); + console.log("Factory ondoOracle:", factory.ondoOracle()); + console.log("Factory priceFeedFactory:", address(factory.priceFeedFactory())); + + saveDeploymentInfo(address(factory)); + } + + function saveDeploymentInfo(address factoryAddress) internal { + string memory json = string( + abi.encodePacked( + "{\n", + ' "network": "', + network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + getGitBranch(), + '",\n', + ' "gitCommitHash": "', + vm.toString(getGitCommitHash()), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "deployer": "', + vm.toString(deployerAddr), + '",\n', + ' "contracts": {\n', + ' "termMaxOndoPriceFeedAdapterFactory": "', + vm.toString(factoryAddress), + '",\n', + ' "ondoOracle": "', + vm.toString(ondoOracle), + '",\n', + ' "priceFeedFactoryV2": "', + vm.toString(address(coreContracts.priceFeedFactory)), + '"\n', + " }\n", + "}" + ) + ); + + string memory jsonPath = string.concat( + vm.projectRoot(), "/deployments/", network, "/", network, "-ondo-price-feed-adapter-factory.json" + ); + vm.writeFile(jsonPath, json); + console.log("Deployment info saved to:", jsonPath); + } +} diff --git a/script/deploy/DeployOracleAggregatorV2.s.sol b/script/deploy/DeployOracleAggregatorV2.s.sol new file mode 100644 index 00000000..d80de6e2 --- /dev/null +++ b/script/deploy/DeployOracleAggregatorV2.s.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {OrderConfig} from "contracts/v1/storage/TermMaxStorage.sol"; +import {JsonLoader} from "script/utils/JsonLoader.sol"; +import {OrderV2ConfigurationParams} from "contracts/v2/vault/VaultStorageV2.sol"; +import {ITermMaxOrderV2} from "contracts/v2/ITermMaxOrderV2.sol"; +import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; +import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; +import {SimpleAggregator} from "contracts/v2/oracle/SimpleAggregator.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {ITermMaxMarket} from "contracts/v1/ITermMaxMarket.sol"; + +contract DeployOracleAggregatorV2 is DeployBaseV2 { + using StringHelper for string; + // Network-specific config loaded from environment variables + + uint256 deployerPrivateKey; + + CoreParams coreParams; + DeployedContracts coreContracts; + bool isBroadcast; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + isBroadcast = vm.envBool("IS_BROADCAST"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + coreParams.adminAddr = vm.envAddress(adminVar); + coreParams.oracleTimelock = vm.envUint(string.concat(networkUpper, "_ORACLE_TIMELOCK")); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + if (coreParams.isL2Network) { + string memory l2SequencerUptimeFeedVar = string.concat(networkUpper, "_L2_SEQUENCER_UPTIME_FEED"); + coreParams.l2SequencerUpPriceFeed = vm.envAddress(l2SequencerUptimeFeedVar); + string memory l2SequencerGracePeriodVar = string.concat(networkUpper, "_L2_SEQUENCER_GRACE_PERIOD"); + coreParams.l2GracePeriod = vm.envUint(l2SequencerGracePeriodVar); + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + address accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + + coreContracts.oracle = coreParams.isL2Network + ? IOracle( + address( + deployOracleAggregatorWithSequencer( + coreParams.deployerAddr, + coreParams.oracleTimelock, + coreParams.l2SequencerUpPriceFeed, + coreParams.l2GracePeriod + ) + ) + ) + : IOracle(address(deployOracleAggregator(address(coreContracts.accessManager), coreParams.oracleTimelock))); + console.log("Deployed OracleAggregatorV2 at:", address(coreContracts.oracle)); + + if (coreParams.isL2Network) { + OracleAggregatorV2(address(coreContracts.oracle)).transferOwnership(address(coreContracts.accessManager)); + console.log("Transferred ownership of OracleAggregatorV2 to AccessManagerV2"); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + if (isBroadcast) { + writeAsJson( + string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ), + coreParams, + coreContracts + ); + } + } +} diff --git a/script/deploy/DeployOtherPool.s.sol b/script/deploy/DeployOtherPool.s.sol deleted file mode 100644 index 10457c07..00000000 --- a/script/deploy/DeployOtherPool.s.sol +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {Script} from "forge-std/Script.sol"; -import {VmSafe} from "forge-std/Vm.sol"; -import "forge-std/console.sol"; -import "./DeployBaseV2.s.sol"; - -contract DeployOtherPool is DeployBaseV2 { - uint256 deployerPrivateKey; - address accessManagerAddr; - - CoreParams coreParams; - DeployedContracts coreContracts; - - struct ThirdPools { - address thirdPool; - address stable; - } - - ThirdPools[] public thirdPools; - - function setUp() public { - // Load network from environment variable - coreParams.network = vm.envString("NETWORK"); - string memory networkUpper = toUpper(coreParams.network); - - // Load network-specific configuration - string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); - string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); - { - string memory AAVEPoolVar = string.concat(networkUpper, "_AAVE_POOL"); - string memory AAVEReferralCodeVar = string.concat(networkUpper, "_AAVE_REFERRAL_CODE"); - coreParams.AAVE_POOL = vm.envAddress(AAVEPoolVar); - coreParams.AAVE_REFERRAL_CODE = uint16(vm.envUint(AAVEReferralCodeVar)); - } - - deployerPrivateKey = vm.envUint(privateKeyVar); - coreParams.deployerAddr = vm.addr(deployerPrivateKey); - coreParams.adminAddr = vm.envAddress(adminVar); - - coreParams.isMainnet = keccak256(abi.encodePacked(coreParams.network)) - == keccak256(abi.encodePacked("eth-mainnet")) - || keccak256(abi.encodePacked(coreParams.network)) == keccak256(abi.encodePacked("arb-mainnet")) - || keccak256(abi.encodePacked(coreParams.network)) == keccak256(abi.encodePacked("bnb-mainnet")); - coreParams.isL2Network = ( - keccak256(abi.encodePacked(toUpper(coreParams.network))) == keccak256(abi.encodePacked("arb-mainnet")) - ) || (keccak256(abi.encodePacked(toUpper(coreParams.network))) == keccak256(abi.encodePacked("arb-sepolia"))); - { - // Create deployments directory if it doesn't exist - string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); - if (!vm.exists(deploymentsDir)) { - // Directory doesn't exist, create it - vm.createDir(deploymentsDir, true); - } - } - - string memory deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" - ); - if (vm.exists(deploymentPath)) { - coreContracts = readDeployData(vm.readFile(deploymentPath)); - } - - deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" - ); - string memory json = vm.readFile(deploymentPath); - - accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); - console.log("Using existing AccessManagerV2 at:", accessManagerAddr); - coreContracts.accessManager = AccessManagerV2(accessManagerAddr); - } - - function run() public { - console.log("Network:", coreParams.network); - console.log("Deployer balance:", coreParams.deployerAddr.balance); - - vm.startBroadcast(deployerPrivateKey); - - if (coreContracts.whitelistManager == WhitelistManager(address(0))) { - coreContracts.whitelistManager = deployWhitelistManager(address(coreContracts.accessManager)); - console.log("WhitelistManager deployed at:", address(coreContracts.whitelistManager)); - coreContracts.accessManager.grantRole(coreContracts.accessManager.WHITELIST_ROLE(), coreParams.deployerAddr); - } else { - console.log("Using existing WhitelistManager at:", address(coreContracts.whitelistManager)); - } - console.log("Using existing TermMax4626Factory at:", address(coreContracts.tmx4626Factory)); - - string memory configPath = - string.concat(vm.projectRoot(), "/script/deploy/deploydata/", coreParams.network, "-4626-pool.json"); - JsonLoader.PoolConfig[] memory poolConfigs = JsonLoader.getPoolConfigsFromJson(vm.readFile(configPath)); - address[] memory pools = new address[](poolConfigs.length); - for (uint256 i = 0; i < poolConfigs.length; i++) { - console.log("Deploying 4626 pool with thirdPool:", poolConfigs[i].thirdPool); - StableERC4626For4626 stable = coreContracts.tmx4626Factory.createStableERC4626For4626( - coreParams.adminAddr, poolConfigs[i].thirdPool, poolConfigs[i].bufferConfig - ); - pools[i] = address(stable); - thirdPools.push(ThirdPools({thirdPool: poolConfigs[i].thirdPool, stable: address(stable)})); - console.log(" Deployed StableERC4626For4626 at:", address(stable)); - } - - // whitelist the pool - coreContracts.accessManager.batchSetWhitelist( - coreContracts.whitelistManager, pools, IWhitelistManager.ContractModule.POOL, true - ); - - vm.stopBroadcast(); - - console.log("===== Git Info ====="); - console.log("Git branch:", getGitBranch()); - console.log("Git commit hash:"); - console.logBytes(getGitCommitHash()); - console.log(); - - console.log("===== Block Info ====="); - console.log("Block number:", block.number); - console.log("Block timestamp:", block.timestamp); - console.log(); - - console.log("===== Core Info ====="); - console.log("Deployer:", coreParams.deployerAddr); - console.log("Admin:", coreParams.adminAddr); - - string memory deploymentPath = string.concat( - vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" - ); - writeToEnv(); - } - - function writeToEnv() internal { - string memory deploymentEnv = string( - abi.encodePacked( - "NETWORK=", - coreParams.network, - "\nDEPLOYED_AT=", - vm.toString(block.timestamp), - "\nGIT_BRANCH=", - getGitBranch(), - "\nGIT_COMMIT_HASH=", - vm.toString(getGitCommitHash()), - "\nBLOCK_NUMBER=", - vm.toString(block.number), - "\nBLOCK_TIMESTAMP=", - vm.toString(block.timestamp), - "\nDEPLOYER_ADDRESS=", - vm.toString(vm.addr(deployerPrivateKey)), - "\nADMIN_ADDRESS=", - vm.toString(coreParams.adminAddr), - "\n" - ) - ); - for (uint256 i = 0; i < thirdPools.length; i++) { - deploymentEnv = string( - abi.encodePacked( - deploymentEnv, - "THIRD_POOL_ADDRESS_", - vm.toString(i + 1), - "=", - vm.toString(thirdPools[i].thirdPool), - "\n", - "STABLE_4626_POOL_ADDRESS_", - vm.toString(i + 1), - "=", - vm.toString(thirdPools[i].stable), - "\n" - ) - ); - } - - string memory path = string.concat( - vm.projectRoot(), - "/deployments/", - coreParams.network, - "/", - coreParams.network, - "-v2-4626-pools-", - vm.toString(block.timestamp), - ".env" - ); - vm.writeFile(path, deploymentEnv); - } -} diff --git a/script/deploy/DeploySrUSDeAdapter.s.sol b/script/deploy/DeployPTReUSDeAdapter.s.sol similarity index 88% rename from script/deploy/DeploySrUSDeAdapter.s.sol rename to script/deploy/DeployPTReUSDeAdapter.s.sol index a4d5c6b6..3d57a96b 100644 --- a/script/deploy/DeploySrUSDeAdapter.s.sol +++ b/script/deploy/DeployPTReUSDeAdapter.s.sol @@ -8,21 +8,21 @@ import {StringHelper} from "script/utils/StringHelper.sol"; import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; /** - * @title DeploySrUSDeAdapter + * @title DeployPTReUSDeAdapter * @notice Script to deploy TermMaxSparkLinearOracleAdapter for srUSDe on Ethereum mainnet * @dev This script deploys an adapter that wraps Spark/Pendle Linear Oracle for srUSDe * * Usage: - * forge script script/deploy/DeploySrUSDeAdapter.s.sol:DeploySrUSDeAdapter \ + * forge script script/deploy/DeployPTReUSDeAdapter.s.sol:DeployPTReUSDeAdapter \ * --rpc-url $ETH_MAINNET_RPC_URL \ * --private-key $ETH_MAINNET_DEPLOYER_PRIVATE_KEY \ * --broadcast \ * --verify */ -contract DeploySrUSDeAdapter is DeployBaseV2 { +contract DeployPTReUSDeAdapter is DeployBaseV2 { // Spark/Pendle Linear Oracle for srUSDe on Ethereum mainnet // This oracle is already deployed and being used in the markets configuration - address constant SPARK_SRUSDE_LINEAR_ORACLE = 0xeD2b85Df608fa9FBe95371D01566e12fb005EDeE; + address constant SPARK_PTREUSDE_LINEAR_ORACLE = 0x49FA8Ed54f8e7f5d9A12483AAFDE097ac1635b30; // Network configuration string network; @@ -51,7 +51,7 @@ contract DeploySrUSDeAdapter is DeployBaseV2 { console.log("Network:", network); console.log("Deployer:", deployerAddr); console.log("Deployer balance:", deployerAddr.balance); - console.log("Spark srUSDe Linear Oracle:", SPARK_SRUSDE_LINEAR_ORACLE); + console.log("Spark PTReUSDe Linear Oracle:", SPARK_PTREUSDE_LINEAR_ORACLE); } function run() public { @@ -60,13 +60,13 @@ contract DeploySrUSDeAdapter is DeployBaseV2 { vm.startBroadcast(deployerPrivateKey); // Deploy TermMaxSparkLinearOracleAdapter - TermMaxSparkLinearOracleAdapter adapter = new TermMaxSparkLinearOracleAdapter(SPARK_SRUSDE_LINEAR_ORACLE); + TermMaxSparkLinearOracleAdapter adapter = new TermMaxSparkLinearOracleAdapter(SPARK_PTREUSDE_LINEAR_ORACLE); vm.stopBroadcast(); console.log("\n===== Deployment Successful ====="); console.log("TermMaxSparkLinearOracleAdapter deployed at:", address(adapter)); - console.log("Wrapping Spark Linear Oracle at:", SPARK_SRUSDE_LINEAR_ORACLE); + console.log("Wrapping Spark Linear Oracle at:", SPARK_PTREUSDE_LINEAR_ORACLE); // Verify adapter configuration console.log("\n===== Verifying Adapter Configuration ====="); @@ -129,8 +129,8 @@ contract DeploySrUSDeAdapter is DeployBaseV2 { ' "termMaxSparkLinearOracleAdapter": "', vm.toString(adapterAddress), '",\n', - ' "sparkSrUSDeLinearOracle": "', - vm.toString(SPARK_SRUSDE_LINEAR_ORACLE), + ' "sparkPtReUSDeLinearOracle": "', + vm.toString(SPARK_PTREUSDE_LINEAR_ORACLE), '"\n', " }\n", "}" @@ -144,7 +144,7 @@ contract DeploySrUSDeAdapter is DeployBaseV2 { network, "/", network, - "-srusde-spark-linear-adapter-", + "-ptreusde-spark-linear-adapter-", vm.toString(block.timestamp), ".json" ); diff --git a/script/deploy/DeployPancakeOracle.s.sol b/script/deploy/DeployPancakeOracle.s.sol index 519c4dbe..24431087 100644 --- a/script/deploy/DeployPancakeOracle.s.sol +++ b/script/deploy/DeployPancakeOracle.s.sol @@ -66,15 +66,22 @@ contract DeployOracle is DeployBaseV2 { vm.startBroadcast(deployerPrivateKey); address pancakeFactory = 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865; - address baseToken; - address quoteToken; - uint32 _twapPeriod = 900; - uint24 fee = 500; + // B2/WBNB Pool + address baseToken = 0x783c3f003f172c6Ac5AC700218a357d2D66Ee2a2; + address quoteToken = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c; + uint32 _twapPeriod = 180; + uint24 fee = 100; address pool = IUniswapV3Factory(pancakeFactory).getPool(baseToken, quoteToken, fee); require(pool != address(0), "Pool doesn't exist"); TermMaxPancakeTWAPPriceFeed priceFeed = new TermMaxPancakeTWAPPriceFeed(pool, _twapPeriod, baseToken, quoteToken); console.log("Deployed TermMaxPancakeTWAPPriceFeed at:", address(priceFeed)); + (uint80 roundId, int256 price, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + priceFeed.latestRoundData(); + console.log("Price: ", price); + console.log("Started at: ", startedAt); + console.log("Updated at: ", updatedAt); + console.log("Round ID: ", roundId); oracleEnvs = string.concat( "BASE_TOKEN=", diff --git a/script/deploy/DeployPreTMX.s.sol b/script/deploy/DeployPreTMX.s.sol new file mode 100644 index 00000000..79ad6945 --- /dev/null +++ b/script/deploy/DeployPreTMX.s.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import {UniversalFactory} from "contracts/v2/tokenomics/UniversalFactory.sol"; +import {PreTMX} from "contracts/v2/tokenomics/PreTMX.sol"; + +contract DeployPreTMX is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + address preTmxAdmin = 0x65B7949C97e7d96bCd81cf53BfF602923973c950; + bool isBroadcast; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + isBroadcast = vm.envBool("IS_BROADCAST"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + PreTMX preTmx = new PreTMX(preTmxAdmin); + address deployedAddress = address(preTmx); + console.log("Deployed PreTMX at:", deployedAddress); + require(preTmx.owner() == preTmxAdmin, "PreTMX owner mismatch"); + require(preTmx.balanceOf(preTmxAdmin) == 1e9 ether, "PreTMX initial supply mismatch"); + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + + string memory deploymentEnv = string( + abi.encodePacked( + "NETWORK=", + coreParams.network, + "\nDEPLOYED_AT=", + vm.toString(block.timestamp), + "\nGIT_BRANCH=", + getGitBranch(), + "\nGIT_COMMIT_HASH=", + vm.toString(getGitCommitHash()), + "\nBLOCK_NUMBER=", + vm.toString(block.number), + "\nBLOCK_TIMESTAMP=", + vm.toString(block.timestamp), + "\nDEPLOYER_ADDRESS=", + vm.toString(vm.addr(deployerPrivateKey)), + "\nADMIN_ADDRESS=", + vm.toString(adminAddr) + ) + ); + deploymentEnv = string(abi.encodePacked(deploymentEnv, "\nPRE_TMX_ADDRESS=", vm.toString(deployedAddress))); + + string memory path = string.concat( + vm.projectRoot(), + "/deployments/", + coreParams.network, + "/", + coreParams.network, + "-PRE-TMX-", + vm.toString(block.timestamp), + ".env" + ); + if (isBroadcast) { + vm.writeFile(path, deploymentEnv); + } + } +} diff --git a/script/deploy/DeployPriceFeedFactory.s.sol b/script/deploy/DeployPriceFeedFactory.s.sol new file mode 100644 index 00000000..28ce9d2c --- /dev/null +++ b/script/deploy/DeployPriceFeedFactory.s.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; + +contract DeployPriceFeedFactory is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + bool isBroadcast; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + isBroadcast = vm.envBool("IS_BROADCAST"); + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + coreParams.adminAddr = adminAddr; + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + if (coreContracts.priceFeedFactory == TermMaxPriceFeedFactoryV2(address(0))) { + coreContracts.priceFeedFactory = new TermMaxPriceFeedFactoryV2(); + if (isBroadcast) { + writeAsJson( + string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ), + coreParams, + coreContracts + ); + } + console.log("Deployed TermMaxPriceFeedFactoryV2 at:", address(coreContracts.priceFeedFactory)); + } else { + revert("PriceFeedFactory already deployed"); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + } +} diff --git a/script/deploy/DeployTermMaxViewer.s.sol b/script/deploy/DeployTermMaxViewer.s.sol new file mode 100644 index 00000000..0359bd33 --- /dev/null +++ b/script/deploy/DeployTermMaxViewer.s.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import {UniversalFactory} from "contracts/v2/tokenomics/UniversalFactory.sol"; + +contract DeployTermMaxViewer is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + bool isBroadcast; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + isBroadcast = vm.envBool("IS_BROADCAST"); + string memory networkUpper = toUpper(coreParams.network); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + coreParams.adminAddr = adminAddr; + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + if (coreContracts.termMaxViewer == TermMaxViewer(address(0))) { + TermMaxViewer termMaxViewer = deployMarketViewer(address(coreContracts.accessManager)); + coreContracts.termMaxViewer = termMaxViewer; + console.log("Deployed TermMaxViewer at:", address(termMaxViewer)); + } else { + upgradeMarketViewer(coreContracts.accessManager, address(coreContracts.termMaxViewer)); + console.log("Upgraded TermMaxViewer at:", address(coreContracts.termMaxViewer)); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + + if (isBroadcast) { + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + writeAsJson(deploymentPath, coreParams, coreContracts); + } + } +} diff --git a/script/deploy/DeployUSPCPriceFeedAdapter.s.sol b/script/deploy/DeployUSPCPriceFeedAdapter.s.sol new file mode 100644 index 00000000..22d15591 --- /dev/null +++ b/script/deploy/DeployUSPCPriceFeedAdapter.s.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {TermMaxUSPCPriceFeedAdapter} from "contracts/v2/oracle/priceFeeds/TermMaxUSPCPriceFeedAdapter.sol"; +import {DeployBaseV2} from "script/deploy/DeployBaseV2.s.sol"; + +/** + * @title DeployUSPCPriceFeedAdapter + * @notice Script to deploy TermMaxUSPCPriceFeedAdapter on B2 mainnet + * @dev This script deploys an adapter that wraps the USPC oracle + * + * Usage: + * forge script script/deploy/DeployUSPCPriceFeedAdapter.s.sol:DeployUSPCPriceFeedAdapter \ + * --rpc-url $B2_MAINNET_RPC_URL \ + * --private-key $B2_MAINNET_DEPLOYER_PRIVATE_KEY \ + * --broadcast \ + * --verify + */ +contract DeployUSPCPriceFeedAdapter is DeployBaseV2 { + // B2 mainnet USPC oracle + asset addresses + address constant USPC_ORACLE = 0x5eC0C20A83554eC1BBC0F1D3414BB8746a04acD4; + address constant USPC_ASSET = 0xdc807c3a618B6B1248481783def7ED76700B9eC6; + + // Network configuration + string network; + address deployerAddr; + uint256 deployerPrivateKey; + + function setUp() public { + // Load network configuration from environment variables + network = vm.envOr("NETWORK", string("eth-mainnet")); + string memory networkUpper = StringHelper.toUpper(network); + + // Load deployer private key + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + deployerPrivateKey = vm.envUint(privateKeyVar); + deployerAddr = vm.addr(deployerPrivateKey); + + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", network); + if (!vm.exists(deploymentsDir)) { + vm.createDir(deploymentsDir, true); + } + + console.log("===== Deployment Configuration ====="); + console.log("Network:", network); + console.log("Deployer:", deployerAddr); + console.log("Deployer balance:", deployerAddr.balance); + console.log("USPC Oracle:", USPC_ORACLE); + console.log("USPC Asset:", USPC_ASSET); + } + + function run() public { + console.log("\n===== Starting Deployment ====="); + + vm.startBroadcast(deployerPrivateKey); + + // Deploy TermMaxUSPCPriceFeedAdapter + TermMaxUSPCPriceFeedAdapter adapter = new TermMaxUSPCPriceFeedAdapter(USPC_ORACLE, USPC_ASSET); + + vm.stopBroadcast(); + + console.log("\n===== Deployment Successful ====="); + console.log("TermMaxUSPCPriceFeedAdapter deployed at:", address(adapter)); + console.log("Wrapped USPC oracle:", USPC_ORACLE); + console.log("Asset tracked:", USPC_ASSET); + + // Verify adapter configuration + console.log("\n===== Verifying Adapter Configuration ====="); + console.log("Decimals:", adapter.decimals()); + console.log("Description:", adapter.description()); + + // Get price data + (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) = + adapter.latestRoundData(); + console.log("\n===== Price Data ====="); + console.log("Round ID:", roundId); + console.log("Answer (USPC/USDC with 18 decimals):", answer); + console.log("Price (human readable):", uint256(answer) / 1e18); + console.log("Started At:", startedAt); + console.log("Updated At:", updatedAt); + console.log("Answered In Round:", answeredInRound); + + // Save deployment info + saveDeploymentInfo(address(adapter)); + } + + function saveDeploymentInfo(address adapterAddress) internal { + console.log("\n===== Saving Deployment Info ====="); + + // Get git info + string memory gitBranch = getGitBranch(); + bytes memory gitCommitHash = getGitCommitHash(); + + // Create JSON output + string memory json = string( + abi.encodePacked( + "{\n", + ' "network": "', + network, + '",\n', + ' "deployedAt": "', + vm.toString(block.timestamp), + '",\n', + ' "gitBranch": "', + gitBranch, + '",\n', + ' "gitCommitHash": "', + vm.toString(gitCommitHash), + '",\n', + ' "blockInfo": {\n', + ' "number": "', + vm.toString(block.number), + '",\n', + ' "timestamp": "', + vm.toString(block.timestamp), + '"\n', + " },\n", + ' "deployer": "', + vm.toString(deployerAddr), + '",\n', + ' "contracts": {\n', + ' "termMaxUSPCPriceFeedAdapter": "', + vm.toString(adapterAddress), + '",\n', + ' "uspcOracle": "', + vm.toString(USPC_ORACLE), + '",\n', + ' "uspcAsset": "', + vm.toString(USPC_ASSET), + '"\n', + " }\n", + "}" + ) + ); + + // Save to JSON file + string memory jsonPath = + string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-uspc-price-feed-adapter.json"); + vm.writeFile(jsonPath, json); + console.log("Deployment info saved to:", jsonPath); + } +} diff --git a/script/deploy/DeployUniswapPriceFeed.s.sol b/script/deploy/DeployUniswapPriceFeed.s.sol new file mode 100644 index 00000000..149f5f41 --- /dev/null +++ b/script/deploy/DeployUniswapPriceFeed.s.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import { + TermMaxPancakeTWAPPriceFeed, + TermMaxUniswapTWAPPriceFeed +} from "contracts/v2/oracle/priceFeeds/TermMaxPancakeTWAPPriceFeed.sol"; + +contract DeployUniswapPriceFeed is DeployBaseV2 { + uint256 deployerPrivateKey; + address adminAddr; + address accessManagerAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + string oracleEnvs; + string configPath = "-uniswap-pairs.json"; + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + string memory networkUpper = toUpper(coreParams.network); + configPath = string.concat(vm.projectRoot(), "/script/deploy/deploydata/", coreParams.network, configPath); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + adminAddr = vm.envAddress(adminVar); + + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + string memory json = vm.readFile(configPath); + uint256 totalPairs = vm.parseJsonUint(json, ".configNum"); + for (uint256 i = 0; i < totalPairs; i++) { + address pool = vm.parseJsonAddress(json, string.concat(".configs.configs_", vm.toString(i), ".pool")); + address baseToken = + vm.parseJsonAddress(json, string.concat(".configs.configs_", vm.toString(i), ".baseToken")); + address quoteToken = + vm.parseJsonAddress(json, string.concat(".configs.configs_", vm.toString(i), ".quoteToken")); + bool isPancake = vm.parseJsonBool(json, string.concat(".configs.configs_", vm.toString(i), ".isPancake")); + uint256 duration = vm.parseJsonUint(json, string.concat(".configs.configs_", vm.toString(i), ".duration")); + console.log("Pool:", pool); + console.log("Base Token:", baseToken); + console.log("Quote Token:", quoteToken); + console.log("Is Pancake:", isPancake); + console.log("Duration:", duration); + TermMaxUniswapTWAPPriceFeed priceFeed; + if (isPancake) { + priceFeed = new TermMaxPancakeTWAPPriceFeed(pool, uint32(duration), baseToken, quoteToken); + } else { + priceFeed = new TermMaxUniswapTWAPPriceFeed(pool, uint32(duration), baseToken, quoteToken); + } + console.log( + "Deployed TermMax", isPancake ? "Pancake" : "Uniswap", "TWAP Price Feed at:", address(priceFeed) + ); + oracleEnvs = string.concat( + oracleEnvs, + "TERM_MAX_", + toUpper(vm.toString(baseToken)), + "_", + toUpper(vm.toString(quoteToken)), + "_PRICE_FEED_ADDRESS=", + vm.toString(address(priceFeed)), + "\n" + ); + } + + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + console.log("===== Core Info ====="); + console.log("Deployer:", coreParams.deployerAddr); + console.log("Admin:", adminAddr); + + string memory deploymentEnv = string( + abi.encodePacked( + "NETWORK=", + coreParams.network, + "\nDEPLOYED_AT=", + vm.toString(block.timestamp), + "\nGIT_BRANCH=", + getGitBranch(), + "\nGIT_COMMIT_HASH=", + vm.toString(getGitCommitHash()), + "\nBLOCK_NUMBER=", + vm.toString(block.number), + "\nBLOCK_TIMESTAMP=", + vm.toString(block.timestamp), + "\nDEPLOYER_ADDRESS=", + vm.toString(vm.addr(deployerPrivateKey)), + "\nADMIN_ADDRESS=", + vm.toString(adminAddr) + ) + ); + deploymentEnv = string(abi.encodePacked(deploymentEnv, "\n", oracleEnvs)); + + string memory path = string.concat( + vm.projectRoot(), + "/deployments/", + coreParams.network, + "/", + coreParams.network, + "-v2-uniswap-priceFeeds-", + vm.toString(block.timestamp), + ".env" + ); + vm.writeFile(path, deploymentEnv); + } +} diff --git a/script/deploy/DeployVault.s.sol b/script/deploy/DeployVault.s.sol index 353a5b9d..9d563d99 100644 --- a/script/deploy/DeployVault.s.sol +++ b/script/deploy/DeployVault.s.sol @@ -34,13 +34,7 @@ contract DeployVaults is DeployBaseV2 { coreParams.isMainnet = vm.envBool("IS_MAINNET"); coreParams.isL2Network = vm.envBool("IS_L2"); if (coreParams.isMainnet) { - string memory uniswapV3RouterVar = string.concat(networkUpper, "_UNISWAP_V3_ROUTER_ADDRESS"); - string memory odosV2RouterVar = string.concat(networkUpper, "_ODOS_V2_ROUTER_ADDRESS"); - string memory pendleSwapV3RouterVar = string.concat(networkUpper, "_PENDLE_SWAP_V3_ROUTER_ADDRESS"); string memory oracleTimelockVar = string.concat(networkUpper, "_ORACLE_TIMELOCK"); - coreParams.uniswapV3Router = vm.envAddress(uniswapV3RouterVar); - coreParams.odosV2Router = vm.envAddress(odosV2RouterVar); - coreParams.pendleSwapV3Router = vm.envAddress(pendleSwapV3RouterVar); coreParams.oracleTimelock = vm.envUint(oracleTimelockVar); } if (coreParams.isL2Network) { @@ -100,7 +94,7 @@ contract DeployVaults is DeployBaseV2 { console.log(" Vault maxCapacity:", params.maxCapacity); console.log(" Vault minimal apy:", params.minApy); - address vault = coreContracts.vaultFactory.createVault(params, 0); + address vault = coreContracts.vaultFactory.createVault(params, 1); console.log("Deployed TermMaxVaultV2 at:", vault); vaults.push(vault); } diff --git a/script/deploy/DeployWhitelistFeature.s.sol b/script/deploy/DeployWhitelistFeature.s.sol new file mode 100644 index 00000000..aa94e50a --- /dev/null +++ b/script/deploy/DeployWhitelistFeature.s.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {OrderConfig} from "contracts/v1/storage/TermMaxStorage.sol"; +import {JsonLoader} from "script/utils/JsonLoader.sol"; +import {OrderV2ConfigurationParams} from "contracts/v2/vault/VaultStorageV2.sol"; +import {ITermMaxOrderV2} from "contracts/v2/ITermMaxOrderV2.sol"; +import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; +import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; +import {SimpleAggregator} from "contracts/v2/oracle/SimpleAggregator.sol"; +import {StringHelper} from "script/utils/StringHelper.sol"; +import {ITermMaxMarket} from "contracts/v1/ITermMaxMarket.sol"; + +contract DeployWhitelistFeature is DeployBaseV2 { + using StringHelper for string; + // Network-specific config loaded from environment variables + + uint256 deployerPrivateKey; + + CoreParams coreParams; + DeployedContracts coreContracts; + bool isBroadcast; + + address aavePool; + uint16 aaveReferralCode; + + bool isEth; + bool isArb; + bool isBnb; + bool isBera; + bool isHyper; + bool isXlayer; + bool isBase; + bool isB2; + bool isPharos; + + address automaticDeployer = vm.envAddress("AUTOMATIC_DEPLOYER_ADDRESS"); + address interestManager = vm.envAddress("INTEREST_MANAGER_ADDRESS"); + + function setUp() public { + // Load network from environment variable + coreParams.network = vm.envString("NETWORK"); + isBroadcast = vm.envBool("IS_BROADCAST"); + string memory networkUpper = toUpper(coreParams.network); + _getNetWork(); + + // Load network-specific configuration + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + deployerPrivateKey = vm.envUint(privateKeyVar); + coreParams.deployerAddr = vm.addr(deployerPrivateKey); + coreParams.adminAddr = vm.envAddress(adminVar); + + aavePool = vm.envAddress(string.concat(networkUpper, "_AAVE_POOL")); + aaveReferralCode = uint16(vm.envUint(string.concat(networkUpper, "_AAVE_REFERRAL_CODE"))); + coreParams.isMainnet = vm.envBool("IS_MAINNET"); + coreParams.isL2Network = vm.envBool("IS_L2"); + { + // Create deployments directory if it doesn't exist + string memory deploymentsDir = string.concat(vm.projectRoot(), "/deployments/", coreParams.network); + if (!vm.exists(deploymentsDir)) { + // Directory doesn't exist, create it + vm.createDir(deploymentsDir, true); + } + } + + string memory deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-access-manager.json" + ); + string memory json = vm.readFile(deploymentPath); + address accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ); + if (vm.exists(deploymentPath)) { + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + } + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + console.log("Using existing WhitelistManager at:", address(coreContracts.whitelistManager)); + } + + function run() public { + console.log("Network:", coreParams.network); + console.log("Deployer balance:", coreParams.deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + // upgrade contracts + console.log("Upgrading contracts to latest versions..."); + console.log("Upgrade AccessManager implementation to latest version"); + address newAccessManagerImpl = address(new AccessManagerV2()); + console.log("Deployed new AccessManager implementation at:", newAccessManagerImpl); + // log upgrade tx calldata for AccessManager used in safe wallet transaction + bytes memory accessManagerUpgradeCalldata = + abi.encodeWithSelector(UUPSUpgradeable.upgradeToAndCall.selector, newAccessManagerImpl, ""); + console.log("AccessManager upgrade calldata:"); + console.logBytes(accessManagerUpgradeCalldata); + + console.log("Upgrade WhitelistManager implementation to latest version"); + address newWhitelistManagerImpl = address(new WhitelistManager(address(coreContracts.accessManager))); + console.log("Deployed new WhitelistManager implementation at:", newWhitelistManagerImpl); + coreContracts.accessManager.upgradeSubContract(coreContracts.whitelistManager, newWhitelistManagerImpl, ""); + + console.log("Upgrade TermMaxRouterV1 implementation to latest version"); + address newTermMaxRouterV1Impl = address(new TermMaxRouter_V1_1_2(address(coreContracts.accessManager))); + console.log("Deployed new TermMaxRouterV1 implementation at:", newTermMaxRouterV1Impl); + coreContracts.accessManager.upgradeSubContract(coreContracts.routerV1, newTermMaxRouterV1Impl, ""); + + console.log("Upgrade TermMaxRouterV2 implementation to latest version"); + address newTermMaxRouterV2Impl = address(new TermMaxRouterV2(address(coreContracts.accessManager))); + console.log("Deployed new TermMaxRouterV2 implementation at:", newTermMaxRouterV2Impl); + coreContracts.accessManager.upgradeSubContract(coreContracts.router, newTermMaxRouterV2Impl, ""); + + console.log("Upgrade MakerHelper implementation to latest version"); + address newMakerHelperImpl = address(new MakerHelper(address(coreContracts.whitelistManager))); + console.log("Deployed new MakerHelper implementation at:", newMakerHelperImpl); + coreContracts.accessManager.upgradeSubContract(coreContracts.makerHelper, newMakerHelperImpl, ""); + + // new market factory + if (isBnb) { + (coreContracts.factory, coreContracts.alphaFactory) = + deployMarketFactories(address(coreContracts.accessManager), address(coreContracts.whitelistManager)); + console.log("Deployed new TermMaxMarketFactory at:", address(coreContracts.factory)); + console.log("Deployed new TermMaxAlphaFactory at:", address(coreContracts.alphaFactory)); + } else { + coreContracts.factory = + deployFactory(address(coreContracts.accessManager), address(coreContracts.whitelistManager)); + console.log("Deployed new TermMaxMarketFactory at:", address(coreContracts.factory)); + } + + // new vault factory + coreContracts.vaultFactory = + deployVaultFactory(address(coreContracts.accessManager), address(coreContracts.whitelistManager)); + console.log("Deployed new TermMaxVaultFactory at:", address(coreContracts.vaultFactory)); + + // new 4626 factory + + address stableERC4626For4626Implementation; + address stableERC4626ForAaveImplementation; + address variableERC4626ForAaveImplementation; + address stableERC4626ForVenusImplementation; + address stableERC4626ForCustomizeImplementation; + { + // read existing implementations from core-v2 deployment if exist, otherwise deploy new ones + stableERC4626For4626Implementation = coreContracts.tmx4626Factory.stableERC4626For4626Implementation(); + stableERC4626ForAaveImplementation = coreContracts.tmx4626Factory.stableERC4626ForAaveImplementation(); + variableERC4626ForAaveImplementation = coreContracts.tmx4626Factory.variableERC4626ForAaveImplementation(); + try coreContracts.tmx4626Factory.stableERC4626ForVenusImplementation() returns (address addr) { + stableERC4626ForVenusImplementation = addr; + } catch { + console.log("Ignoring missing TERMMAX_4626_FOR_VENUS_IMPLEMENTATION"); + } + try coreContracts.tmx4626Factory.stableERC4626ForCustomizeImplementation() returns (address addr) { + stableERC4626ForCustomizeImplementation = addr; + } catch { + stableERC4626ForCustomizeImplementation = address(new StableERC4626ForCustomize()); + console.log( + "Deploying new StableERC4626ForCustomize implementation at:", + stableERC4626ForCustomizeImplementation + ); + } + } + + coreContracts.tmx4626Factory = new TermMax4626Factory( + address(coreContracts.accessManager), + stableERC4626For4626Implementation, + stableERC4626ForAaveImplementation, + stableERC4626ForVenusImplementation, + variableERC4626ForAaveImplementation, + stableERC4626ForCustomizeImplementation, + address(coreContracts.whitelistManager) + ); + console.log("Deployed TermMax4626Factory at:", address(coreContracts.tmx4626Factory)); + vm.stopBroadcast(); + + uint256 whitelistFactoryCount = 3; + if (address(coreContracts.alphaFactory) != address(0)) { + whitelistFactoryCount++; + } + uint256 grantCount = whitelistFactoryCount + 4; + bytes32[] memory roles = new bytes32[](grantCount); + address[] memory grantees = new address[](grantCount); + + uint256 i; + roles[i] = coreContracts.accessManager.WHITELIST_ROLE(); + grantees[i] = address(coreContracts.factory); + unchecked { + ++i; + } + + if (address(coreContracts.alphaFactory) != address(0)) { + roles[i] = coreContracts.accessManager.WHITELIST_ROLE(); + grantees[i] = address(coreContracts.alphaFactory); + unchecked { + ++i; + } + } + + roles[i] = coreContracts.accessManager.WHITELIST_ROLE(); + grantees[i] = address(coreContracts.vaultFactory); + unchecked { + ++i; + } + + roles[i] = coreContracts.accessManager.WHITELIST_ROLE(); + grantees[i] = address(coreContracts.tmx4626Factory); + unchecked { + ++i; + } + + roles[i] = coreContracts.accessManager.VAULT_DEPLOYER_ROLE(); + grantees[i] = automaticDeployer; + unchecked { + ++i; + } + + roles[i] = coreContracts.accessManager.POOL_DEPLOYER_ROLE(); + grantees[i] = automaticDeployer; + unchecked { + ++i; + } + + roles[i] = coreContracts.accessManager.STABLE_ERC4626_BUFFER_ROLE(); + grantees[i] = automaticDeployer; + unchecked { + ++i; + } + + roles[i] = coreContracts.accessManager.STABLE_ERC4626_INCOME_WITHDRAW_ROLE(); + grantees[i] = interestManager; + + console.log("Granting roles via safe wallet..."); + for (uint256 j = 0; j < grantCount; ++j) { + bytes memory grantRoleCalldata = + abi.encodeWithSelector(coreContracts.accessManager.grantRole.selector, roles[j], grantees[j]); + console.log("grantRole to:", grantees[j]); + console.log("role:"); + console.logBytes32(roles[j]); + console.log("grantee:", grantees[j]); + console.log("grantRole calldata:"); + console.logBytes(grantRoleCalldata); + } + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + + writeAsJson( + string.concat( + vm.projectRoot(), "/deployments/", coreParams.network, "/", coreParams.network, "-core-v2.json" + ), + coreParams, + coreContracts + ); + } + + function _getNetWork() internal { + isEth = keccak256(bytes(coreParams.network)) == keccak256(bytes("eth-mainnet")); + isArb = keccak256(bytes(coreParams.network)) == keccak256(bytes("arb-mainnet")); + isBnb = keccak256(bytes(coreParams.network)) == keccak256(bytes("bnb-mainnet")); + isBera = keccak256(bytes(coreParams.network)) == keccak256(bytes("bera-mainnet")); + isHyper = keccak256(bytes(coreParams.network)) == keccak256(bytes("hyperevm-mainnet")); + isXlayer = keccak256(bytes(coreParams.network)) == keccak256(bytes("xlayer-mainnet")); + isBase = keccak256(bytes(coreParams.network)) == keccak256(bytes("base-mainnet")); + isB2 = keccak256(bytes(coreParams.network)) == keccak256(bytes("b2-mainnet")); + isPharos = keccak256(bytes(coreParams.network)) == keccak256(bytes("pharos-mainnet")); + } +} diff --git a/script/deploy/PlaceOrder.s.sol b/script/deploy/PlaceOrder.s.sol new file mode 100644 index 00000000..81cf2eea --- /dev/null +++ b/script/deploy/PlaceOrder.s.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import "forge-std/console.sol"; +import "./DeployBaseV2.s.sol"; +import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {OrderConfig, CurveCut} from "contracts/v1/storage/TermMaxStorage.sol"; +import {JsonLoader} from "script/utils/JsonLoader.sol"; +import {OrderV2ConfigurationParams} from "contracts/v2/vault/VaultStorageV2.sol"; +import {ITermMaxOrderV2} from "contracts/v2/ITermMaxOrderV2.sol"; +import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; +import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; + +contract PlaceOrder is DeployBaseV2 { + // Network-specific config loaded from environment variables + string network; + uint256 deployerPrivateKey; + address deployerAddr; + address adminAddr; + + CoreParams coreParams; + DeployedContracts coreContracts; + + string configPath = "-order.json"; + + // Data parsed from single order json (arb-sepolia-order.json style) + struct ParsedOrderJson { + address market; + address maker; + uint256 virtualXtReserve; + address pool; + uint256 initialLiquidity; + OrderConfig orderConfig; + } + + // ------------------------- JSON PARSING (Single Order) ------------------------- + function _parseSingleOrderJson(string memory jsonData) internal view returns (ParsedOrderJson memory p) { + // maker / pool may be placeholder. Ensure valid hex before attempting readAddress to avoid revert. + // We expect user to replace placeholder addresses with real ones prior to execution. + p.market = vm.parseJsonAddress(jsonData, ".market"); + p.maker = vm.parseJsonAddress(jsonData, ".maker"); + p.pool = vm.parseJsonAddress(jsonData, ".pool"); + p.virtualXtReserve = vm.parseJsonUint(jsonData, ".virtualXtReserve"); + p.initialLiquidity = vm.parseJsonUint(jsonData, ".initialLiquidity"); + // orderConfig + string memory orderConfigPrefix = ".orderConfig"; + OrderConfig memory oc = JsonLoader.getOrderConfigFromJson(jsonData, orderConfigPrefix); + p.orderConfig = oc; + } + + function _getCurveString(CurveCut memory c) internal pure returns (string memory) { + return string.concat( + "xtReserve=", + vm.toString(c.xtReserve), + " liqSquare=", + vm.toString(c.liqSquare), + " offset=", + vm.toString(c.offset) + ); + } + + function setUp() public { + // Load network from environment variable + network = vm.envString("NETWORK"); + configPath = string.concat(vm.projectRoot(), "/script/deploy/deploydata/", network, configPath); + // Load network-specific configuration + { + string memory networkUpper = toUpper(network); + string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); + string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); + + deployerPrivateKey = vm.envUint(privateKeyVar); + adminAddr = vm.envAddress(adminVar); + coreParams.adminAddr = adminAddr; + deployerAddr = vm.addr(deployerPrivateKey); + + console.log("Admin:", adminAddr); + console.log("Deployer:", deployerAddr); + } + + string memory deploymentPath = + string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-access-manager.json"); + string memory json = vm.readFile(deploymentPath); + address accessManagerAddr = vm.parseJsonAddress(json, ".contracts.accessManager"); + + deploymentPath = string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-core-v2.json"); + json = vm.readFile(deploymentPath); + coreContracts = readDeployData(json); + console.log("Using existing AccessManagerV2 at:", accessManagerAddr); + coreContracts.accessManager = AccessManagerV2(accessManagerAddr); + } + + function run() public { + console.log("Network:", network); + console.log("Deployer balance:", deployerAddr.balance); + + vm.startBroadcast(deployerPrivateKey); + // Detect whether config file is single order json (contains .orderConfig) or market configs list + string memory rawJson = vm.readFile(configPath); + ParsedOrderJson memory parsed = _parseSingleOrderJson(rawJson); + { + console.log("Single Order JSON detected. Parsed values:"); + console.log(" Market:", parsed.market); + console.log(" Maker:", parsed.maker); + console.log(" Virtual XT Reserve:", parsed.virtualXtReserve); + console.log(" Initial Liquidity:", parsed.initialLiquidity); + console.log(" Pool (may be zero if placeholder):", parsed.pool); + console.log(" OrderConfig.gtId:", parsed.orderConfig.gtId); + console.log(" OrderConfig.maxXtReserve:", parsed.orderConfig.maxXtReserve); + console.log(" Lend curve cuts length:", parsed.orderConfig.curveCuts.lendCurveCuts.length); + for (uint256 i; i < parsed.orderConfig.curveCuts.lendCurveCuts.length; i++) { + CurveCut memory c = parsed.orderConfig.curveCuts.lendCurveCuts[i]; + string memory str = string.concat(" Lend[", vm.toString(i), "] ", _getCurveString(c)); + console.log(str); + } + console.log(" Borrow curve cuts length:", parsed.orderConfig.curveCuts.borrowCurveCuts.length); + for (uint256 i; i < parsed.orderConfig.curveCuts.borrowCurveCuts.length; i++) { + CurveCut memory c2 = parsed.orderConfig.curveCuts.borrowCurveCuts[i]; + string memory str = string.concat(" Borrow[", vm.toString(i), "] ", _getCurveString(c2)); + console.log(str); + } + } + // Place order on TermMaxOrderV2 + TermMaxMarketV2 market = TermMaxMarketV2(parsed.market); + OrderInitialParams memory params; + params.maker = parsed.maker; + params.virtualXtReserve = uint128(parsed.virtualXtReserve); + params.pool = IERC4626(parsed.pool); + params.orderConfig = parsed.orderConfig; + + address order = address(market.createOrder(params)); + console.log("Order created at address:", order); + require(TermMaxOrderV2(order).maker() == parsed.maker, "Order maker mismatch"); + if (parsed.initialLiquidity > 0) { + (IERC20 ft, IERC20 xt,,, IERC20 debtToken) = market.tokens(); // Placeholder for adding liquidity logic + debtToken.approve(address(market), parsed.initialLiquidity); + market.mint(order, parsed.initialLiquidity); + require(ft.balanceOf(order) == parsed.initialLiquidity, "Initial liquidity mint failed"); + require(xt.balanceOf(order) == parsed.initialLiquidity, "Initial liquidity mint failed"); + } + vm.stopBroadcast(); + + console.log("===== Git Info ====="); + console.log("Git branch:", getGitBranch()); + console.log("Git commit hash:"); + console.logBytes(getGitCommitHash()); + console.log(); + + console.log("===== Block Info ====="); + console.log("Block number:", block.number); + console.log("Block timestamp:", block.timestamp); + console.log(); + } +} diff --git a/script/deploy/UpdateTreasurer.s.sol b/script/deploy/UpdateTreasurer.s.sol deleted file mode 100644 index 1b537d26..00000000 --- a/script/deploy/UpdateTreasurer.s.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {Script} from "forge-std/Script.sol"; -import {VmSafe} from "forge-std/Vm.sol"; -import "forge-std/console.sol"; -import "./DeployBaseV2.s.sol"; -import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import {OrderConfig} from "contracts/v1/storage/TermMaxStorage.sol"; -import {JsonLoader} from "script/utils/JsonLoader.sol"; -import {OrderV2ConfigurationParams} from "contracts/v2/vault/VaultStorageV2.sol"; -import {ITermMaxOrderV2} from "contracts/v2/ITermMaxOrderV2.sol"; -import {ITermMaxMarketV2} from "contracts/v2/ITermMaxMarketV2.sol"; -import {ITermMaxMarket} from "contracts/v1/ITermMaxMarket.sol"; -import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; -import {TermMaxMarketV2} from "contracts/v2/TermMaxMarketV2.sol"; - -contract DeployMarketsScript is DeployBaseV2 { - // Network-specific config loaded from environment variables - string network; - uint256 deployerPrivateKey; - address deployerAddr; - address adminAddr; - - CoreParams coreParams; - DeployedContracts coreContracts; - - address treasurerAddr; - - function setUp() public { - // Load network from environment variable - network = vm.envString("NETWORK"); - // Load network-specific configuration - { - string memory networkUpper = toUpper(network); - string memory privateKeyVar = string.concat(networkUpper, "_DEPLOYER_PRIVATE_KEY"); - string memory adminVar = string.concat(networkUpper, "_ADMIN_ADDRESS"); - - deployerPrivateKey = vm.envUint(privateKeyVar); - adminAddr = vm.envAddress(adminVar); - deployerAddr = vm.addr(deployerPrivateKey); - treasurerAddr = vm.envAddress(string.concat(networkUpper, "_TREASURER_ADDRESS")); - - console.log("Admin:", adminAddr); - console.log("Deployer:", deployerAddr); - console.log("Treasurer:", treasurerAddr); - } - - string memory deploymentPath = - string.concat(vm.projectRoot(), "/deployments/", network, "/", network, "-access-manager.json"); - string memory json = vm.readFile(deploymentPath); - coreContracts.accessManager = AccessManagerV2(vm.parseJsonAddress(json, ".contracts.accessManager")); - } - - function run() public { - console.log("Network:", network); - console.log("Deployer balance:", deployerAddr.balance); - address[] memory markets = new address[](4); - markets[0] = 0x6e4b0B37f45E85467AAEF5504d7262C45f047D88; - markets[1] = 0xE3C3eC217C779D854b1Cf4A8260B35378B5C5d78; - markets[2] = 0xA4E200dc744640A7205008E0667ADBe861EE71fa; - markets[3] = 0xe36212B6800C07dB575d29444547535dEBd92D64; - - vm.startBroadcast(deployerPrivateKey); - { - for (uint256 i = 0; i < markets.length; i++) { - MarketConfig memory config = TermMaxMarketV2(markets[i]).config(); - console.log("Market:", markets[i]); - console.log(" Name:", IERC20Metadata(markets[i]).name()); - config.treasurer = treasurerAddr; - coreContracts.accessManager.updateMarketConfig(ITermMaxMarket(markets[i]), config); - } - } - vm.stopBroadcast(); - - console.log("===== Git Info ====="); - console.log("Git branch:", getGitBranch()); - console.log("Git commit hash:"); - console.logBytes(getGitCommitHash()); - console.log(); - - console.log("===== Block Info ====="); - console.log("Block number:", block.number); - console.log("Block timestamp:", block.timestamp); - console.log(); - } -} diff --git a/script/utils/JsonLoader.sol b/script/utils/JsonLoader.sol index 888b9cd9..853fe467 100644 --- a/script/utils/JsonLoader.sol +++ b/script/utils/JsonLoader.sol @@ -7,6 +7,7 @@ import {MarketConfig, FeeConfig, LoanConfig} from "contracts/v1/storage/TermMaxS import {VaultInitialParamsV2, IERC20, IERC4626} from "contracts/v2/storage/TermMaxStorageV2.sol"; import {StakingBuffer} from "contracts/v2/tokens/StakingBuffer.sol"; import {IOracleV2, AggregatorV3Interface} from "contracts/v2/oracle/OracleAggregatorV2.sol"; +import {OrderConfig, CurveCut} from "contracts/v1/storage/TermMaxStorage.sol"; library JsonLoader { using stdJson for string; @@ -300,4 +301,45 @@ library JsonLoader { vm.parseInt(jsonData.readString(string.concat(configPrefix, ".oracleParams.minPrice"))); return oracleConfig; } + + function getOrderConfigFromJson(string memory testdataJSON, string memory key) + internal + pure + returns (OrderConfig memory orderConfig) + { + orderConfig.maxXtReserve = vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(key, ".maxXtReserve"))); + orderConfig.gtId = vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(key, ".gtId"))); + + { + string memory curveCutsPath = string.concat(key, ".borrowCurveCuts"); + uint256 length = + vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(key, ".borrowCurveCuts.length"))); + orderConfig.curveCuts.borrowCurveCuts = new CurveCut[](length); + + for (uint256 i = 0; i < length; i++) { + string memory indexPath = string.concat(curveCutsPath, ".", vm.toString(i)); + orderConfig.curveCuts.borrowCurveCuts[i].xtReserve = + vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".xtReserve"))); + orderConfig.curveCuts.borrowCurveCuts[i].liqSquare = + vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".liqSquare"))); + orderConfig.curveCuts.borrowCurveCuts[i].offset = + vm.parseInt(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".offset"))); + } + } + { + string memory curveCutsPath = string.concat(key, ".lendCurveCuts"); + uint256 length = vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(key, ".lendCurveCuts.length"))); + orderConfig.curveCuts.lendCurveCuts = new CurveCut[](length); + + for (uint256 i = 0; i < length; i++) { + string memory indexPath = string.concat(curveCutsPath, ".", vm.toString(i)); + orderConfig.curveCuts.lendCurveCuts[i].xtReserve = + vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".xtReserve"))); + orderConfig.curveCuts.lendCurveCuts[i].liqSquare = + vm.parseUint(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".liqSquare"))); + orderConfig.curveCuts.lendCurveCuts[i].offset = + vm.parseInt(vm.parseJsonString(testdataJSON, string.concat(indexPath, ".offset"))); + } + } + } } diff --git a/script/utils/StringHelper.sol b/script/utils/StringHelper.sol index 4723c5c3..883f1832 100644 --- a/script/utils/StringHelper.sol +++ b/script/utils/StringHelper.sol @@ -23,6 +23,25 @@ library StringHelper { return string(bUpper); } + function toLower(string memory str) internal pure returns (string memory) { + bytes memory bStr = bytes(str); + bytes memory bLower = new bytes(bStr.length); + for (uint256 i = 0; i < bStr.length; i++) { + // Convert underscore to hyphen + if (bStr[i] == 0x5F) { + bLower[i] = 0x2D; // '-' + continue; + } + // Convert uppercase to lowercase + if ((uint8(bStr[i]) >= 65) && (uint8(bStr[i]) <= 90)) { + bLower[i] = bytes1(uint8(bStr[i]) + 32); + } else { + bLower[i] = bStr[i]; + } + } + return string(bLower); + } + // Format options: // 'YYYYMMDD' = YYYYMMDD (e.g., 20250626) // 'DDMMMYYYY' = DDMMMYYYY (e.g., 26JUN2025)