@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.
- package/.turbo/turbo-build$colon$js.log +119 -101
- package/CHANGELOG.md +31 -1
- package/README.md +1 -0
- package/abis/AddressConstants.json +7 -0
- package/abis/BaseTest.json +65 -3
- package/abis/BuySupplyWithV4SwapHook.json +429 -0
- package/abis/FeeEstimatorHook.json +23 -0
- package/abis/ITrustedMsgSenderProviderLookup.json +21 -0
- package/abis/IUniswapV4Router04.json +484 -0
- package/abis/IZoraV4CoinHook.json +5 -0
- package/abis/MockAirlock.json +39 -0
- package/abis/SimpleERC20.json +326 -0
- package/abis/TrustedMsgSenderProviderLookup.json +215 -0
- package/abis/VmContractHelper242.json +233 -0
- package/abis/ZoraV4CoinHook.json +21 -3
- package/addresses/8453.json +7 -9
- package/audits/report-cantinacode-zora-1021.pdf +0 -0
- package/dist/index.cjs +140 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +139 -18
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +205 -28
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +5 -1
- package/package/wagmiGenerated.ts +139 -18
- package/package.json +3 -3
- package/script/DeployPostDeploymentHooks.s.sol +1 -3
- package/script/DeployTrustedMsgSenderLookup.s.sol +20 -0
- package/src/deployment/CoinsDeployerBase.sol +31 -9
- package/src/hooks/ZoraV4CoinHook.sol +19 -55
- package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +310 -0
- package/src/interfaces/ITrustedMsgSenderProviderLookup.sol +18 -0
- package/src/interfaces/IZoraV4CoinHook.sol +3 -0
- package/src/libs/HooksDeployment.sol +9 -8
- package/src/libs/V4Liquidity.sol +50 -6
- package/src/utils/AutoSwapper.sol +1 -1
- package/src/utils/TrustedMsgSenderProviderLookup.sol +73 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/BuySupplyWithV4SwapHook.t.sol +509 -0
- package/test/Coin.t.sol +21 -9
- package/test/CoinUniV4.t.sol +1 -2
- package/test/ContentCoinRewards.t.sol +1 -3
- package/test/CreatorCoin.t.sol +1 -4
- package/test/CreatorCoinRewards.t.sol +5 -3
- package/test/Factory.t.sol +3 -3
- package/test/HooksDeployment.t.sol +58 -6
- package/test/LiquidityMigration.t.sol +6 -2
- package/test/MultiOwnable.t.sol +4 -4
- package/test/TrustedMsgSenderProviderLookup.t.sol +112 -0
- package/test/Upgrades.t.sol +41 -27
- package/test/ZoraHookRegistry.t.sol +19 -9
- package/test/mocks/MockAirlock.sol +22 -0
- package/test/mocks/SimpleERC20.sol +8 -0
- package/test/utils/BaseTest.sol +185 -6
- package/test/utils/FeeEstimatorHook.sol +3 -1
- package/test/utils/TrustedSenderTestHelper.sol +18 -0
- package/test/utils/hookmate/README.md +50 -0
- package/test/utils/hookmate/artifacts/DeployHelper.sol +20 -0
- package/test/utils/hookmate/artifacts/Permit2.sol +16 -0
- package/test/utils/hookmate/artifacts/UniversalRouter.sol +29 -0
- package/test/utils/hookmate/artifacts/V4PoolManager.sol +17 -0
- package/test/utils/hookmate/artifacts/V4PositionManager.sol +23 -0
- package/test/utils/hookmate/artifacts/V4Quoter.sol +17 -0
- package/test/utils/hookmate/artifacts/V4Router.sol +18 -0
- package/test/utils/hookmate/constants/AddressConstants.sol +193 -0
- package/test/utils/hookmate/interfaces/router/IUniswapV4Router04.sol +173 -0
- package/test/utils/hookmate/interfaces/router/PathKey.sol +34 -0
- package/test/utils/hookmate/test/utils/SwapFeeEventAsserter.sol +24 -0
- package/wagmi.config.ts +1 -1
- package/src/utils/uniswap/BytesLib.sol +0 -35
- package/src/utils/uniswap/Path.sol +0 -31
- /package/abis/{VmContractHelper226.json → VmContractHelper235.json} +0 -0
package/src/libs/V4Liquidity.sol
CHANGED
|
@@ -269,13 +269,14 @@ library V4Liquidity {
|
|
|
269
269
|
salt: 0
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
|
|
272
|
+
// callerDelta already includes fees, feesAccrued is informational only
|
|
273
|
+
(BalanceDelta callerDelta, ) = poolManager.modifyLiquidity(poolKey, params, "");
|
|
273
274
|
|
|
274
275
|
burnedPositions[i] = BurnedPosition({
|
|
275
276
|
tickLower: positions[i].tickLower,
|
|
276
277
|
tickUpper: positions[i].tickUpper,
|
|
277
|
-
amount0Received: uint128(
|
|
278
|
-
amount1Received: uint128(
|
|
278
|
+
amount0Received: uint128(callerDelta.amount0()),
|
|
279
|
+
amount1Received: uint128(callerDelta.amount1())
|
|
279
280
|
});
|
|
280
281
|
}
|
|
281
282
|
}
|
|
@@ -315,20 +316,63 @@ library V4Liquidity {
|
|
|
315
316
|
feeGrowthInside1DeltaX128 = feeGrowthInside1X128 - feeGrowthInside1LastX128;
|
|
316
317
|
}
|
|
317
318
|
|
|
319
|
+
/// @notice Mints liquidity positions into the pool
|
|
320
|
+
/// @dev Uses a defensive balance check to prevent ERC20InsufficientBalance errors during migration.
|
|
321
|
+
/// When burning positions from an old hook, the amounts received may not exactly match what's needed
|
|
322
|
+
/// to mint the same liquidity in the new hook due to:
|
|
323
|
+
/// 1. Rounding in getLiquidityForAmounts() when converting between liquidity and token amounts
|
|
324
|
+
/// 2. Price movements between burn and mint operations
|
|
325
|
+
/// 3. Any accumulated dust from previous operations
|
|
326
|
+
/// By capping each position's liquidity at what's actually mintable with remaining balances,
|
|
327
|
+
/// we ensure the migration never reverts due to insufficient tokens.
|
|
318
328
|
function mintPositions(IPoolManager poolManager, PoolKey memory poolKey, LpPosition[] memory positions) internal returns (int128 amount0, int128 amount1) {
|
|
319
|
-
ModifyLiquidityParams memory params;
|
|
320
329
|
uint256 numPositions = positions.length;
|
|
321
330
|
|
|
331
|
+
// Track remaining token balances throughout minting.
|
|
332
|
+
// These balances decrease as each position consumes tokens.
|
|
333
|
+
uint256 balance0 = poolKey.currency0.balanceOf(address(this));
|
|
334
|
+
uint256 balance1 = poolKey.currency1.balanceOf(address(this));
|
|
335
|
+
|
|
336
|
+
// Cache sqrt price once for all liquidity calculations
|
|
337
|
+
(uint160 sqrtPriceX96, , , ) = StateLibrary.getSlot0(poolManager, poolKey.toId());
|
|
338
|
+
|
|
322
339
|
for (uint256 i; i < numPositions; i++) {
|
|
323
|
-
|
|
340
|
+
if (positions[i].liquidity == 0) {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Calculate the maximum liquidity we can mint given our remaining token balances.
|
|
345
|
+
// This is the key defensive check: even if the requested liquidity would require
|
|
346
|
+
// more tokens than we have (due to rounding), we cap it at what's actually possible.
|
|
347
|
+
uint128 maxLiquidity = LiquidityAmounts.getLiquidityForAmounts(
|
|
348
|
+
sqrtPriceX96,
|
|
349
|
+
TickMath.getSqrtPriceAtTick(positions[i].tickLower),
|
|
350
|
+
TickMath.getSqrtPriceAtTick(positions[i].tickUpper),
|
|
351
|
+
balance0,
|
|
352
|
+
balance1
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
// Use the lesser of requested liquidity and what we can actually afford
|
|
356
|
+
uint128 liquidityToMint = positions[i].liquidity < maxLiquidity ? positions[i].liquidity : maxLiquidity;
|
|
357
|
+
|
|
358
|
+
if (liquidityToMint == 0) {
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
ModifyLiquidityParams memory params = ModifyLiquidityParams({
|
|
324
363
|
tickLower: positions[i].tickLower,
|
|
325
364
|
tickUpper: positions[i].tickUpper,
|
|
326
|
-
liquidityDelta: SafeCast.toInt256(
|
|
365
|
+
liquidityDelta: SafeCast.toInt256(liquidityToMint),
|
|
327
366
|
salt: 0
|
|
328
367
|
});
|
|
329
368
|
|
|
330
369
|
(BalanceDelta delta, ) = poolManager.modifyLiquidity(poolKey, params, "");
|
|
331
370
|
|
|
371
|
+
// Update remaining balances for next iteration.
|
|
372
|
+
// delta.amount0/1 are negative when minting (tokens flow out), so adding them decreases our balance.
|
|
373
|
+
balance0 = uint256(int256(balance0) + int256(delta.amount0()));
|
|
374
|
+
balance1 = uint256(int256(balance1) + int256(delta.amount1()));
|
|
375
|
+
|
|
332
376
|
amount0 += delta.amount0();
|
|
333
377
|
amount1 += delta.amount1();
|
|
334
378
|
}
|
|
@@ -9,7 +9,7 @@ pragma solidity ^0.8.28;
|
|
|
9
9
|
|
|
10
10
|
import {ISwapRouter} from "@zoralabs/shared-contracts/interfaces/uniswap/ISwapRouter.sol";
|
|
11
11
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
12
|
-
import {Path} from "
|
|
12
|
+
import {Path} from "@zoralabs/shared-contracts/libs/UniswapV3/Path.sol";
|
|
13
13
|
|
|
14
14
|
/// @title AutoSwapper
|
|
15
15
|
/// @notice A contract that allows for swapping of tokens via a uniswap v3 swap router. Only works with Uniswap V3 swaps.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
|
|
2
|
+
// This software is licensed under the Zora Delayed Open Source License.
|
|
3
|
+
// Under this license, you may use, copy, modify, and distribute this software for
|
|
4
|
+
// non-commercial purposes only. Commercial use and competitive products are prohibited
|
|
5
|
+
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
|
+
// at which point this software automatically becomes available under the MIT License.
|
|
7
|
+
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
+
pragma solidity ^0.8.23;
|
|
9
|
+
|
|
10
|
+
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
|
|
11
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
12
|
+
import {ContractVersionBase} from "../version/ContractVersionBase.sol";
|
|
13
|
+
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.sol";
|
|
14
|
+
|
|
15
|
+
/// @title TrustedMsgSenderProviderLookup
|
|
16
|
+
/// @notice Contract for ITrustedMsgSenderProviderLookup that manages trusted message senders
|
|
17
|
+
/// @dev This contract allows the owner to add/remove trusted senders and provides lookup functionality
|
|
18
|
+
contract TrustedMsgSenderProviderLookup is ITrustedMsgSenderProviderLookup, ContractVersionBase, Ownable2Step {
|
|
19
|
+
/// @notice Emitted when a trusted sender is added
|
|
20
|
+
/// @param sender The address that was added as trusted
|
|
21
|
+
event TrustedSenderAdded(address indexed sender);
|
|
22
|
+
|
|
23
|
+
/// @notice Emitted when a trusted sender is removed
|
|
24
|
+
/// @param sender The address that was removed from trusted
|
|
25
|
+
event TrustedSenderRemoved(address indexed sender);
|
|
26
|
+
|
|
27
|
+
/// @notice Mapping of addresses to their trusted sender status
|
|
28
|
+
mapping(address => bool) private trustedSenders;
|
|
29
|
+
|
|
30
|
+
/// @notice Constructor that initializes the contract with trusted senders and sets the owner
|
|
31
|
+
/// @param trustedMessageSenders Array of addresses to mark as trusted senders initially
|
|
32
|
+
/// @param initialOwner The address that will own this contract
|
|
33
|
+
constructor(address[] memory trustedMessageSenders, address initialOwner) Ownable(initialOwner) {
|
|
34
|
+
for (uint256 i = 0; i < trustedMessageSenders.length; i++) {
|
|
35
|
+
trustedSenders[trustedMessageSenders[i]] = true;
|
|
36
|
+
emit TrustedSenderAdded(trustedMessageSenders[i]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// @notice Checks if an address is a trusted message sender provider
|
|
41
|
+
/// @param sender The address to check
|
|
42
|
+
/// @return true if the sender is trusted, false otherwise
|
|
43
|
+
function isTrustedMsgSenderProvider(address sender) external view override returns (bool) {
|
|
44
|
+
return trustedSenders[sender];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// @notice Adds multiple trusted senders in a single transaction (only callable by owner)
|
|
48
|
+
/// @param senders Array of addresses to add as trusted
|
|
49
|
+
function addTrustedMsgSenderProviders(address[] calldata senders) external onlyOwner {
|
|
50
|
+
for (uint256 i = 0; i < senders.length; i++) {
|
|
51
|
+
address sender = senders[i];
|
|
52
|
+
require(sender != address(0), "Cannot add zero address as trusted sender");
|
|
53
|
+
|
|
54
|
+
if (!trustedSenders[sender]) {
|
|
55
|
+
trustedSenders[sender] = true;
|
|
56
|
+
emit TrustedSenderAdded(sender);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// @notice Removes multiple trusted senders in a single transaction (only callable by owner)
|
|
62
|
+
/// @param senders Array of addresses to remove from trusted
|
|
63
|
+
function removeTrustedMsgSenderProviders(address[] calldata senders) external onlyOwner {
|
|
64
|
+
for (uint256 i = 0; i < senders.length; i++) {
|
|
65
|
+
address sender = senders[i];
|
|
66
|
+
|
|
67
|
+
if (trustedSenders[sender]) {
|
|
68
|
+
trustedSenders[sender] = false;
|
|
69
|
+
emit TrustedSenderRemoved(sender);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
|
|
|
9
9
|
contract ContractVersionBase is IVersionedContract {
|
|
10
10
|
/// @notice The version of the contract
|
|
11
11
|
function contractVersion() external pure override returns (string memory) {
|
|
12
|
-
return "2.
|
|
12
|
+
return "2.4.0";
|
|
13
13
|
}
|
|
14
14
|
}
|