@zoralabs/coins 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.turbo/turbo-build$colon$js.log +119 -101
  2. package/CHANGELOG.md +31 -1
  3. package/README.md +1 -0
  4. package/abis/AddressConstants.json +7 -0
  5. package/abis/BaseTest.json +65 -3
  6. package/abis/BuySupplyWithV4SwapHook.json +429 -0
  7. package/abis/FeeEstimatorHook.json +23 -0
  8. package/abis/ITrustedMsgSenderProviderLookup.json +21 -0
  9. package/abis/IUniswapV4Router04.json +484 -0
  10. package/abis/IZoraV4CoinHook.json +5 -0
  11. package/abis/MockAirlock.json +39 -0
  12. package/abis/SimpleERC20.json +326 -0
  13. package/abis/TrustedMsgSenderProviderLookup.json +215 -0
  14. package/abis/VmContractHelper242.json +233 -0
  15. package/abis/ZoraV4CoinHook.json +21 -3
  16. package/addresses/8453.json +7 -9
  17. package/audits/report-cantinacode-zora-1021.pdf +0 -0
  18. package/dist/index.cjs +140 -19
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.js +139 -18
  21. package/dist/index.js.map +1 -1
  22. package/dist/wagmiGenerated.d.ts +205 -28
  23. package/dist/wagmiGenerated.d.ts.map +1 -1
  24. package/foundry.toml +5 -1
  25. package/package/wagmiGenerated.ts +139 -18
  26. package/package.json +3 -3
  27. package/script/DeployPostDeploymentHooks.s.sol +1 -3
  28. package/script/DeployTrustedMsgSenderLookup.s.sol +20 -0
  29. package/src/deployment/CoinsDeployerBase.sol +31 -9
  30. package/src/hooks/ZoraV4CoinHook.sol +19 -55
  31. package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +310 -0
  32. package/src/interfaces/ITrustedMsgSenderProviderLookup.sol +18 -0
  33. package/src/interfaces/IZoraV4CoinHook.sol +3 -0
  34. package/src/libs/HooksDeployment.sol +9 -8
  35. package/src/libs/V4Liquidity.sol +50 -6
  36. package/src/utils/AutoSwapper.sol +1 -1
  37. package/src/utils/TrustedMsgSenderProviderLookup.sol +73 -0
  38. package/src/version/ContractVersionBase.sol +1 -1
  39. package/test/BuySupplyWithV4SwapHook.t.sol +509 -0
  40. package/test/Coin.t.sol +21 -9
  41. package/test/CoinUniV4.t.sol +1 -2
  42. package/test/ContentCoinRewards.t.sol +1 -3
  43. package/test/CreatorCoin.t.sol +1 -4
  44. package/test/CreatorCoinRewards.t.sol +5 -3
  45. package/test/Factory.t.sol +3 -3
  46. package/test/HooksDeployment.t.sol +58 -6
  47. package/test/LiquidityMigration.t.sol +6 -2
  48. package/test/MultiOwnable.t.sol +4 -4
  49. package/test/TrustedMsgSenderProviderLookup.t.sol +112 -0
  50. package/test/Upgrades.t.sol +41 -27
  51. package/test/ZoraHookRegistry.t.sol +19 -9
  52. package/test/mocks/MockAirlock.sol +22 -0
  53. package/test/mocks/SimpleERC20.sol +8 -0
  54. package/test/utils/BaseTest.sol +185 -6
  55. package/test/utils/FeeEstimatorHook.sol +3 -1
  56. package/test/utils/TrustedSenderTestHelper.sol +18 -0
  57. package/test/utils/hookmate/README.md +50 -0
  58. package/test/utils/hookmate/artifacts/DeployHelper.sol +20 -0
  59. package/test/utils/hookmate/artifacts/Permit2.sol +16 -0
  60. package/test/utils/hookmate/artifacts/UniversalRouter.sol +29 -0
  61. package/test/utils/hookmate/artifacts/V4PoolManager.sol +17 -0
  62. package/test/utils/hookmate/artifacts/V4PositionManager.sol +23 -0
  63. package/test/utils/hookmate/artifacts/V4Quoter.sol +17 -0
  64. package/test/utils/hookmate/artifacts/V4Router.sol +18 -0
  65. package/test/utils/hookmate/constants/AddressConstants.sol +193 -0
  66. package/test/utils/hookmate/interfaces/router/IUniswapV4Router04.sol +173 -0
  67. package/test/utils/hookmate/interfaces/router/PathKey.sol +34 -0
  68. package/test/utils/hookmate/test/utils/SwapFeeEventAsserter.sol +24 -0
  69. package/wagmi.config.ts +1 -1
  70. package/src/utils/uniswap/BytesLib.sol +0 -35
  71. package/src/utils/uniswap/Path.sol +0 -31
  72. /package/abis/{VmContractHelper226.json → VmContractHelper235.json} +0 -0
@@ -8,27 +8,62 @@ import {ContractAddresses} from "./utils/ContractAddresses.sol";
8
8
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
9
9
  import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
10
10
  import {HookUpgradeGate} from "../src/hooks/HookUpgradeGate.sol";
11
+ import {ITrustedMsgSenderProviderLookup} from "../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
12
+ import {TrustedSenderTestHelper} from "./utils/TrustedSenderTestHelper.sol";
11
13
 
12
14
  contract HooksDeploymentTest is Test, ContractAddresses {
13
15
  address internal hookUpgradeGate;
16
+ ITrustedMsgSenderProviderLookup internal trustedMsgSenderLookup;
17
+ address internal owner;
18
+ address internal nonOwner;
19
+ address internal trustedSender1;
20
+ address internal trustedSender2;
21
+ address internal nonTrustedSender;
14
22
 
15
23
  function setUp() public {
16
24
  vm.createSelectFork("base", 31653138);
17
25
 
26
+ owner = makeAddr("owner");
27
+ nonOwner = makeAddr("nonOwner");
28
+ trustedSender1 = makeAddr("trustedSender1");
29
+ trustedSender2 = makeAddr("trustedSender2");
30
+ nonTrustedSender = makeAddr("nonTrustedSender");
31
+
18
32
  hookUpgradeGate = address(new HookUpgradeGate(makeAddr("factoryOwner")));
33
+
34
+ // Initialize with one trusted sender
35
+ address[] memory initialTrustedSenders = new address[](1);
36
+ initialTrustedSenders[0] = trustedSender1;
37
+
38
+ trustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(owner, initialTrustedSenders);
19
39
  }
20
40
 
21
41
  function test_canMineAndCacheSalt() public {
22
42
  address[] memory trustedMessageSenders = new address[](0);
23
43
 
44
+ ITrustedMsgSenderProviderLookup localTrustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(
45
+ makeAddr("owner"),
46
+ trustedMessageSenders
47
+ );
48
+
24
49
  (bytes32 salt, ) = HooksDeployment.mineAndCacheSalt(
25
50
  address(this),
26
- abi.encode(V4_POOL_MANAGER, 0x777777751622c0d3258f214F9DF38E35BF45baF3, trustedMessageSenders, address(hookUpgradeGate))
51
+ abi.encode(
52
+ V4_POOL_MANAGER,
53
+ 0x777777751622c0d3258f214F9DF38E35BF45baF3,
54
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
55
+ address(hookUpgradeGate)
56
+ )
27
57
  );
28
58
 
29
59
  (bytes32 salt2, bool wasCached2) = HooksDeployment.mineAndCacheSalt(
30
60
  address(this),
31
- abi.encode(V4_POOL_MANAGER, 0x777777751622c0d3258f214F9DF38E35BF45baF3, trustedMessageSenders, address(hookUpgradeGate))
61
+ abi.encode(
62
+ V4_POOL_MANAGER,
63
+ 0x777777751622c0d3258f214F9DF38E35BF45baF3,
64
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
65
+ address(hookUpgradeGate)
66
+ )
32
67
  );
33
68
 
34
69
  assertEq(salt, salt2);
@@ -40,17 +75,23 @@ contract HooksDeploymentTest is Test, ContractAddresses {
40
75
  vm.createSelectFork("base", 31653138);
41
76
 
42
77
  address[] memory trustedMessageSenders = new address[](0);
78
+
79
+ ITrustedMsgSenderProviderLookup localTrustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(
80
+ makeAddr("owner"),
81
+ trustedMessageSenders
82
+ );
83
+
43
84
  (, bytes32 salt) = HooksDeployment.mineForCoinSalt(
44
85
  address(this),
45
86
  V4_POOL_MANAGER,
46
87
  0x777777751622c0d3258f214F9DF38E35BF45baF3,
47
- trustedMessageSenders,
88
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
48
89
  hookUpgradeGate
49
90
  );
50
91
  IHooks hook = HooksDeployment.deployZoraV4CoinHook(
51
92
  V4_POOL_MANAGER,
52
93
  0x777777751622c0d3258f214F9DF38E35BF45baF3,
53
- trustedMessageSenders,
94
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
54
95
  hookUpgradeGate,
55
96
  salt
56
97
  );
@@ -68,16 +109,27 @@ contract HooksDeploymentTest is Test, ContractAddresses {
68
109
  vm.createSelectFork("base", 31653138);
69
110
 
70
111
  address[] memory trustedMessageSenders = new address[](0);
112
+
113
+ ITrustedMsgSenderProviderLookup localTrustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(
114
+ makeAddr("owner"),
115
+ trustedMessageSenders
116
+ );
117
+
71
118
  (, bytes32 salt) = HooksDeployment.mineForCoinSalt(
72
119
  address(this),
73
120
  V4_POOL_MANAGER,
74
121
  0x777777751622c0d3258f214F9DF38E35BF45baF3,
75
- trustedMessageSenders,
122
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
76
123
  hookUpgradeGate
77
124
  );
78
125
 
79
126
  IHooks hook = HooksDeployment.deployHookWithSalt(
80
- HooksDeployment.makeHookCreationCode(V4_POOL_MANAGER, 0x777777751622c0d3258f214F9DF38E35BF45baF3, trustedMessageSenders, hookUpgradeGate),
127
+ HooksDeployment.makeHookCreationCode(
128
+ V4_POOL_MANAGER,
129
+ 0x777777751622c0d3258f214F9DF38E35BF45baF3,
130
+ ITrustedMsgSenderProviderLookup(address(localTrustedMsgSenderLookup)),
131
+ hookUpgradeGate
132
+ ),
81
133
  salt
82
134
  );
83
135
 
@@ -4,6 +4,8 @@ pragma solidity ^0.8.23;
4
4
  import {MockERC20} from "./mocks/MockERC20.sol";
5
5
  import {BaseTest} from "./utils/BaseTest.sol";
6
6
  import {HooksDeployment} from "../src/libs/HooksDeployment.sol";
7
+ import {TrustedSenderTestHelper} from "./utils/TrustedSenderTestHelper.sol";
8
+ import {ITrustedMsgSenderProviderLookup} from "../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
7
9
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
8
10
  import {IUpgradeableV4Hook, IUpgradeableDestinationV4Hook, BurnedPosition} from "../src/interfaces/IUpgradeableV4Hook.sol";
9
11
  import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
@@ -450,7 +452,8 @@ contract LiquidityMigrationTest is BaseTest {
450
452
  coin.migrateLiquidity(newHook, "");
451
453
 
452
454
  // Now fix the bug by etching fixed hook code onto the old hook address
453
- bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
455
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(makeAddr("owner"), new address[](0));
456
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
454
457
 
455
458
  (IHooks fixedHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
456
459
 
@@ -477,7 +480,8 @@ contract LiquidityMigrationTest is BaseTest {
477
480
  assertEq(oldFee, 30000);
478
481
 
479
482
  // Now fix the bug by etching fixed hook code onto the old hook address
480
- bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
483
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(makeAddr("owner"), new address[](0));
484
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, trustedMsgSenderLookup, upgradeGate);
481
485
 
482
486
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
483
487
 
@@ -5,7 +5,7 @@ import "./utils/BaseTest.sol";
5
5
 
6
6
  contract MultiOwnableTest is BaseTest {
7
7
  function setUp() public override {
8
- super.setUp();
8
+ super.setUpNonForked();
9
9
 
10
10
  _deployV4Coin();
11
11
  }
@@ -135,7 +135,7 @@ contract MultiOwnableTest is BaseTest {
135
135
 
136
136
  function test_revert_init_with_zero_owners() public {
137
137
  address[] memory emptyOwners = new address[](0);
138
- bytes memory poolConfig_ = _generatePoolConfig(address(weth));
138
+ bytes memory poolConfig_ = _generatePoolConfig(address(0));
139
139
  vm.expectRevert(MultiOwnable.OneOwnerRequired.selector);
140
140
  factory.deploy(users.creator, emptyOwners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
141
141
  }
@@ -143,7 +143,7 @@ contract MultiOwnableTest is BaseTest {
143
143
  function test_revert_init_with_zero_address() public {
144
144
  address[] memory owners = new address[](1);
145
145
  owners[0] = address(0);
146
- bytes memory poolConfig_ = _generatePoolConfig(address(weth));
146
+ bytes memory poolConfig_ = _generatePoolConfig(address(0));
147
147
  vm.expectRevert(MultiOwnable.OwnerCannotBeAddressZero.selector);
148
148
  factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
149
149
  }
@@ -152,7 +152,7 @@ contract MultiOwnableTest is BaseTest {
152
152
  address[] memory owners = new address[](2);
153
153
  owners[0] = users.creator;
154
154
  owners[1] = users.creator;
155
- bytes memory poolConfig_ = _generatePoolConfig(address(weth));
155
+ bytes memory poolConfig_ = _generatePoolConfig(address(0));
156
156
  vm.expectRevert(MultiOwnable.AlreadyOwner.selector);
157
157
  factory.deploy(users.creator, owners, "https://test.com", "Test Token", "TEST", poolConfig_, users.platformReferrer, 0);
158
158
  }
@@ -0,0 +1,112 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import "forge-std/Test.sol";
5
+ import {TrustedMsgSenderProviderLookup} from "../src/utils/TrustedMsgSenderProviderLookup.sol";
6
+ import {ITrustedMsgSenderProviderLookup} from "../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
7
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
8
+ import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
9
+
10
+ contract TrustedMsgSenderProviderLookupTest is Test {
11
+ ITrustedMsgSenderProviderLookup internal trustedMsgSenderLookup;
12
+
13
+ address internal owner;
14
+ address internal nonOwner;
15
+ address internal trustedSender1;
16
+ address internal trustedSender2;
17
+
18
+ event TrustedSenderAdded(address indexed sender);
19
+ event TrustedSenderRemoved(address indexed sender);
20
+
21
+ function setUp() public {
22
+ owner = makeAddr("owner");
23
+ nonOwner = makeAddr("nonOwner");
24
+ trustedSender1 = makeAddr("trustedSender1");
25
+ trustedSender2 = makeAddr("trustedSender2");
26
+ }
27
+
28
+ function deployAndInitializeLookup(address[] memory initialTrustedSenders, address initialOwner) internal returns (ITrustedMsgSenderProviderLookup) {
29
+ // Deploy the contract directly using constructor
30
+ TrustedMsgSenderProviderLookup lookup = new TrustedMsgSenderProviderLookup(initialTrustedSenders, initialOwner);
31
+ return ITrustedMsgSenderProviderLookup(address(lookup));
32
+ }
33
+
34
+ function test_constructor_initializesCorrectly() public {
35
+ address[] memory initialTrustedSenders = new address[](2);
36
+ initialTrustedSenders[0] = trustedSender1;
37
+ initialTrustedSenders[1] = trustedSender2;
38
+
39
+ trustedMsgSenderLookup = deployAndInitializeLookup(initialTrustedSenders, owner);
40
+
41
+ assertEq(Ownable2Step(address(trustedMsgSenderLookup)).owner(), owner);
42
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender1));
43
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender2));
44
+ }
45
+
46
+ function test_isTrustedMsgSenderProvider_returnsCorrectValues() public {
47
+ address[] memory initialTrustedSenders = new address[](1);
48
+ initialTrustedSenders[0] = trustedSender1;
49
+
50
+ trustedMsgSenderLookup = deployAndInitializeLookup(initialTrustedSenders, owner);
51
+
52
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender1));
53
+ assertFalse(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender2));
54
+ assertFalse(trustedMsgSenderLookup.isTrustedMsgSenderProvider(address(0)));
55
+ }
56
+
57
+ function test_addTrustedMsgSenderProviders_worksCorrectly() public {
58
+ address[] memory emptyTrustedSenders = new address[](0);
59
+ trustedMsgSenderLookup = deployAndInitializeLookup(emptyTrustedSenders, owner);
60
+
61
+ address[] memory sendersToAdd = new address[](2);
62
+ sendersToAdd[0] = trustedSender1;
63
+ sendersToAdd[1] = trustedSender2;
64
+
65
+ vm.prank(owner);
66
+ TrustedMsgSenderProviderLookup(address(trustedMsgSenderLookup)).addTrustedMsgSenderProviders(sendersToAdd);
67
+
68
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender1));
69
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender2));
70
+ }
71
+
72
+ function test_addTrustedMsgSenderProviders_onlyOwnerCanAdd() public {
73
+ address[] memory emptyTrustedSenders = new address[](0);
74
+ trustedMsgSenderLookup = deployAndInitializeLookup(emptyTrustedSenders, owner);
75
+
76
+ address[] memory sendersToAdd = new address[](1);
77
+ sendersToAdd[0] = trustedSender1;
78
+
79
+ vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner));
80
+ vm.prank(nonOwner);
81
+ TrustedMsgSenderProviderLookup(address(trustedMsgSenderLookup)).addTrustedMsgSenderProviders(sendersToAdd);
82
+ }
83
+
84
+ function test_removeTrustedMsgSenderProviders_worksCorrectly() public {
85
+ address[] memory initialTrustedSenders = new address[](2);
86
+ initialTrustedSenders[0] = trustedSender1;
87
+ initialTrustedSenders[1] = trustedSender2;
88
+ trustedMsgSenderLookup = deployAndInitializeLookup(initialTrustedSenders, owner);
89
+
90
+ address[] memory sendersToRemove = new address[](1);
91
+ sendersToRemove[0] = trustedSender1;
92
+
93
+ vm.prank(owner);
94
+ TrustedMsgSenderProviderLookup(address(trustedMsgSenderLookup)).removeTrustedMsgSenderProviders(sendersToRemove);
95
+
96
+ assertFalse(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender1));
97
+ assertTrue(trustedMsgSenderLookup.isTrustedMsgSenderProvider(trustedSender2));
98
+ }
99
+
100
+ function test_removeTrustedMsgSenderProviders_onlyOwnerCanRemove() public {
101
+ address[] memory initialTrustedSenders = new address[](1);
102
+ initialTrustedSenders[0] = trustedSender1;
103
+ trustedMsgSenderLookup = deployAndInitializeLookup(initialTrustedSenders, owner);
104
+
105
+ address[] memory sendersToRemove = new address[](1);
106
+ sendersToRemove[0] = trustedSender1;
107
+
108
+ vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, nonOwner));
109
+ vm.prank(nonOwner);
110
+ TrustedMsgSenderProviderLookup(address(trustedMsgSenderLookup)).removeTrustedMsgSenderProviders(sendersToRemove);
111
+ }
112
+ }
@@ -14,6 +14,7 @@ import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
14
14
  import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
15
15
  import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
16
16
  import {ZoraV4CoinHook} from "../src/hooks/ZoraV4CoinHook.sol";
17
+ import {BuySupplyWithV4SwapHook} from "../src/hooks/deployment/BuySupplyWithV4SwapHook.sol";
17
18
  import {console} from "forge-std/console.sol";
18
19
  import {IDeployedCoinVersionLookup} from "../src/interfaces/IDeployedCoinVersionLookup.sol";
19
20
  import {IHooksUpgradeGate} from "../src/interfaces/IHooksUpgradeGate.sol";
@@ -27,6 +28,8 @@ import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
27
28
  import {IZoraV4CoinHook} from "../src/interfaces/IZoraV4CoinHook.sol";
28
29
  import {PoolStateReader} from "../src/libs/PoolStateReader.sol";
29
30
  import {LpPosition} from "../src/types/LpPosition.sol";
31
+ import {ITrustedMsgSenderProviderLookup} from "../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
32
+ import {TrustedSenderTestHelper} from "./utils/TrustedSenderTestHelper.sol";
30
33
 
31
34
  contract BadImpl {
32
35
  function contractName() public pure returns (string memory) {
@@ -106,26 +109,34 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
106
109
 
107
110
  uint128 amountIn = 1 ether;
108
111
 
109
- address buySupplyWithSwapRouterHook = deployment.buySupplyWithSwapRouterHook;
110
-
111
- // build weth to usdc swap
112
- bytes memory call = abi.encodeWithSelector(
113
- ISwapRouter.exactInputSingle.selector,
114
- ISwapRouter.ExactInputSingleParams({
115
- tokenIn: WETH_ADDRESS,
116
- tokenOut: ZORA,
117
- fee: 3000,
118
- recipient: buySupplyWithSwapRouterHook,
119
- amountIn: amountIn,
120
- amountOutMinimum: 0,
121
- sqrtPriceLimitX96: 0
122
- })
123
- );
112
+ address buySupplyWithV4SwapHook = deployment.buySupplyWithSwapRouterHook;
124
113
 
125
114
  address buyRecipient = makeAddr("buyRecipient");
126
115
 
127
116
  address trader = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
128
117
 
118
+ // Create V3 path: ETH -> ZORA (using exact path from test)
119
+ bytes memory v3Route = abi.encodePacked(
120
+ WETH_ADDRESS, // WETH
121
+ uint24(3000), // fee
122
+ ZORA // ZORA
123
+ );
124
+
125
+ // No V4 route needed since coin is backed by ZORA
126
+ PoolKey[] memory v4Route = new PoolKey[](0);
127
+
128
+ // Encode proper BuySupplyWithV4SwapHook data
129
+ BuySupplyWithV4SwapHook.InitialSupplyParams memory params = BuySupplyWithV4SwapHook.InitialSupplyParams({
130
+ buyRecipient: buyRecipient,
131
+ v3Route: v3Route,
132
+ v4Route: v4Route,
133
+ inputCurrency: address(0), // ETH
134
+ inputAmount: amountIn,
135
+ minAmountOut: 0
136
+ });
137
+
138
+ bytes memory hookData = abi.encode(params);
139
+
129
140
  vm.startPrank(trader);
130
141
  vm.deal(trader, amountIn);
131
142
 
@@ -137,8 +148,8 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
137
148
  "TEST",
138
149
  poolConfig,
139
150
  users.platformReferrer,
140
- buySupplyWithSwapRouterHook,
141
- abi.encode(buyRecipient, call),
151
+ buySupplyWithV4SwapHook,
152
+ hookData,
142
153
  keccak256("test")
143
154
  );
144
155
 
@@ -186,7 +197,9 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
186
197
 
187
198
  uint256 amountIn = 0.000111 ether;
188
199
 
189
- bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
200
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup2 = TrustedSenderTestHelper.deployTrustedMessageSender(makeAddr("owner"), new address[](0));
201
+
202
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, trustedMsgSenderLookup2, upgradeGate);
190
203
 
191
204
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
192
205
 
@@ -238,7 +251,9 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
238
251
 
239
252
  address existingHook = address(creatorCoin.hooks());
240
253
 
241
- bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
254
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup3 = TrustedSenderTestHelper.deployTrustedMessageSender(makeAddr("owner"), new address[](0));
255
+
256
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, trustedMsgSenderLookup3, upgradeGate);
242
257
 
243
258
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
244
259
 
@@ -272,19 +287,17 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
272
287
  uint128[] memory afterLiquidity = getLiquidityForPositions(afterKey, afterPositions);
273
288
 
274
289
  for (uint256 i = 0; i < beforeLiquidity.length; i++) {
275
- // we added any extra liquidity to the last position, so we don't expect it to be the same
276
- if (i != beforeLiquidity.length - 1) {
277
- assertApproxEqAbs(beforeLiquidity[i], afterLiquidity[i], 200);
278
- }
290
+ assertApproxEqAbs(beforeLiquidity[i], afterLiquidity[i], 200);
279
291
  }
280
292
 
281
293
  uint160 afterPrice = PoolStateReader.getSqrtPriceX96(creatorCoin.getPoolKey(), poolManager);
282
294
 
283
295
  assertEq(beforePrice, afterPrice);
284
296
 
285
- // make sure that the new hook has no balance of 0 or 1
286
- assertApproxEqAbs(creatorCoin.getPoolKey().currency0.balanceOf(address(newHook)), 0, 10);
287
- assertApproxEqAbs(creatorCoin.getPoolKey().currency1.balanceOf(address(newHook)), 0, 10);
297
+ // Small amounts of dust from rounding may remain in the hook as burned tokens
298
+ // This is expected and saves on code size by not minting them back into the pool
299
+ assertApproxEqAbs(creatorCoin.getPoolKey().currency0.balanceOf(address(newHook)), 0, 0.1 ether);
300
+ assertApproxEqAbs(creatorCoin.getPoolKey().currency1.balanceOf(address(newHook)), 0, 0.1 ether);
288
301
 
289
302
  // now try to swap some currency for the creator coin - it should succeed
290
303
  _swapSomeCurrencyForCoin(creatorCoin, zora, uint128(IERC20(zora).balanceOf(trader) / 2), trader);
@@ -306,7 +319,8 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
306
319
  // this swap should revert because the content coin is broken
307
320
  _swapSomeCurrencyForCoinAndExpectRevert(ICoin(contentCoin), creatorCoin, uint128(amountIn), trader);
308
321
 
309
- bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
322
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup2 = TrustedSenderTestHelper.deployTrustedMessageSender(makeAddr("owner"), new address[](0));
323
+ bytes memory creationCode = HooksDeployment.makeHookCreationCode(address(poolManager), coinVersionLookup, trustedMsgSenderLookup2, upgradeGate);
310
324
 
311
325
  (IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
312
326
 
@@ -7,20 +7,28 @@ import {IZoraHookRegistry} from "../src/interfaces/IZoraHookRegistry.sol";
7
7
  import {ZoraHookRegistry} from "../src/hook-registry/ZoraHookRegistry.sol";
8
8
 
9
9
  contract MockHook {
10
- function contractVersion() public pure returns (string memory) {
11
- return "0.0.0";
10
+ string private _version;
11
+
12
+ constructor(string memory version_) {
13
+ _version = version_;
14
+ }
15
+
16
+ function contractVersion() public view returns (string memory) {
17
+ return _version;
12
18
  }
13
19
  }
14
20
 
21
+ contract MockHookNoVersion {
22
+ // No contractVersion function
23
+ }
24
+
15
25
  contract ZoraHookRegistryTest is Test {
16
- uint256 internal forkId;
17
26
  address internal owner;
18
27
 
19
28
  ZoraHookRegistry internal zoraHookRegistry;
20
29
  MockHook internal mockHook;
21
30
 
22
31
  function setUp() public {
23
- forkId = vm.createSelectFork("base", 34509280);
24
32
  owner = makeAddr("owner");
25
33
 
26
34
  address[] memory initialOwners = new address[](1);
@@ -29,7 +37,7 @@ contract ZoraHookRegistryTest is Test {
29
37
  zoraHookRegistry = new ZoraHookRegistry();
30
38
  zoraHookRegistry.initialize(initialOwners);
31
39
 
32
- mockHook = new MockHook();
40
+ mockHook = new MockHook("0.0.0");
33
41
  }
34
42
 
35
43
  function test_register_hooks() public {
@@ -179,7 +187,8 @@ contract ZoraHookRegistryTest is Test {
179
187
  address[] memory hooks = new address[](1);
180
188
  string[] memory tags = new string[](1);
181
189
 
182
- hooks[0] = 0x81542dC43Aff247eff4a0eceFC286A2973aE1040;
190
+ MockHook hookWithVersion = new MockHook("1.1.1");
191
+ hooks[0] = address(hookWithVersion);
183
192
  tags[0] = "CONTENT";
184
193
 
185
194
  vm.prank(owner);
@@ -192,7 +201,8 @@ contract ZoraHookRegistryTest is Test {
192
201
  address[] memory hooks = new address[](1);
193
202
  string[] memory tags = new string[](1);
194
203
 
195
- hooks[0] = 0xA1eBdD5cA6470Bbd67114331387f2dDa7bfad040;
204
+ MockHookNoVersion hookNoVersion = new MockHookNoVersion();
205
+ hooks[0] = address(hookNoVersion);
196
206
  tags[0] = "CONTENT";
197
207
 
198
208
  vm.prank(owner);
@@ -207,8 +217,8 @@ contract ZoraHookRegistryTest is Test {
207
217
 
208
218
  function test_get_hook_addresses_multiple_and_remove_middle() public {
209
219
  address a = address(mockHook);
210
- address b = address(new MockHook());
211
- address c = address(new MockHook());
220
+ address b = address(new MockHook("0.0.0"));
221
+ address c = address(new MockHook("0.0.0"));
212
222
 
213
223
  address[] memory hooks = new address[](3);
214
224
  string[] memory tags = new string[](3);
@@ -0,0 +1,22 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {IAirlock} from "../../src/interfaces/IAirlock.sol";
5
+
6
+ /// @title MockAirlock
7
+ /// @notice Mock implementation of IAirlock for testing purposes
8
+ contract MockAirlock is IAirlock {
9
+ address private _owner;
10
+
11
+ constructor(address owner_) {
12
+ _owner = owner_;
13
+ }
14
+
15
+ function owner() external view override returns (address) {
16
+ return _owner;
17
+ }
18
+
19
+ function setOwner(address newOwner) external {
20
+ _owner = newOwner;
21
+ }
22
+ }
@@ -0,0 +1,8 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
5
+
6
+ contract SimpleERC20 is ERC20 {
7
+ constructor(string memory name, string memory symbol) ERC20(name, symbol) {}
8
+ }