From 0945ec46878e0bed3cd114cec370ee14529ad431 Mon Sep 17 00:00:00 2001 From: horsefacts Date: Wed, 4 Jun 2025 16:53:05 -0400 Subject: [PATCH] chore: TierRegistry deployment script --- .env.example | 13 +++- .env.local | 13 +++- .env.prod | 13 +++- .env.upgrade | 13 +++- .github/workflows/ci.yml | 5 +- docker-compose.yml | 14 ++--- foundry.toml | 5 +- script/DeployTierRegistry.s.sol | 86 +++++++++++++++++++++++++ src/TierRegistry.sol | 2 +- src/interfaces/ITierRegistry.sol | 2 +- test/Deploy/AuthKeys.t.sol | 2 +- test/Deploy/DeployL1.t.sol | 2 +- test/Deploy/DeployL2.t.sol | 2 +- test/Deploy/DeployTierRegistry.t.sol | 94 ++++++++++++++++++++++++++++ test/Deploy/UpgradeBundler.t.sol | 2 +- test/Deploy/UpgradeL2.t.sol | 2 +- test/TierRegistry/TierRegistry.t.sol | 2 +- 17 files changed, 241 insertions(+), 31 deletions(-) create mode 100644 script/DeployTierRegistry.s.sol create mode 100644 test/Deploy/DeployTierRegistry.t.sol diff --git a/.env.example b/.env.example index bfb2304f..8bb2ac60 100644 --- a/.env.example +++ b/.env.example @@ -30,9 +30,15 @@ FNAME_RESOLVER_SERVER_URL=https://fnames.farcaster.xyz/ccip/{sender}/{data}.json FNAME_RESOLVER_SIGNER_ADDRESS=0xBc5274eFc266311015793d89E9B591fa46294741 FNAME_RESOLVER_OWNER_ADDRESS=0x138356f24c7A16BE48978dE277a468F6C16A19a5 -# RPC endpoints for OP testnet and mainnet. -L1_MAINNET_RPC_URL= -L2_MAINNET_RPC_URL= +# Tier registry params +TIER_REGISTRY_VAULT_ADDRESS=0x53c6dA835c777AD11159198FBe11f95E5eE6B692 +TIER_REGISTRY_OWNER_ADDRESS=0x53c6dA835c777AD11159198FBe11f95E5eE6B692 +TIER_REGISTRY_MIGRATOR_ADDRESS=0x53c6dA835c777AD11159198FBe11f95E5eE6B692 + +# RPC endpoints +ETH_MAINNET_RPC_URL= +OP_MAINNET_RPC_URL= +BASE_MAINNET_RPC_URL= # Salts STORAGE_RENT_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c65360d99ba6ea4e0161f2b96c @@ -41,6 +47,7 @@ KEY_REGISTRY_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c62af4de6e1f03 SIGNED_KEY_REQUEST_VALIDATOR_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6610c0841333604016684800c BUNDLER_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6e451fc0a34ec4c008c9a31fa RECOVERY_PROXY_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6110eaaca06f77900dac1cad3 +TIER_REGISTRY_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6110eaaca06f77900dac1cad3 # Deployer address. DEPLOYER=0x6D2b70e39C6bc63763098e336323591eb77Cd0C6 diff --git a/.env.local b/.env.local index ff67da31..03b959b2 100644 --- a/.env.local +++ b/.env.local @@ -38,9 +38,15 @@ FNAME_RESOLVER_SERVER_URL=https://fnames.farcaster.xyz/ccip/{sender}/{data}.json FNAME_RESOLVER_SIGNER_ADDRESS=0xBc5274eFc266311015793d89E9B591fa46294741 FNAME_RESOLVER_OWNER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -# RPC endpoints for OP testnet and mainnet. -L2_MAINNET_RPC_URL= -L1_MAINNET_RPC_URL= +# Tier registry params +TIER_REGISTRY_VAULT_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +TIER_REGISTRY_OWNER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +TIER_REGISTRY_MIGRATOR_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +# RPC endpoints +ETH_MAINNET_RPC_URL= +OP_MAINNET_RPC_URL= +BASE_MAINNET_RPC_URL= STORAGE_RENT_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 ID_REGISTRY_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 @@ -48,6 +54,7 @@ KEY_REGISTRY_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000 SIGNED_KEY_REQUEST_VALIDATOR_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 BUNDLER_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 RECOVERY_PROXY_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 +TIER_REGISTRY_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 # Deployer address. # Default address is Anvil test account 1 diff --git a/.env.prod b/.env.prod index 9f2138a9..3bfdaa2c 100644 --- a/.env.prod +++ b/.env.prod @@ -30,9 +30,15 @@ FNAME_RESOLVER_SERVER_URL=https://fnames.farcaster.xyz/ccip/{sender}/{data}.json FNAME_RESOLVER_SIGNER_ADDRESS=0xBc5274eFc266311015793d89E9B591fa46294741 FNAME_RESOLVER_OWNER_ADDRESS=0x138356f24c7A16BE48978dE277a468F6C16A19a5 -# RPC endpoints for OP testnet and mainnet. -L1_MAINNET_RPC_URL= -L2_MAINNET_RPC_URL= +# Tier registry params +TIER_REGISTRY_VAULT_ADDRESS=0x0BDcA19c9801bb484285362fD5dd0c94592c874C +TIER_REGISTRY_OWNER_ADDRESS=0x53c6dA835c777AD11159198FBe11f95E5eE6B692 +TIER_REGISTRY_MIGRATOR_ADDRESS=0x2d93c2f74b2c4697f9ea85d0450148aa45d4d5a2 + +# RPC endpoints +ETH_MAINNET_RPC_URL= +OP_MAINNET_RPC_URL= +BASE_MAINNET_RPC_URL= # Salts STORAGE_RENT_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c65360d99ba6ea4e0161f2b96c @@ -41,6 +47,7 @@ KEY_REGISTRY_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c62af4de6e1f03 SIGNED_KEY_REQUEST_VALIDATOR_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6610c0841333604016684800c BUNDLER_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6e451fc0a34ec4c008c9a31fa RECOVERY_PROXY_CREATE2_SALT=0x6d2b70e39c6bc63763098e336323591eb77cd0c6110eaaca06f77900dac1cad3 +TIER_REGISTRY_CREATE2_SALT=0x299707e127cc77de01b9fd968bc0ff475f3c63425a6dbfc4658e47004603abdf # Deployer address. DEPLOYER=0x6D2b70e39C6bc63763098e336323591eb77Cd0C6 diff --git a/.env.upgrade b/.env.upgrade index 032bd742..0abb9c01 100644 --- a/.env.upgrade +++ b/.env.upgrade @@ -30,9 +30,15 @@ FNAME_RESOLVER_SERVER_URL=https://fnames.farcaster.xyz/ccip/{sender}/{data}.json FNAME_RESOLVER_SIGNER_ADDRESS=0xBc5274eFc266311015793d89E9B591fa46294741 FNAME_RESOLVER_OWNER_ADDRESS=0x138356f24c7A16BE48978dE277a468F6C16A19a5 -# RPC endpoints for OP testnet and mainnet. -L1_MAINNET_RPC_URL= -L2_MAINNET_RPC_URL= +# Tier registry params +TIER_REGISTRY_VAULT_ADDRESS=0x0BDcA19c9801bb484285362fD5dd0c94592c874C +TIER_REGISTRY_OWNER_ADDRESS=0x53c6dA835c777AD11159198FBe11f95E5eE6B692 +TIER_REGISTRY_MIGRATOR_ADDRESS=0x2d93c2f74b2c4697f9ea85d0450148aa45d4d5a2 + +# RPC endpoints +ETH_MAINNET_RPC_URL= +OP_MAINNET_RPC_URL= +BASE_MAINNET_RPC_URL= # Salts STORAGE_RENT_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 @@ -43,6 +49,7 @@ KEY_GATEWAY_CREATE2_SALT=0x299707e127cc77de01b9fd968bc0ff475f3c6342229ded5ec3c3b SIGNED_KEY_REQUEST_VALIDATOR_CREATE2_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 BUNDLER_CREATE2_SALT=0x299707e127cc77de01b9fd968bc0ff475f3c6342e9da01d98917640342e02a5c RECOVERY_PROXY_CREATE2_SALT=0x299707e127cc77de01b9fd968bc0ff475f3c63421958ea987b94fd038a490454 +TIER_REGISTRY_CREATE2_SALT=0x299707e127cc77de01b9fd968bc0ff475f3c63425a6dbfc4658e47004603abdf # Deployed contracts STORAGE_RENT_ADDRESS=0x00000000fcCe7f938e7aE6D3c335bD6a1a7c593D diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65363ba6..842443c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,8 +9,9 @@ on: env: FOUNDRY_PROFILE: ci - L1_MAINNET_RPC_URL: ${{ secrets.L1_MAINNET_RPC_URL }} - L2_MAINNET_RPC_URL: ${{ secrets.L2_MAINNET_RPC_URL }} + ETH_MAINNET_RPC_URL: ${{ secrets.L1_MAINNET_RPC_URL }} + OP_MAINNET_RPC_URL: ${{ secrets.L2_MAINNET_RPC_URL }} + BASE_MAINNET_RPC_URL: ${{ secrets.BASE_MAINNET_RPC_URL }} jobs: build-image: diff --git a/docker-compose.yml b/docker-compose.yml index 6fed1804..b77d55e0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,7 +9,7 @@ x-anvil-defaults: &anvil-defaults <<: *build-defaults restart: on-failure healthcheck: - test: ['CMD', '/usr/bin/nc', '-z', 'localhost', '${PORT:-8545}'] + test: ["CMD", "/usr/bin/nc", "-z", "localhost", "${PORT:-8545}"] interval: 1s timeout: 1s retries: 3 @@ -27,15 +27,15 @@ services: <<: *anvil-defaults command: | sh -c ' - exec anvil --host 0.0.0.0 --port ${PORT:-8545} --rpc-url $$L2_MAINNET_RPC_URL --state /var/lib/anvil/state --retries 3 --timeout 10000 + exec anvil --host 0.0.0.0 --port ${PORT:-8545} --rpc-url $$OP_MAINNET_RPC_URL --state /var/lib/anvil/state --retries 3 --timeout 10000 ' environment: - - L2_MAINNET_RPC_URL + - OP_MAINNET_RPC_URL volumes: - l2-anvil-data:/var/lib/anvil - l2-anvil-cache:/root/.foundry/cache ports: - - '${PORT:-8545}:${PORT:-8545}' + - "${PORT:-8545}:${PORT:-8545}" l2-deployer: <<: *deployer-defaults @@ -81,15 +81,15 @@ services: <<: *anvil-defaults command: | sh -c ' - exec anvil --host 0.0.0.0 --port ${PORT:-8545} --rpc-url $$L1_MAINNET_RPC_URL --state /var/lib/anvil/state --retries 3 --timeout 10000 + exec anvil --host 0.0.0.0 --port ${PORT:-8545} --rpc-url $$ETH_MAINNET_RPC_URL --state /var/lib/anvil/state --retries 3 --timeout 10000 ' environment: - - L1_MAINNET_RPC_URL + - ETH_MAINNET_RPC_URL volumes: - l1-anvil-data:/var/lib/anvil - l1-anvil-cache:/root/.foundry/cache ports: - - '${PORT:-8546}:${PORT:-8545}' + - "${PORT:-8546}:${PORT:-8545}" l1-deployer: <<: *deployer-defaults diff --git a/foundry.toml b/foundry.toml index 30d662a3..79cac164 100644 --- a/foundry.toml +++ b/foundry.toml @@ -28,5 +28,6 @@ int_types = "long" multiline_func_header = "params_first" [rpc_endpoints] -l2_mainnet = "${L2_MAINNET_RPC_URL}" -l1_mainnet = "${L1_MAINNET_RPC_URL}" +base_mainnet = "${BASE_MAINNET_RPC_URL}" +op_mainnet = "${OP_MAINNET_RPC_URL}" +eth_mainnet = "${ETH_MAINNET_RPC_URL}" diff --git a/script/DeployTierRegistry.s.sol b/script/DeployTierRegistry.s.sol new file mode 100644 index 00000000..5407a441 --- /dev/null +++ b/script/DeployTierRegistry.s.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.21; + +import {Test} from "forge-std/Test.sol"; +import {TierRegistry} from "../src/TierRegistry.sol"; +import {console, ImmutableCreate2Deployer} from "./abstract/ImmutableCreate2Deployer.sol"; + +contract DeployTierRegistry is ImmutableCreate2Deployer, Test { + address public constant BASE_USDC = address(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913); + uint256 public constant MIN_DAYS = 30; + uint256 public constant MAX_DAYS = 365; + uint256 public constant PRICE_PER_DAY = 328768; + + struct Salts { + bytes32 tierRegistry; + } + + struct DeploymentParams { + address deployer; + address vault; + address owner; + address migrator; + Salts salts; + } + + struct Addresses { + address tierRegistry; + } + + struct Contracts { + TierRegistry tierRegistry; + } + + function run() public { + runSetup(runDeploy(loadDeploymentParams())); + } + + function runDeploy( + DeploymentParams memory params + ) public returns (Contracts memory) { + return runDeploy(params, true); + } + + function runDeploy(DeploymentParams memory params, bool broadcast) public returns (Contracts memory) { + Addresses memory addrs; + addrs.tierRegistry = register( + "TierRegistry", + params.salts.tierRegistry, + type(TierRegistry).creationCode, + abi.encode(params.migrator, params.deployer) + ); + deploy(broadcast); + + return Contracts({tierRegistry: TierRegistry(addrs.tierRegistry)}); + } + + function runSetup(Contracts memory contracts, DeploymentParams memory params, bool broadcast) public { + if (deploymentChanged()) { + console.log("Running setup"); + + if (broadcast) vm.startBroadcast(); + contracts.tierRegistry.setTier(1, BASE_USDC, MIN_DAYS, MAX_DAYS, PRICE_PER_DAY, params.vault); + contracts.tierRegistry.transferOwnership(params.owner); + if (broadcast) vm.stopBroadcast(); + } else { + console.log("No changes, skipping setup"); + } + } + + function runSetup( + Contracts memory contracts + ) public { + DeploymentParams memory params = loadDeploymentParams(); + runSetup(contracts, params, true); + } + + function loadDeploymentParams() internal returns (DeploymentParams memory) { + return DeploymentParams({ + deployer: vm.envAddress("DEPLOYER"), + vault: vm.envAddress("TIER_REGISTRY_VAULT_ADDRESS"), + owner: vm.envAddress("TIER_REGISTRY_OWNER_ADDRESS"), + migrator: vm.envAddress("TIER_REGISTRY_MIGRATOR_ADDRESS"), + salts: Salts({tierRegistry: vm.envOr("TIER_REGISTRY_CREATE2_SALT", bytes32(0))}) + }); + } +} diff --git a/src/TierRegistry.sol b/src/TierRegistry.sol index f1bfbe12..3d1cc1ef 100644 --- a/src/TierRegistry.sol +++ b/src/TierRegistry.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.29; import {Migration} from "./abstract/Migration.sol"; -import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {SafeERC20, IERC20} from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ITierRegistry} from "./interfaces/ITierRegistry.sol"; diff --git a/src/interfaces/ITierRegistry.sol b/src/interfaces/ITierRegistry.sol index 47317cd9..6f8b7d6d 100644 --- a/src/interfaces/ITierRegistry.sol +++ b/src/interfaces/ITierRegistry.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.29; import {IMigration} from "./abstract/IMigration.sol"; -import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "openzeppelin/contracts/token/ERC20/IERC20.sol"; /** * @title ITierRegistry diff --git a/test/Deploy/AuthKeys.t.sol b/test/Deploy/AuthKeys.t.sol index bfe924a6..cb5beab0 100644 --- a/test/Deploy/AuthKeys.t.sol +++ b/test/Deploy/AuthKeys.t.sol @@ -58,7 +58,7 @@ contract AuthKeysTest is Test { address internal migrator = relayer; function setUp() public { - vm.createSelectFork("l2_mainnet", 134877573); + vm.createSelectFork("op_mainnet", 134877573); (alice, alicePk) = makeAddrAndKey("alice"); (bob, bobPk) = makeAddrAndKey("bob"); diff --git a/test/Deploy/DeployL1.t.sol b/test/Deploy/DeployL1.t.sol index 05bba15c..22e7d547 100644 --- a/test/Deploy/DeployL1.t.sol +++ b/test/Deploy/DeployL1.t.sol @@ -15,7 +15,7 @@ contract DeployL1Test is DeployL1, FnameResolverTestSuite { address internal alice = makeAddr("alice"); function setUp() public override { - vm.createSelectFork("l1_mainnet"); + vm.createSelectFork("eth_mainnet"); (signer, signerPk) = makeAddrAndKey("signer"); diff --git a/test/Deploy/DeployL2.t.sol b/test/Deploy/DeployL2.t.sol index ac5fc793..b278db9f 100644 --- a/test/Deploy/DeployL2.t.sol +++ b/test/Deploy/DeployL2.t.sol @@ -59,7 +59,7 @@ contract DeployL2Test is DeployL2, Test { address internal deployer = address(0x6D2b70e39C6bc63763098e336323591eb77Cd0C6); function setUp() public { - vm.createSelectFork("l2_mainnet", 108869038); + vm.createSelectFork("op_mainnet", 108869038); (alice, alicePk) = makeAddrAndKey("alice"); (bob, bobPk) = makeAddrAndKey("bob"); diff --git a/test/Deploy/DeployTierRegistry.t.sol b/test/Deploy/DeployTierRegistry.t.sol new file mode 100644 index 00000000..5c9769db --- /dev/null +++ b/test/Deploy/DeployTierRegistry.t.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.21; + +import "forge-std/console.sol"; +import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {TierRegistry, DeployTierRegistry} from "../../script/DeployTierRegistry.s.sol"; + +/* solhint-disable state-visibility */ + +contract DeployTierRegistryTest is DeployTierRegistry { + address public alice = makeAddr("alice"); + address public bob = makeAddr("bob"); + address public vault = makeAddr("vault"); + address public owner = makeAddr("owner"); + address public migrator = makeAddr("migrator"); + address public deployer = makeAddr("deployer"); + + TierRegistry public tierRegistry; + + event PurchasedTier(uint256 indexed fid, uint256 indexed tier, uint256 forDays, address indexed payer); + + function setUp() public { + vm.createSelectFork("base_mainnet", 31172413); + + DeployTierRegistry.DeploymentParams memory params = DeployTierRegistry.DeploymentParams({ + deployer: deployer, + vault: vault, + owner: owner, + migrator: migrator, + salts: DeployTierRegistry.Salts({tierRegistry: 0}) + }); + + vm.startPrank(deployer); + DeployTierRegistry.Contracts memory contracts = runDeploy(params, false); + runSetup(contracts, params, false); + vm.stopPrank(); + + tierRegistry = contracts.tierRegistry; + } + + function test_deploymentParams() public { + // Ownership parameters + assertEq(tierRegistry.owner(), deployer); + assertEq(tierRegistry.pendingOwner(), owner); + assertEq(tierRegistry.migrator(), migrator); + assertEq(tierRegistry.isMigrated(), false); + assertEq(tierRegistry.paused(), true); + + // Initial tier + TierRegistry.TierInfo memory tier = tierRegistry.tierInfo(1); + assertEq(tier.minDays, 30); + assertEq(tier.maxDays, 365); + assertEq(tier.vault, vault); + assertEq(address(tier.paymentToken), BASE_USDC); + assertEq(tier.tokenPricePerDay, PRICE_PER_DAY); + } + + function test_e2e() public { + // Owner accepts ownership + vm.prank(owner); + tierRegistry.acceptOwnership(); + assertEq(tierRegistry.owner(), owner); + + // Migrator backfills and migrates + vm.startPrank(migrator); + uint256[] memory fids = new uint256[](2); + fids[0] = 1; + fids[1] = 2; + + vm.expectEmit(); + emit PurchasedTier(1, 1, 365, migrator); + emit PurchasedTier(2, 1, 365, migrator); + tierRegistry.batchCreditTier(1, fids, 365); + tierRegistry.migrate(); + vm.stopPrank(); + + // Cannot purchase + vm.expectRevert("Pausable: paused"); + vm.prank(alice); + tierRegistry.purchaseTier(3, 1, 30); + + // Owner unpauses + vm.prank(owner); + tierRegistry.unpause(); + + // Public purchase + deal(BASE_USDC, alice, 100 * 1e6); + vm.startPrank(alice); + uint256 price = tierRegistry.price(1, 30); + IERC20(BASE_USDC).approve(address(tierRegistry), price); + tierRegistry.purchaseTier(3, 1, 30); + vm.stopPrank(); + } +} diff --git a/test/Deploy/UpgradeBundler.t.sol b/test/Deploy/UpgradeBundler.t.sol index a087e9b5..f97f9741 100644 --- a/test/Deploy/UpgradeBundler.t.sol +++ b/test/Deploy/UpgradeBundler.t.sol @@ -48,7 +48,7 @@ contract UpgradeBundlerTest is UpgradeBundler { address internal warpcastWallet = address(0x2cd85a093261f59270804A6EA697CeA4CeBEcafE); function setUp() public { - vm.createSelectFork("l2_mainnet", 136433938); + vm.createSelectFork("op_mainnet", 136433938); (alice, alicePk) = makeAddrAndKey("alice"); (bob, bobPk) = makeAddrAndKey("bob"); diff --git a/test/Deploy/UpgradeL2.t.sol b/test/Deploy/UpgradeL2.t.sol index 3bca782a..6a33f43e 100644 --- a/test/Deploy/UpgradeL2.t.sol +++ b/test/Deploy/UpgradeL2.t.sol @@ -73,7 +73,7 @@ contract UpgradeL2Test is UpgradeL2 { address internal signedKeyRequestValidatorAddr = address(0x00000000FC700472606ED4fA22623Acf62c60553); function setUp() public { - vm.createSelectFork("l2_mainnet", 111079475); + vm.createSelectFork("op_mainnet", 111079475); (alice, alicePk) = makeAddrAndKey("alice"); (bob, bobPk) = makeAddrAndKey("bob"); diff --git a/test/TierRegistry/TierRegistry.t.sol b/test/TierRegistry/TierRegistry.t.sol index ef55b80f..db4c868c 100644 --- a/test/TierRegistry/TierRegistry.t.sol +++ b/test/TierRegistry/TierRegistry.t.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.21; import "forge-std/Test.sol"; +import {SafeERC20, IERC20} from "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {ITierRegistry} from "../../src/TierRegistry.sol"; import {IGuardians} from "../../src/abstract/Guardians.sol"; import {IMigration} from "../../src/interfaces/abstract/IMigration.sol"; import {TransferHelper} from "../../src/libraries/TransferHelper.sol"; import {TierRegistryTestSuite} from "./TierRegistryTestSuite.sol"; -import "openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract TierRegistryTest is TierRegistryTestSuite { using SafeERC20 for IERC20;