@zoralabs/coins 2.4.0 → 2.4.1
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 +116 -124
- package/CHANGELOG.md +6 -0
- package/abis/Address.json +0 -16
- package/abis/BuySupplyWithSwapRouterHook.json +0 -27
- package/abis/BuySupplyWithV4SwapHook.json +0 -32
- package/abis/Clones.json +1 -1
- package/abis/CoinDopplerMultiCurve.json +109 -0
- package/abis/Create2.json +0 -21
- package/abis/ERC1967Proxy.json +1 -1
- package/abis/ERC1967Utils.json +0 -45
- package/abis/{UpgradeCoinImpl.json → Errors.json} +14 -10
- package/abis/{MockERC20.json → IERC1363.json} +134 -104
- package/abis/IERC1967.json +47 -0
- package/abis/IERC20.json +0 -36
- package/abis/IProtocolRewards.json +0 -258
- package/abis/{Script.json → ISupportsLimitOrderFill.json} +2 -2
- package/abis/IZoraLimitOrderBookCoinsInterface.json +67 -0
- package/abis/IZoraV4CoinHook.json +10 -0
- package/abis/ProxyShim.json +15 -16
- package/abis/SafeCast.json +51 -0
- package/abis/{AddressConstants.json → SafeCast160.json} +1 -1
- package/abis/Strings.json +10 -0
- package/abis/UUPSUpgradeable.json +1 -1
- package/abis/V3ToV4SwapLib.json +28 -0
- package/abis/ZoraFactory.json +1 -1
- package/abis/ZoraFactoryImpl.json +22 -6
- package/abis/ZoraV4CoinHook.json +20 -48
- package/dist/index.cjs +950 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +948 -41
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +1459 -76
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +951 -44
- package/package.json +9 -9
- package/remappings.txt +2 -1
- package/src/ZoraFactoryImpl.sol +8 -0
- package/src/deployment/ForkedCoinsAddresses.sol +54 -0
- package/src/hooks/ZoraV4CoinHook.sol +74 -20
- package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +20 -142
- package/src/interfaces/ISupportsLimitOrderFill.sol +11 -0
- package/src/interfaces/IZoraLimitOrderBookCoinsInterface.sol +21 -0
- package/src/interfaces/IZoraV4CoinHook.sol +6 -0
- package/src/libs/CoinConstants.sol +6 -0
- package/src/libs/CoinDopplerMultiCurve.sol +1 -1
- package/src/libs/CoinRewardsV4.sol +0 -1
- package/src/libs/HooksDeployment.sol +20 -8
- package/src/libs/UniV4SwapHelper.sol +35 -0
- package/src/libs/V3ToV4SwapLib.sol +261 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/BuySupplyWithV4SwapHook.t.sol +4 -3
- package/test/Coin.t.sol +7 -1
- package/test/CoinUniV4.t.sol +2 -1
- package/test/ContentCoinRewards.t.sol +5 -1
- package/test/CreatorCoin.t.sol +3 -1
- package/test/CreatorCoinRewards.t.sol +3 -1
- package/test/Factory.t.sol +20 -7
- package/test/HooksDeployment.t.sol +16 -3
- package/test/LiquidityMigration.t.sol +52 -44
- package/test/MultiOwnable.t.sol +2 -1
- package/test/Upgrades.t.sol +110 -81
- package/test/V4Liquidity.t.sol +1 -1
- package/test/mocks/MockSwapRouter.sol +33 -0
- package/test/mocks/MockZoraLimitOrderBook.sol +14 -0
- package/test/utils/BaseTest.sol +14 -448
- package/test/utils/FeeEstimatorHook.sol +6 -2
- package/test/utils/V4TestSetup.sol +595 -0
- package/wagmi.config.ts +1 -1
- package/abis/BaseTest.json +0 -718
- package/abis/DeterministicDeployerAndCaller.json +0 -315
- package/abis/DeterministicUUPSProxyDeployer.json +0 -167
- package/abis/EIP712.json +0 -67
- package/abis/ERC20.json +0 -310
- package/abis/FeeEstimatorHook.json +0 -1938
- package/abis/IERC721.json +0 -287
- package/abis/IERC721Enumerable.json +0 -343
- package/abis/IERC721Metadata.json +0 -332
- package/abis/IERC721TokenReceiver.json +0 -36
- package/abis/IImmutableCreate2Factory.json +0 -93
- package/abis/IMulticall3.json +0 -440
- package/abis/ISafe.json +0 -15
- package/abis/ISymbol.json +0 -15
- package/abis/IUniswapV4Router04.json +0 -484
- package/abis/IUniversalRouter.json +0 -61
- package/abis/IV4Quoter.json +0 -310
- package/abis/ImmutableCreate2FactoryUtils.json +0 -15
- package/abis/LibString.json +0 -7
- package/abis/Math.json +0 -7
- package/abis/MockAirlock.json +0 -39
- package/abis/MockERC721.json +0 -350
- package/abis/ProtocolRewards.json +0 -494
- package/abis/ShortStrings.json +0 -18
- package/abis/SimpleERC20.json +0 -326
- package/abis/StdAssertions.json +0 -379
- package/abis/StdInvariant.json +0 -180
- package/abis/Test.json +0 -570
- package/abis/VmContractHelper235.json +0 -233
- package/abis/VmContractHelper242.json +0 -233
- package/abis/stdError.json +0 -119
- package/abis/stdStorageSafe.json +0 -52
- package/addresses/8453.json +0 -13
- package/addresses/84532.json +0 -10
- package/deterministicConfig/deployerAndCaller.json +0 -5
- package/deterministicConfig/zoraFactory.json +0 -8
- package/script/Deploy.s.sol +0 -23
- package/script/DeployAutoSwapper.s.sol +0 -30
- package/script/DeployDevFactory.s.sol +0 -21
- package/script/DeployPostDeploymentHooks.s.sol +0 -20
- package/script/DeployTrustedMsgSenderLookup.s.sol +0 -20
- package/script/DeployUpgradeGate.s.sol +0 -21
- package/script/GenerateDeterministicParams.s.sol +0 -43
- package/script/PrintRegisterUpgradePath.s.sol +0 -28
- package/script/PrintUpgradeCommand.s.sol +0 -13
- package/script/TestBackingCoinSwap.s.sol +0 -144
- package/script/TestV4Swap.s.sol +0 -133
- package/script/UpgradeCoinImpl.sol +0 -23
- package/script/UpgradeFactoryImpl.s.sol +0 -28
- package/script/UpgradeHooks.s.sol +0 -23
- package/src/deployment/CoinsDeployerBase.sol +0 -297
- /package/{test → src}/utils/ProxyShim.sol +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoralabs/coins",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@openzeppelin/contracts": "
|
|
18
|
-
"@openzeppelin/contracts-upgradeable": "
|
|
17
|
+
"@openzeppelin/contracts": "5.4.0",
|
|
18
|
+
"@openzeppelin/contracts-upgradeable": "5.4.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^20.1.2",
|
|
@@ -35,19 +35,19 @@
|
|
|
35
35
|
"tsx": "^3.13.0",
|
|
36
36
|
"typescript": "^5.2.2",
|
|
37
37
|
"viem": "^2.21.18",
|
|
38
|
+
"@zoralabs/shared-contracts": "^0.0.5",
|
|
38
39
|
"@zoralabs/shared-scripts": "^0.0.0",
|
|
39
|
-
"@zoralabs/tsconfig": "^0.0.1"
|
|
40
|
-
"@zoralabs/shared-contracts": "^0.0.5"
|
|
40
|
+
"@zoralabs/tsconfig": "^0.0.1"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "forge build",
|
|
44
|
-
"build:contracts:minimal": "forge build
|
|
44
|
+
"build:contracts:minimal": "forge build src/ --no-metadata",
|
|
45
45
|
"build:js": "pnpm run wagmi:generate && pnpm run copy-abis && pnpm run prettier:write && tsup",
|
|
46
46
|
"build:sizes": "forge build src/ --sizes",
|
|
47
47
|
"copy-abis": "pnpm exec bundle-abis",
|
|
48
|
-
"coverage": "forge coverage --report lcov --ir-minimum --no-match-coverage '(test/|src/utils/uniswap/|
|
|
49
|
-
"prettier:check": "prettier --check 'src/**/*.sol' 'test/**/*.sol'
|
|
50
|
-
"prettier:write": "prettier --write 'src/**/*.sol' 'test/**/*.sol'
|
|
48
|
+
"coverage": "forge coverage --report lcov --ir-minimum --no-match-coverage '(test/|src/utils/uniswap/|src/deployment/)'",
|
|
49
|
+
"prettier:check": "prettier --check 'src/**/*.sol' 'test/**/*.sol'",
|
|
50
|
+
"prettier:write": "prettier --write 'src/**/*.sol' 'test/**/*.sol'",
|
|
51
51
|
"test": "forge test -vv",
|
|
52
52
|
"test-gas": "forge test --gas-report",
|
|
53
53
|
"update-contract-version": "pnpm exec update-contract-version",
|
package/remappings.txt
CHANGED
|
@@ -2,7 +2,8 @@ ds-test/=node_modules/ds-test/src/
|
|
|
2
2
|
forge-std/=node_modules/forge-std/src/
|
|
3
3
|
@openzeppelin/=node_modules/@openzeppelin/
|
|
4
4
|
@zoralabs/shared-contracts/=node_modules/@zoralabs/shared-contracts/src/
|
|
5
|
-
|
|
5
|
+
@zoralabs/limit-orders/=node_modules/@zoralabs/limit-orders/
|
|
6
|
+
solady/=node_modules/solady/src/
|
|
6
7
|
@uniswap/v4-core/=node_modules/@uniswap/v4-core/
|
|
7
8
|
@uniswap/v4-periphery/=node_modules/@uniswap/v4-periphery/
|
|
8
9
|
permit2/src/=node_modules/@uniswap/permit2/src/
|
package/src/ZoraFactoryImpl.sol
CHANGED
|
@@ -390,6 +390,14 @@ contract ZoraFactoryImpl is
|
|
|
390
390
|
__UUPSUpgradeable_init();
|
|
391
391
|
__ReentrancyGuard_init();
|
|
392
392
|
__Ownable_init(initialOwner);
|
|
393
|
+
|
|
394
|
+
address[] memory hooks = new address[](1);
|
|
395
|
+
string[] memory tags = new string[](1);
|
|
396
|
+
|
|
397
|
+
hooks[0] = hook;
|
|
398
|
+
tags[0] = "CoinHook";
|
|
399
|
+
|
|
400
|
+
IZoraHookRegistry(zoraHookRegistry).registerHooks(hooks, tags);
|
|
393
401
|
}
|
|
394
402
|
|
|
395
403
|
/// @notice The implementation address of the factory contract
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.28;
|
|
3
|
+
|
|
4
|
+
/// @notice Minimal deployment base for coins tests
|
|
5
|
+
/// @dev Provides hardcoded deployment addresses for testing
|
|
6
|
+
contract ForkedCoinsAddresses {
|
|
7
|
+
struct CoinsDeployment {
|
|
8
|
+
// Factory
|
|
9
|
+
address zoraFactory;
|
|
10
|
+
address zoraFactoryImpl;
|
|
11
|
+
// Implementation
|
|
12
|
+
address coinV3Impl;
|
|
13
|
+
address coinV4Impl;
|
|
14
|
+
address creatorCoinImpl;
|
|
15
|
+
string coinVersion;
|
|
16
|
+
// hooks
|
|
17
|
+
address buySupplyWithSwapRouterHook;
|
|
18
|
+
address zoraV4CoinHook;
|
|
19
|
+
address hookUpgradeGate;
|
|
20
|
+
// trusted sender lookup
|
|
21
|
+
address trustedMsgSenderLookup;
|
|
22
|
+
// Hook deployment salt (for deterministic deployment)
|
|
23
|
+
bytes32 zoraV4CoinHookSalt;
|
|
24
|
+
bool isDev;
|
|
25
|
+
// Hook registry
|
|
26
|
+
address zoraHookRegistry;
|
|
27
|
+
// Limit order book
|
|
28
|
+
address zoraLimitOrderBook;
|
|
29
|
+
address swapWithLimitOrdersRouter;
|
|
30
|
+
address orderBookAuthority;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
address internal constant ZORA = 0x1111111111166b7FE7bd91427724B487980aFc69;
|
|
34
|
+
|
|
35
|
+
function readDeployment() internal pure returns (CoinsDeployment memory deployment) {
|
|
36
|
+
return readDeployment(false);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function readDeployment(bool dev) internal pure returns (CoinsDeployment memory deployment) {
|
|
40
|
+
// Hardcoded Base mainnet deployment addresses
|
|
41
|
+
deployment.zoraFactory = 0x777777751622c0d3258f214F9DF38E35BF45baF3;
|
|
42
|
+
deployment.zoraFactoryImpl = 0x8Ec7f068A77fa5FC1925110f82381374BA054Ff2;
|
|
43
|
+
deployment.coinV3Impl = 0x45Bf86430af7CD071Ea23aE52325A78C8d12aD5a;
|
|
44
|
+
deployment.coinV4Impl = 0x7Cad62748DDf516CF85bC2C05C14786D84Cf861c;
|
|
45
|
+
deployment.creatorCoinImpl = 0x36853f9f48fAEe51Bd3db15db21EB4B9038bB795;
|
|
46
|
+
deployment.coinVersion = "2.3.0";
|
|
47
|
+
deployment.buySupplyWithSwapRouterHook = 0xd8CC7bCA1dE52eA788829B16E375e9B96C18D433;
|
|
48
|
+
deployment.zoraV4CoinHook = 0xC8d077444625eB300A427a6dfB2b1DBf9b159040;
|
|
49
|
+
deployment.hookUpgradeGate = 0xD88f6BdD765313CaFA5888C177c325E2C3AbF2D2;
|
|
50
|
+
deployment.zoraV4CoinHookSalt = 0x0000000000000000000000000000000000000000000000000000000000001624;
|
|
51
|
+
deployment.zoraHookRegistry = 0x777777C4c14b133858c3982D41Dbf02509fc18d7;
|
|
52
|
+
deployment.isDev = dev;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -5,41 +5,42 @@
|
|
|
5
5
|
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
6
|
// at which point this software automatically becomes available under the MIT License.
|
|
7
7
|
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
-
pragma solidity ^0.8.
|
|
8
|
+
pragma solidity ^0.8.28;
|
|
9
9
|
|
|
10
|
+
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
11
|
+
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
10
12
|
import {BaseHook} from "@uniswap/v4-periphery/src/utils/BaseHook.sol";
|
|
11
13
|
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
|
|
12
|
-
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
13
14
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
14
15
|
import {BalanceDelta, BalanceDeltaLibrary} from "@uniswap/v4-core/src/types/BalanceDelta.sol";
|
|
15
16
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
16
17
|
import {SwapParams} from "@uniswap/v4-core/src/types/PoolOperation.sol";
|
|
18
|
+
import {BeforeSwapDelta} from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
|
|
19
|
+
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
|
|
20
|
+
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
21
|
+
import {TransientSlot} from "@openzeppelin/contracts/utils/TransientSlot.sol";
|
|
22
|
+
|
|
17
23
|
import {IZoraV4CoinHook} from "../interfaces/IZoraV4CoinHook.sol";
|
|
18
24
|
import {IMsgSender} from "../interfaces/IMsgSender.sol";
|
|
19
25
|
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.sol";
|
|
20
|
-
import {IHasSwapPath} from "../interfaces/ICoin.sol";
|
|
26
|
+
import {ICoin, IHasSwapPath, IHasRewardsRecipients, IHasCoinType} from "../interfaces/ICoin.sol";
|
|
27
|
+
import {IDeployedCoinVersionLookup} from "../interfaces/IDeployedCoinVersionLookup.sol";
|
|
28
|
+
import {IUpgradeableV4Hook, IUpgradeableDestinationV4Hook, IUpgradeableDestinationV4HookWithUpdateableFee, BurnedPosition} from "../interfaces/IUpgradeableV4Hook.sol";
|
|
29
|
+
import {IHooksUpgradeGate} from "../interfaces/IHooksUpgradeGate.sol";
|
|
30
|
+
import {IZoraHookRegistry} from "../interfaces/IZoraHookRegistry.sol";
|
|
31
|
+
import {IZoraLimitOrderBookCoinsInterface} from "../interfaces/IZoraLimitOrderBookCoinsInterface.sol";
|
|
21
32
|
import {LpPosition} from "../types/LpPosition.sol";
|
|
22
33
|
import {V4Liquidity} from "../libs/V4Liquidity.sol";
|
|
23
34
|
import {CoinRewardsV4} from "../libs/CoinRewardsV4.sol";
|
|
24
|
-
import {ICoin} from "../interfaces/ICoin.sol";
|
|
25
|
-
import {IDeployedCoinVersionLookup} from "../interfaces/IDeployedCoinVersionLookup.sol";
|
|
26
35
|
import {CoinCommon} from "../libs/CoinCommon.sol";
|
|
27
36
|
import {CoinDopplerMultiCurve} from "../libs/CoinDopplerMultiCurve.sol";
|
|
28
37
|
import {PoolStateReader} from "../libs/PoolStateReader.sol";
|
|
29
|
-
import {IHasRewardsRecipients} from "../interfaces/ICoin.sol";
|
|
30
38
|
import {CoinConfigurationVersions} from "../libs/CoinConfigurationVersions.sol";
|
|
31
|
-
import {
|
|
32
|
-
import {IHooksUpgradeGate} from "../interfaces/IHooksUpgradeGate.sol";
|
|
33
|
-
import {MultiOwnable} from "../utils/MultiOwnable.sol";
|
|
34
|
-
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
35
|
-
import {IUpgradeableDestinationV4Hook, IUpgradeableDestinationV4HookWithUpdateableFee} from "../interfaces/IUpgradeableV4Hook.sol";
|
|
36
|
-
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
37
|
-
import {BurnedPosition} from "../interfaces/IUpgradeableV4Hook.sol";
|
|
39
|
+
import {CoinConstants} from "../libs/CoinConstants.sol";
|
|
38
40
|
import {LiquidityAmounts} from "../utils/uniswap/LiquidityAmounts.sol";
|
|
39
41
|
import {TickMath} from "../utils/uniswap/TickMath.sol";
|
|
40
42
|
import {ContractVersionBase, IVersionedContract} from "../version/ContractVersionBase.sol";
|
|
41
|
-
import {
|
|
42
|
-
import {CoinConstants} from "../libs/CoinConstants.sol";
|
|
43
|
+
import {ISupportsLimitOrderFill} from "../interfaces/ISupportsLimitOrderFill.sol";
|
|
43
44
|
|
|
44
45
|
/// @title ZoraV4CoinHook
|
|
45
46
|
/// @notice Uniswap V4 hook that automatically handles fee collection and reward distributions on every swap,
|
|
@@ -78,26 +79,38 @@ contract ZoraV4CoinHook is
|
|
|
78
79
|
/// @notice The trusted message sender lookup contract - used to determine if an address is trusted
|
|
79
80
|
ITrustedMsgSenderProviderLookup internal immutable trustedMsgSenderLookup;
|
|
80
81
|
|
|
82
|
+
/// @notice The Zora limit order book contract - used to fill limit orders during swaps
|
|
83
|
+
IZoraLimitOrderBookCoinsInterface internal immutable zoraLimitOrderBook;
|
|
84
|
+
|
|
85
|
+
/// @notice The Zora hook registry
|
|
86
|
+
IZoraHookRegistry internal immutable zoraHookRegistry;
|
|
87
|
+
|
|
81
88
|
/// @notice The constructor for the ZoraV4CoinHook.
|
|
82
89
|
/// @param poolManager_ The Uniswap V4 pool manager
|
|
83
90
|
/// @param coinVersionLookup_ The coin version lookup contract - used to determine if an address is a coin and what version it is.
|
|
84
91
|
/// @param trustedMsgSenderLookup_ The trusted message sender lookup contract - used to determine if an address is trusted
|
|
85
92
|
/// @param upgradeGate_ The upgrade gate contract for managing hook upgrades
|
|
93
|
+
/// @param zoraLimitOrderBook_ The Zora limit order book contract for filling orders during swaps
|
|
94
|
+
/// @param zoraHookRegistry_ The Zora hook registry contract for identifying registered hooks
|
|
86
95
|
constructor(
|
|
87
96
|
IPoolManager poolManager_,
|
|
88
97
|
IDeployedCoinVersionLookup coinVersionLookup_,
|
|
89
98
|
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup_,
|
|
90
|
-
IHooksUpgradeGate upgradeGate_
|
|
99
|
+
IHooksUpgradeGate upgradeGate_,
|
|
100
|
+
IZoraLimitOrderBookCoinsInterface zoraLimitOrderBook_,
|
|
101
|
+
IZoraHookRegistry zoraHookRegistry_
|
|
91
102
|
) BaseHook(poolManager_) {
|
|
92
103
|
require(address(coinVersionLookup_) != address(0), CoinVersionLookupCannotBeZeroAddress());
|
|
93
|
-
|
|
94
104
|
require(address(upgradeGate_) != address(0), UpgradeGateCannotBeZeroAddress());
|
|
95
|
-
|
|
105
|
+
require(address(zoraLimitOrderBook_) != address(0), ZoraLimitOrderBookCannotBeZeroAddress());
|
|
106
|
+
require(address(zoraHookRegistry_) != address(0), ZoraHookRegistryCannotBeZeroAddress());
|
|
96
107
|
require(address(trustedMsgSenderLookup_) != address(0), TrustedMsgSenderLookupCannotBeZeroAddress());
|
|
97
108
|
|
|
98
109
|
coinVersionLookup = coinVersionLookup_;
|
|
99
110
|
upgradeGate = upgradeGate_;
|
|
100
111
|
trustedMsgSenderLookup = trustedMsgSenderLookup_;
|
|
112
|
+
zoraLimitOrderBook = zoraLimitOrderBook_;
|
|
113
|
+
zoraHookRegistry = zoraHookRegistry_;
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
/// @notice Returns the trusted message sender lookup contract
|
|
@@ -116,7 +129,7 @@ contract ZoraV4CoinHook is
|
|
|
116
129
|
afterAddLiquidity: false,
|
|
117
130
|
beforeRemoveLiquidity: false,
|
|
118
131
|
afterRemoveLiquidity: false,
|
|
119
|
-
beforeSwap:
|
|
132
|
+
beforeSwap: true,
|
|
120
133
|
afterSwap: true,
|
|
121
134
|
beforeDonate: false,
|
|
122
135
|
afterDonate: false,
|
|
@@ -148,7 +161,8 @@ contract ZoraV4CoinHook is
|
|
|
148
161
|
super.supportsInterface(interfaceId) ||
|
|
149
162
|
interfaceId == type(IUpgradeableDestinationV4Hook).interfaceId ||
|
|
150
163
|
interfaceId == type(IUpgradeableDestinationV4HookWithUpdateableFee).interfaceId ||
|
|
151
|
-
interfaceId == type(IVersionedContract).interfaceId
|
|
164
|
+
interfaceId == type(IVersionedContract).interfaceId ||
|
|
165
|
+
interfaceId == type(ISupportsLimitOrderFill).interfaceId;
|
|
152
166
|
}
|
|
153
167
|
|
|
154
168
|
/// @notice Internal fn generating the positions for a given pool key.
|
|
@@ -281,6 +295,27 @@ contract ZoraV4CoinHook is
|
|
|
281
295
|
V4Liquidity.lockAndMint(poolManager, key, positions);
|
|
282
296
|
}
|
|
283
297
|
|
|
298
|
+
/// @notice Transiently stores the tick before a swap.
|
|
299
|
+
/// @dev This is used in `_afterSwap` to determine the ticks crossed during the swap.
|
|
300
|
+
function _beforeSwap(
|
|
301
|
+
address sender,
|
|
302
|
+
PoolKey calldata key,
|
|
303
|
+
SwapParams calldata,
|
|
304
|
+
bytes calldata
|
|
305
|
+
) internal virtual override returns (bytes4, BeforeSwapDelta, uint24) {
|
|
306
|
+
if (_isInternalSwap(sender)) {
|
|
307
|
+
return (BaseHook.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Store tick for user-initiated swaps only
|
|
311
|
+
(, int24 currentTick, , ) = StateLibrary.getSlot0(poolManager, key.toId());
|
|
312
|
+
|
|
313
|
+
TransientSlot.Int256Slot slot = TransientSlot.asInt256(CoinConstants._BEFORE_SWAP_TICK_SLOT);
|
|
314
|
+
TransientSlot.tstore(slot, int256(currentTick));
|
|
315
|
+
|
|
316
|
+
return (BaseHook.beforeSwap.selector, BeforeSwapDelta.wrap(0), 0);
|
|
317
|
+
}
|
|
318
|
+
|
|
284
319
|
/// @notice Internal fn called when a swap is executed.
|
|
285
320
|
/// @dev This hook is called from BaseHook library from uniswap v4.
|
|
286
321
|
/// This hook:
|
|
@@ -301,6 +336,10 @@ contract ZoraV4CoinHook is
|
|
|
301
336
|
BalanceDelta delta,
|
|
302
337
|
bytes calldata hookData
|
|
303
338
|
) internal virtual override returns (bytes4, int128) {
|
|
339
|
+
if (_isInternalSwap(sender)) {
|
|
340
|
+
return (BaseHook.afterSwap.selector, 0);
|
|
341
|
+
}
|
|
342
|
+
|
|
304
343
|
bytes32 poolKeyHash = CoinCommon.hashPoolKey(key);
|
|
305
344
|
|
|
306
345
|
// get the coin address and positions for the pool key; they must have been set in the afterInitialize callback
|
|
@@ -343,9 +382,19 @@ contract ZoraV4CoinHook is
|
|
|
343
382
|
);
|
|
344
383
|
}
|
|
345
384
|
|
|
385
|
+
(int24 tickBeforeSwap, int24 tickAfterSwap) = _getSwapTickRange(key);
|
|
386
|
+
zoraLimitOrderBook.fill(key, !params.zeroForOne, tickBeforeSwap, tickAfterSwap, CoinConstants.SENTINEL_DEFAULT_LIMIT_ORDER_FILL_COUNT, address(0));
|
|
387
|
+
|
|
346
388
|
return (BaseHook.afterSwap.selector, 0);
|
|
347
389
|
}
|
|
348
390
|
|
|
391
|
+
/// @dev Get the tick range of a swap
|
|
392
|
+
function _getSwapTickRange(PoolKey calldata key) internal view returns (int24 tickBeforeSwap, int24 tickAfterSwap) {
|
|
393
|
+
TransientSlot.Int256Slot slot = TransientSlot.asInt256(CoinConstants._BEFORE_SWAP_TICK_SLOT);
|
|
394
|
+
tickBeforeSwap = int24(int256(TransientSlot.tload(slot)));
|
|
395
|
+
(, tickAfterSwap, , ) = StateLibrary.getSlot0(poolManager, key.toId());
|
|
396
|
+
}
|
|
397
|
+
|
|
349
398
|
/// @dev Internal fn to allow for overriding market reward distribution logic
|
|
350
399
|
function _distributeMarketRewards(Currency currency, uint128 fees, IHasRewardsRecipients coin, address tradeReferrer) internal virtual {
|
|
351
400
|
// get rewards distribution methodology from the coin
|
|
@@ -395,6 +444,11 @@ contract ZoraV4CoinHook is
|
|
|
395
444
|
delete poolCoins[poolKeyHash];
|
|
396
445
|
}
|
|
397
446
|
|
|
447
|
+
/// @dev Checks if the swap is internal and should skip hook operations
|
|
448
|
+
function _isInternalSwap(address sender) internal view returns (bool) {
|
|
449
|
+
return sender == address(this) || sender == address(zoraLimitOrderBook) || zoraHookRegistry.isRegisteredHook(sender);
|
|
450
|
+
}
|
|
451
|
+
|
|
398
452
|
/// @notice Receives ETH from the pool manager for ETH-backed coins during fee collection.
|
|
399
453
|
/// @dev Only required for coins using ETH as backing currency (currency = address(0)).
|
|
400
454
|
/// Restricted to onlyPoolManager to prevent ETH from getting stuck in the contract.
|
|
@@ -17,6 +17,7 @@ import {ICoinV3} from "../../interfaces/ICoinV3.sol";
|
|
|
17
17
|
import {CoinConfigurationVersions} from "../../libs/CoinConfigurationVersions.sol";
|
|
18
18
|
import {TransientStateLibrary} from "@uniswap/v4-core/src/libraries/TransientStateLibrary.sol";
|
|
19
19
|
import {Path} from "@zoralabs/shared-contracts/libs/UniswapV3/Path.sol";
|
|
20
|
+
import {V3ToV4SwapLib} from "../../libs/V3ToV4SwapLib.sol";
|
|
20
21
|
|
|
21
22
|
/// @title BuySupplyWithV4SwapHook
|
|
22
23
|
/// @notice Hook for purchasing initial coin supply with flexible swap routing
|
|
@@ -67,9 +68,6 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
67
68
|
// ============ ERRORS ============
|
|
68
69
|
|
|
69
70
|
error OnlyPoolManager();
|
|
70
|
-
error InsufficientInputCurrency(uint256 inputAmount, uint256 availableAmount);
|
|
71
|
-
error V3RouteCannotStartWithInputCurrency();
|
|
72
|
-
error V3RouteDoesNotConnectToV4RouteStart();
|
|
73
71
|
error InsufficientOutputAmount();
|
|
74
72
|
|
|
75
73
|
// ============ CONSTRUCTOR ============
|
|
@@ -90,12 +88,20 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
90
88
|
PoolKey[] memory v4Route = _buildV4RouteToCoin(coin, params.v4Route);
|
|
91
89
|
|
|
92
90
|
// STEP 2: Validate routes
|
|
93
|
-
|
|
91
|
+
V3ToV4SwapLib.validateRoutes(params.v3Route, params.inputCurrency, v4Route);
|
|
94
92
|
|
|
95
|
-
|
|
93
|
+
V3ToV4SwapLib.validateAndTransferInputCurrency(params.inputCurrency, params.inputAmount, params.buyRecipient, msg.value);
|
|
96
94
|
|
|
97
95
|
// STEP 3: Execute V3 swap (inputCurrency -> backing currency)
|
|
98
|
-
(uint256 currencyAmount, address currencyReceived) =
|
|
96
|
+
(uint256 currencyAmount, address currencyReceived) = V3ToV4SwapLib.executeV3Swap(
|
|
97
|
+
swapRouter,
|
|
98
|
+
V3ToV4SwapLib.V3SwapParams({
|
|
99
|
+
v3Route: params.v3Route,
|
|
100
|
+
inputCurrency: params.inputCurrency,
|
|
101
|
+
inputAmount: params.inputAmount,
|
|
102
|
+
recipient: address(this)
|
|
103
|
+
})
|
|
104
|
+
);
|
|
99
105
|
|
|
100
106
|
// STEP 4: Execute V4 swaps if needed, then buy coin
|
|
101
107
|
uint256 coinAmount = _executeV4Swap(v4Route, currencyAmount, currencyReceived, params.buyRecipient);
|
|
@@ -120,41 +126,6 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
120
126
|
|
|
121
127
|
// ============ VALIDATION ============
|
|
122
128
|
|
|
123
|
-
function _validateRoutes(InitialSupplyParams memory params, PoolKey[] memory v4Route) internal pure {
|
|
124
|
-
// Determine what currency should be the input to the V4 route
|
|
125
|
-
address v4InputCurrency;
|
|
126
|
-
if (params.v3Route.length == 0) {
|
|
127
|
-
// No V3 swap - input currency should directly match V4 route start
|
|
128
|
-
v4InputCurrency = params.inputCurrency;
|
|
129
|
-
} else {
|
|
130
|
-
// V3 swap exists - V3 output should match V4 route start
|
|
131
|
-
v4InputCurrency = _getV3RouteOutputCurrency(params.v3Route);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
PoolKey memory firstPool = v4Route[0];
|
|
135
|
-
|
|
136
|
-
require(
|
|
137
|
-
v4InputCurrency == Currency.unwrap(firstPool.currency0) || v4InputCurrency == Currency.unwrap(firstPool.currency1),
|
|
138
|
-
V3RouteDoesNotConnectToV4RouteStart()
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function _validateAndTransferInputCurrency(InitialSupplyParams memory params) internal {
|
|
143
|
-
if (params.inputCurrency == address(0)) {
|
|
144
|
-
uint256 providedAmount = msg.value;
|
|
145
|
-
|
|
146
|
-
require(providedAmount == params.inputAmount, InsufficientInputCurrency(params.inputAmount, providedAmount));
|
|
147
|
-
} else {
|
|
148
|
-
uint256 providedAmount = IERC20(params.inputCurrency).allowance(params.buyRecipient, address(this));
|
|
149
|
-
|
|
150
|
-
// must be enough allowance to transfer
|
|
151
|
-
require(providedAmount >= params.inputAmount, InsufficientInputCurrency(params.inputAmount, providedAmount));
|
|
152
|
-
|
|
153
|
-
// transfer from the buy recipient to this contract
|
|
154
|
-
IERC20(params.inputCurrency).safeTransferFrom(params.buyRecipient, address(this), params.inputAmount);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
129
|
function _buildV4RouteToCoin(ICoin coin, PoolKey[] memory v4Route) internal view returns (PoolKey[] memory fullRoute) {
|
|
159
130
|
fullRoute = new PoolKey[](v4Route.length + 1);
|
|
160
131
|
|
|
@@ -165,31 +136,7 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
165
136
|
fullRoute[v4Route.length] = coin.getPoolKey();
|
|
166
137
|
}
|
|
167
138
|
|
|
168
|
-
// ============
|
|
169
|
-
|
|
170
|
-
function _executeV3Swap(InitialSupplyParams memory params) internal returns (uint256 amountCurrency, address currencyReceived) {
|
|
171
|
-
if (params.v3Route.length == 0) {
|
|
172
|
-
// No V3 swap needed - return inputAmount directly
|
|
173
|
-
return (params.inputAmount, params.inputCurrency);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// for v3 swap section, we dont support currently having an input currency other than eth
|
|
177
|
-
if (params.inputCurrency != address(0)) {
|
|
178
|
-
revert V3RouteCannotStartWithInputCurrency();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Build swap router call for exactInput
|
|
182
|
-
ISwapRouter.ExactInputParams memory swapParams = ISwapRouter.ExactInputParams({
|
|
183
|
-
path: params.v3Route,
|
|
184
|
-
recipient: address(this),
|
|
185
|
-
amountIn: params.inputAmount,
|
|
186
|
-
amountOutMinimum: 0 // For testing - in production should have slippage protection
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
amountCurrency = swapRouter.exactInput{value: params.inputAmount}(swapParams);
|
|
190
|
-
|
|
191
|
-
currencyReceived = _getV3RouteOutputCurrency(params.v3Route);
|
|
192
|
-
}
|
|
139
|
+
// ============ V4 SWAP LOGIC ============
|
|
193
140
|
|
|
194
141
|
function _executeV4Swap(PoolKey[] memory v4Route, uint256 amountIn, address currencyIn, address buyRecipient) internal returns (uint256 amountCoin) {
|
|
195
142
|
Currency startingCurrency = Currency.wrap(currencyIn);
|
|
@@ -207,37 +154,16 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
207
154
|
(PoolKey[], uint256, Currency, address)
|
|
208
155
|
);
|
|
209
156
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
for (uint256 i = 0; i < v4Route.length; i++) {
|
|
216
|
-
PoolKey memory poolKey = v4Route[i];
|
|
217
|
-
|
|
218
|
-
// Determine swap direction based on current currency
|
|
219
|
-
bool zeroForOne = lastReceivedCurrency == poolKey.currency0;
|
|
220
|
-
|
|
221
|
-
BalanceDelta delta = poolManager.swap(
|
|
222
|
-
poolKey,
|
|
223
|
-
SwapParams(zeroForOne, -(int128(lastReceivedAmount)), zeroForOne ? TickMath.MIN_SQRT_PRICE + 1 : TickMath.MAX_SQRT_PRICE - 1),
|
|
224
|
-
""
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
// Extract output amount from delta
|
|
228
|
-
outputAmount = zeroForOne ? uint128(delta.amount1()) : uint128(delta.amount0());
|
|
229
|
-
|
|
230
|
-
// Update currentAmount for next iteration
|
|
231
|
-
lastReceivedAmount = uint128(outputAmount);
|
|
232
|
-
|
|
233
|
-
// Update current currency for next swap
|
|
234
|
-
lastReceivedCurrency = zeroForOne ? poolKey.currency1 : poolKey.currency0;
|
|
235
|
-
}
|
|
157
|
+
// Execute V4 multi-hop swap
|
|
158
|
+
V3ToV4SwapLib.V4SwapResult memory result = V3ToV4SwapLib.executeV4MultiHopSwap(
|
|
159
|
+
poolManager,
|
|
160
|
+
V3ToV4SwapLib.V4SwapParams({v4Route: v4Route, amountIn: amountIn, startingCurrency: startingCurrency})
|
|
161
|
+
);
|
|
236
162
|
|
|
237
163
|
// Settle all currency deltas and get final amount
|
|
238
|
-
|
|
164
|
+
V3ToV4SwapLib.settleDeltas(poolManager, startingCurrency, result.outputCurrency, buyRecipient, amountIn, result.outputAmount);
|
|
239
165
|
|
|
240
|
-
return abi.encode(
|
|
166
|
+
return abi.encode(result.outputAmount);
|
|
241
167
|
}
|
|
242
168
|
|
|
243
169
|
/// @notice Helper to decode V4 route data (external for try/catch)
|
|
@@ -249,22 +175,6 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
249
175
|
return abi.encode(params);
|
|
250
176
|
}
|
|
251
177
|
|
|
252
|
-
function _settleDeltas(Currency inputCurrency, Currency outputCurrency, address to, uint256 inputAmount, uint128 outputAmount) private {
|
|
253
|
-
// pay the input amount
|
|
254
|
-
if (inputCurrency.isAddressZero()) {
|
|
255
|
-
// For ETH, settle with msg.value
|
|
256
|
-
poolManager.settle{value: inputAmount}();
|
|
257
|
-
} else {
|
|
258
|
-
// For ERC20, sync and transfer
|
|
259
|
-
poolManager.sync(inputCurrency);
|
|
260
|
-
inputCurrency.transfer(address(poolManager), inputAmount);
|
|
261
|
-
poolManager.settle();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// transfer the output amount to the recipient
|
|
265
|
-
poolManager.take(outputCurrency, to, outputAmount);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
178
|
// ============ UTILITIES ============
|
|
269
179
|
|
|
270
180
|
function _getCoinBackingCurrency(ICoin coin) internal view returns (Currency) {
|
|
@@ -275,36 +185,4 @@ contract BuySupplyWithV4SwapHook is BaseCoinDeployHook {
|
|
|
275
185
|
}
|
|
276
186
|
return poolKey.currency0;
|
|
277
187
|
}
|
|
278
|
-
|
|
279
|
-
function _getV3RouteOutputCurrency(bytes memory path) internal pure returns (address tokenOut) {
|
|
280
|
-
if (path.length == 0) {
|
|
281
|
-
// if no path, then output currency is eth
|
|
282
|
-
return address(0);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// For a path with multiple pools, we need to traverse to the end
|
|
286
|
-
// Path format: tokenA + fee + tokenB + fee + tokenC...
|
|
287
|
-
// We want the final token (tokenC in this example)
|
|
288
|
-
|
|
289
|
-
// Follow Uniswap's pattern: traverse the path to find the final token
|
|
290
|
-
bytes memory currentPath = path;
|
|
291
|
-
|
|
292
|
-
// Keep skipping tokens until we reach the final pool
|
|
293
|
-
while (currentPath.hasMultiplePools()) {
|
|
294
|
-
currentPath = currentPath.skipToken();
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
// The final segment contains the last pool, decode to get the output token
|
|
298
|
-
(, tokenOut, ) = currentPath.decodeFirstPool();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function _getV3RouteInputCurrency(bytes memory path) internal pure returns (address tokenIn) {
|
|
302
|
-
if (path.length == 0) {
|
|
303
|
-
// if no path, then input currency is eth
|
|
304
|
-
return address(0);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Use Path library to get the input token (first token in the path)
|
|
308
|
-
(tokenIn, , ) = path.decodeFirstPool();
|
|
309
|
-
}
|
|
310
188
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.23;
|
|
3
|
+
|
|
4
|
+
/// @title ISupportsLimitOrderFill
|
|
5
|
+
/// @notice Marker interface for hooks that handle limit order filling in their afterSwap
|
|
6
|
+
/// @dev Hooks implementing this interface should handle zoraLimitOrderBook.fill() in afterSwap.
|
|
7
|
+
/// Use ERC165's supportsInterface to declare support: supportsInterface(type(ISupportsLimitOrderFill).interfaceId)
|
|
8
|
+
|
|
9
|
+
interface ISupportsLimitOrderFill {
|
|
10
|
+
function supportsLimitOrderFill() external pure returns (bool);
|
|
11
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
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 {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
11
|
+
|
|
12
|
+
interface IZoraLimitOrderBookCoinsInterface {
|
|
13
|
+
/// @notice Fills limit orders within a tick window.
|
|
14
|
+
/// @param key Pool key whose orders should be processed.
|
|
15
|
+
/// @param isCurrency0 Whether currency0 orders are targeted; otherwise currency1.
|
|
16
|
+
/// @param startTick Inclusive starting tick. Use `-type(int24).max` for the default lower bound.
|
|
17
|
+
/// @param endTick Inclusive ending tick. Use `type(int24).max` for the default upper bound.
|
|
18
|
+
/// @param maxFillCount Maximum orders to fill in this pass.
|
|
19
|
+
/// @param fillReferral Address to receive accrued LP fees; use address(0) to give fees to maker.
|
|
20
|
+
function fill(PoolKey calldata key, bool isCurrency0, int24 startTick, int24 endTick, uint256 maxFillCount, address fillReferral) external;
|
|
21
|
+
}
|
|
@@ -57,6 +57,12 @@ interface IZoraV4CoinHook is IUpgradeableV4Hook {
|
|
|
57
57
|
/// @notice Thrown when a non-coin is used to access the functionality of a coin.
|
|
58
58
|
error OnlyCoin(address caller, address expectedCoin);
|
|
59
59
|
|
|
60
|
+
/// @notice Thrown when the Zora limit order book is the zero address.
|
|
61
|
+
error ZoraLimitOrderBookCannotBeZeroAddress();
|
|
62
|
+
|
|
63
|
+
/// @notice Thrown when the Zora hook registry is the zero address.
|
|
64
|
+
error ZoraHookRegistryCannotBeZeroAddress();
|
|
65
|
+
|
|
60
66
|
/// @notice The pool coin struct. Lists all the contract-created positions for the coin.
|
|
61
67
|
struct PoolCoin {
|
|
62
68
|
/// @notice The address of the coin.
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
pragma solidity ^0.8.23;
|
|
9
9
|
|
|
10
10
|
library CoinConstants {
|
|
11
|
+
/// @dev Slot for transiently storing the tick before a swap.
|
|
12
|
+
bytes32 internal constant _BEFORE_SWAP_TICK_SLOT = keccak256("ZoraV4CoinHook.beforeSwap.tick");
|
|
13
|
+
|
|
14
|
+
/// @dev Constant used to indicate the max fill count for limit orders
|
|
15
|
+
uint256 internal constant SENTINEL_DEFAULT_LIMIT_ORDER_FILL_COUNT = 0;
|
|
16
|
+
|
|
11
17
|
/// @dev Constant used to increase precision during calculations
|
|
12
18
|
uint256 internal constant WAD = 1e18;
|
|
13
19
|
|
|
@@ -105,7 +105,7 @@ library CoinDopplerMultiCurve {
|
|
|
105
105
|
bool isCoinToken0,
|
|
106
106
|
PoolConfiguration memory poolConfiguration,
|
|
107
107
|
uint256 totalSupply
|
|
108
|
-
)
|
|
108
|
+
) external pure returns (LpPosition[] memory positions) {
|
|
109
109
|
positions = new LpPosition[](poolConfiguration.numPositions);
|
|
110
110
|
|
|
111
111
|
uint256 discoverySupply;
|
|
@@ -27,7 +27,6 @@ import {IHasRewardsRecipients} from "../interfaces/IHasRewardsRecipients.sol";
|
|
|
27
27
|
import {ICoin} from "../interfaces/ICoin.sol";
|
|
28
28
|
import {IZoraV4CoinHook} from "../interfaces/IZoraV4CoinHook.sol";
|
|
29
29
|
import {IHasSwapPath} from "../interfaces/ICoin.sol";
|
|
30
|
-
import {V4Liquidity} from "./V4Liquidity.sol";
|
|
31
30
|
import {UniV4SwapToCurrency} from "./UniV4SwapToCurrency.sol";
|
|
32
31
|
import {ICreatorCoinHook} from "../interfaces/ICreatorCoinHook.sol";
|
|
33
32
|
import {IHasCoinType} from "../interfaces/ICoin.sol";
|