@zoralabs/coins 2.3.1 → 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 +119 -128
- package/CHANGELOG.md +30 -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/ITrustedMsgSenderProviderLookup.json +21 -0
- package/abis/IZoraLimitOrderBookCoinsInterface.json +67 -0
- package/abis/IZoraV4CoinHook.json +15 -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/TrustedMsgSenderProviderLookup.json +215 -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 +41 -51
- 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/foundry.toml +5 -1
- package/package/wagmiGenerated.ts +951 -44
- package/package.json +7 -7
- package/remappings.txt +2 -1
- package/src/ZoraFactoryImpl.sol +8 -0
- package/src/deployment/ForkedCoinsAddresses.sol +54 -0
- package/src/hooks/ZoraV4CoinHook.sol +92 -74
- package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +20 -142
- package/src/interfaces/ISupportsLimitOrderFill.sol +11 -0
- package/src/interfaces/ITrustedMsgSenderProviderLookup.sol +18 -0
- package/src/interfaces/IZoraLimitOrderBookCoinsInterface.sol +21 -0
- package/src/interfaces/IZoraV4CoinHook.sol +9 -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 +25 -12
- package/src/libs/UniV4SwapHelper.sol +35 -0
- package/src/libs/V3ToV4SwapLib.sol +261 -0
- package/src/libs/V4Liquidity.sol +50 -6
- package/src/utils/TrustedMsgSenderProviderLookup.sol +73 -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 +7 -1
- package/test/Factory.t.sol +20 -7
- package/test/HooksDeployment.t.sol +73 -8
- package/test/LiquidityMigration.t.sol +55 -43
- package/test/MultiOwnable.t.sol +2 -1
- package/test/TrustedMsgSenderProviderLookup.t.sol +112 -0
- package/test/Upgrades.t.sol +112 -78
- 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 +17 -425
- package/test/utils/FeeEstimatorHook.sol +8 -2
- package/test/utils/TrustedSenderTestHelper.sol +18 -0
- 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 -1915
- 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/VmContractHelper239.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/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 -276
- /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.
|
|
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",
|
|
@@ -41,13 +41,13 @@
|
|
|
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,40 +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
|
-
import {
|
|
25
|
+
import {ITrustedMsgSenderProviderLookup} from "../interfaces/ITrustedMsgSenderProviderLookup.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";
|
|
20
32
|
import {LpPosition} from "../types/LpPosition.sol";
|
|
21
33
|
import {V4Liquidity} from "../libs/V4Liquidity.sol";
|
|
22
34
|
import {CoinRewardsV4} from "../libs/CoinRewardsV4.sol";
|
|
23
|
-
import {ICoin} from "../interfaces/ICoin.sol";
|
|
24
|
-
import {IDeployedCoinVersionLookup} from "../interfaces/IDeployedCoinVersionLookup.sol";
|
|
25
35
|
import {CoinCommon} from "../libs/CoinCommon.sol";
|
|
26
36
|
import {CoinDopplerMultiCurve} from "../libs/CoinDopplerMultiCurve.sol";
|
|
27
37
|
import {PoolStateReader} from "../libs/PoolStateReader.sol";
|
|
28
|
-
import {IHasRewardsRecipients} from "../interfaces/ICoin.sol";
|
|
29
38
|
import {CoinConfigurationVersions} from "../libs/CoinConfigurationVersions.sol";
|
|
30
|
-
import {
|
|
31
|
-
import {IHooksUpgradeGate} from "../interfaces/IHooksUpgradeGate.sol";
|
|
32
|
-
import {MultiOwnable} from "../utils/MultiOwnable.sol";
|
|
33
|
-
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
|
|
34
|
-
import {IUpgradeableDestinationV4Hook, IUpgradeableDestinationV4HookWithUpdateableFee} from "../interfaces/IUpgradeableV4Hook.sol";
|
|
35
|
-
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
36
|
-
import {BurnedPosition} from "../interfaces/IUpgradeableV4Hook.sol";
|
|
39
|
+
import {CoinConstants} from "../libs/CoinConstants.sol";
|
|
37
40
|
import {LiquidityAmounts} from "../utils/uniswap/LiquidityAmounts.sol";
|
|
38
41
|
import {TickMath} from "../utils/uniswap/TickMath.sol";
|
|
39
42
|
import {ContractVersionBase, IVersionedContract} from "../version/ContractVersionBase.sol";
|
|
40
|
-
import {
|
|
41
|
-
import {CoinConstants} from "../libs/CoinConstants.sol";
|
|
43
|
+
import {ISupportsLimitOrderFill} from "../interfaces/ISupportsLimitOrderFill.sol";
|
|
42
44
|
|
|
43
45
|
/// @title ZoraV4CoinHook
|
|
44
46
|
/// @notice Uniswap V4 hook that automatically handles fee collection and reward distributions on every swap,
|
|
@@ -60,9 +62,10 @@ contract ZoraV4CoinHook is
|
|
|
60
62
|
{
|
|
61
63
|
using BalanceDeltaLibrary for BalanceDelta;
|
|
62
64
|
|
|
63
|
-
/// @
|
|
64
|
-
///
|
|
65
|
-
|
|
65
|
+
/// @dev DEPRECATED: This mapping is kept for storage compatibility. It doesn't matter that storage slots moved around
|
|
66
|
+
/// between versions since the contracts are immutable, but in some tests we do etching to test if a new hook fixes some bugs, so we want to maintain the storage slot order.
|
|
67
|
+
/// This slot previously held the mappings of trusted message senders.
|
|
68
|
+
mapping(address => bool) internal legacySlot0;
|
|
66
69
|
|
|
67
70
|
/// @notice Mapping of pool keys to coins.
|
|
68
71
|
mapping(bytes32 => IZoraV4CoinHook.PoolCoin) internal poolCoins;
|
|
@@ -73,27 +76,46 @@ contract ZoraV4CoinHook is
|
|
|
73
76
|
/// @notice The upgrade gate contract - used to verify allowed upgrade paths
|
|
74
77
|
IHooksUpgradeGate internal immutable upgradeGate;
|
|
75
78
|
|
|
79
|
+
/// @notice The trusted message sender lookup contract - used to determine if an address is trusted
|
|
80
|
+
ITrustedMsgSenderProviderLookup internal immutable trustedMsgSenderLookup;
|
|
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
|
+
|
|
76
88
|
/// @notice The constructor for the ZoraV4CoinHook.
|
|
77
89
|
/// @param poolManager_ The Uniswap V4 pool manager
|
|
78
90
|
/// @param coinVersionLookup_ The coin version lookup contract - used to determine if an address is a coin and what version it is.
|
|
79
|
-
/// @param
|
|
91
|
+
/// @param trustedMsgSenderLookup_ The trusted message sender lookup contract - used to determine if an address is trusted
|
|
80
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
|
|
81
95
|
constructor(
|
|
82
96
|
IPoolManager poolManager_,
|
|
83
97
|
IDeployedCoinVersionLookup coinVersionLookup_,
|
|
84
|
-
|
|
85
|
-
IHooksUpgradeGate upgradeGate_
|
|
98
|
+
ITrustedMsgSenderProviderLookup trustedMsgSenderLookup_,
|
|
99
|
+
IHooksUpgradeGate upgradeGate_,
|
|
100
|
+
IZoraLimitOrderBookCoinsInterface zoraLimitOrderBook_,
|
|
101
|
+
IZoraHookRegistry zoraHookRegistry_
|
|
86
102
|
) BaseHook(poolManager_) {
|
|
87
103
|
require(address(coinVersionLookup_) != address(0), CoinVersionLookupCannotBeZeroAddress());
|
|
88
|
-
|
|
89
104
|
require(address(upgradeGate_) != address(0), UpgradeGateCannotBeZeroAddress());
|
|
105
|
+
require(address(zoraLimitOrderBook_) != address(0), ZoraLimitOrderBookCannotBeZeroAddress());
|
|
106
|
+
require(address(zoraHookRegistry_) != address(0), ZoraHookRegistryCannotBeZeroAddress());
|
|
107
|
+
require(address(trustedMsgSenderLookup_) != address(0), TrustedMsgSenderLookupCannotBeZeroAddress());
|
|
90
108
|
|
|
91
109
|
coinVersionLookup = coinVersionLookup_;
|
|
92
110
|
upgradeGate = upgradeGate_;
|
|
111
|
+
trustedMsgSenderLookup = trustedMsgSenderLookup_;
|
|
112
|
+
zoraLimitOrderBook = zoraLimitOrderBook_;
|
|
113
|
+
zoraHookRegistry = zoraHookRegistry_;
|
|
114
|
+
}
|
|
93
115
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
/// @notice Returns the trusted message sender lookup contract
|
|
117
|
+
function getTrustedMsgSenderLookup() external view returns (ITrustedMsgSenderProviderLookup) {
|
|
118
|
+
return trustedMsgSenderLookup;
|
|
97
119
|
}
|
|
98
120
|
|
|
99
121
|
/// @notice Returns the uniswap v4 hook settings / permissions.
|
|
@@ -107,7 +129,7 @@ contract ZoraV4CoinHook is
|
|
|
107
129
|
afterAddLiquidity: false,
|
|
108
130
|
beforeRemoveLiquidity: false,
|
|
109
131
|
afterRemoveLiquidity: false,
|
|
110
|
-
beforeSwap:
|
|
132
|
+
beforeSwap: true,
|
|
111
133
|
afterSwap: true,
|
|
112
134
|
beforeDonate: false,
|
|
113
135
|
afterDonate: false,
|
|
@@ -120,7 +142,7 @@ contract ZoraV4CoinHook is
|
|
|
120
142
|
|
|
121
143
|
/// @inheritdoc IZoraV4CoinHook
|
|
122
144
|
function isTrustedMessageSender(address sender) external view returns (bool) {
|
|
123
|
-
return
|
|
145
|
+
return trustedMsgSenderLookup.isTrustedMsgSenderProvider(sender);
|
|
124
146
|
}
|
|
125
147
|
|
|
126
148
|
/// @inheritdoc IZoraV4CoinHook
|
|
@@ -139,7 +161,8 @@ contract ZoraV4CoinHook is
|
|
|
139
161
|
super.supportsInterface(interfaceId) ||
|
|
140
162
|
interfaceId == type(IUpgradeableDestinationV4Hook).interfaceId ||
|
|
141
163
|
interfaceId == type(IUpgradeableDestinationV4HookWithUpdateableFee).interfaceId ||
|
|
142
|
-
interfaceId == type(IVersionedContract).interfaceId
|
|
164
|
+
interfaceId == type(IVersionedContract).interfaceId ||
|
|
165
|
+
interfaceId == type(ISupportsLimitOrderFill).interfaceId;
|
|
143
166
|
}
|
|
144
167
|
|
|
145
168
|
/// @notice Internal fn generating the positions for a given pool key.
|
|
@@ -256,51 +279,6 @@ contract ZoraV4CoinHook is
|
|
|
256
279
|
|
|
257
280
|
// Store the positions and mint the initial liquidity into the new pool
|
|
258
281
|
_initializeForPositions(newKey, coin, positions);
|
|
259
|
-
|
|
260
|
-
// Handle any remaining token balances by adding them to the last position
|
|
261
|
-
// This ensures no tokens are left unminted during the migration process
|
|
262
|
-
_mintExtraLiquidityAtLastPosition(sqrtPriceX96, newKey);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/// @notice Internal fn to add any remaining token balances to the last liquidity position.
|
|
266
|
-
/// @param sqrtPriceX96 The sqrt price x96.
|
|
267
|
-
/// @param poolKey The pool key.
|
|
268
|
-
function _mintExtraLiquidityAtLastPosition(uint160 sqrtPriceX96, PoolKey memory poolKey) internal {
|
|
269
|
-
// Check if there are any leftover token balances in the hook after migration
|
|
270
|
-
// These could result from rounding or partial liquidity transfers
|
|
271
|
-
uint256 currency0Balance = poolKey.currency0.balanceOfSelf();
|
|
272
|
-
uint256 currency1Balance = poolKey.currency1.balanceOfSelf();
|
|
273
|
-
|
|
274
|
-
// Get the stored positions for this pool to access the last position
|
|
275
|
-
LpPosition[] storage positions = poolCoins[CoinCommon.hashPoolKey(poolKey)].positions;
|
|
276
|
-
|
|
277
|
-
// Only proceed if there are actually leftover tokens to mint
|
|
278
|
-
if (currency0Balance > 0 || currency1Balance > 0) {
|
|
279
|
-
// Get reference to the last position where we'll add the extra liquidity
|
|
280
|
-
LpPosition storage lastPosition = positions[positions.length - 1];
|
|
281
|
-
|
|
282
|
-
// Calculate how much liquidity we can create with the remaining token balances
|
|
283
|
-
// This uses the current pool price and the last position's tick range
|
|
284
|
-
uint128 newLiquidity = LiquidityAmounts.getLiquidityForAmounts(
|
|
285
|
-
sqrtPriceX96,
|
|
286
|
-
TickMath.getSqrtPriceAtTick(lastPosition.tickLower),
|
|
287
|
-
TickMath.getSqrtPriceAtTick(lastPosition.tickUpper),
|
|
288
|
-
currency0Balance,
|
|
289
|
-
currency1Balance
|
|
290
|
-
);
|
|
291
|
-
|
|
292
|
-
// Create a temporary array with just the last position to mint the extra liquidity
|
|
293
|
-
LpPosition[] memory newPositions = new LpPosition[](1);
|
|
294
|
-
newPositions[0] = lastPosition;
|
|
295
|
-
newPositions[0].liquidity = newLiquidity; // Set the calculated liquidity amount
|
|
296
|
-
|
|
297
|
-
// Mint the extra liquidity into the pool using the V4 liquidity manager
|
|
298
|
-
V4Liquidity.lockAndMint(poolManager, poolKey, newPositions);
|
|
299
|
-
|
|
300
|
-
// Update our internal tracking of the last position's liquidity
|
|
301
|
-
// This keeps our records in sync with the actual pool state
|
|
302
|
-
positions[positions.length - 1].liquidity += newPositions[0].liquidity;
|
|
303
|
-
}
|
|
304
282
|
}
|
|
305
283
|
|
|
306
284
|
/// @notice Saves the positions for the coin and mints them into the pool
|
|
@@ -317,6 +295,27 @@ contract ZoraV4CoinHook is
|
|
|
317
295
|
V4Liquidity.lockAndMint(poolManager, key, positions);
|
|
318
296
|
}
|
|
319
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
|
+
|
|
320
319
|
/// @notice Internal fn called when a swap is executed.
|
|
321
320
|
/// @dev This hook is called from BaseHook library from uniswap v4.
|
|
322
321
|
/// This hook:
|
|
@@ -337,6 +336,10 @@ contract ZoraV4CoinHook is
|
|
|
337
336
|
BalanceDelta delta,
|
|
338
337
|
bytes calldata hookData
|
|
339
338
|
) internal virtual override returns (bytes4, int128) {
|
|
339
|
+
if (_isInternalSwap(sender)) {
|
|
340
|
+
return (BaseHook.afterSwap.selector, 0);
|
|
341
|
+
}
|
|
342
|
+
|
|
340
343
|
bytes32 poolKeyHash = CoinCommon.hashPoolKey(key);
|
|
341
344
|
|
|
342
345
|
// get the coin address and positions for the pool key; they must have been set in the afterInitialize callback
|
|
@@ -379,9 +382,19 @@ contract ZoraV4CoinHook is
|
|
|
379
382
|
);
|
|
380
383
|
}
|
|
381
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
|
+
|
|
382
388
|
return (BaseHook.afterSwap.selector, 0);
|
|
383
389
|
}
|
|
384
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
|
+
|
|
385
398
|
/// @dev Internal fn to allow for overriding market reward distribution logic
|
|
386
399
|
function _distributeMarketRewards(Currency currency, uint128 fees, IHasRewardsRecipients coin, address tradeReferrer) internal virtual {
|
|
387
400
|
// get rewards distribution methodology from the coin
|
|
@@ -403,7 +416,7 @@ contract ZoraV4CoinHook is
|
|
|
403
416
|
/// @return swapper The original message sender.
|
|
404
417
|
/// @return senderIsTrusted Whether the sender is a trusted message sender.
|
|
405
418
|
function _getOriginalMsgSender(address sender) internal view returns (address swapper, bool senderIsTrusted) {
|
|
406
|
-
senderIsTrusted =
|
|
419
|
+
senderIsTrusted = trustedMsgSenderLookup.isTrustedMsgSenderProvider(sender);
|
|
407
420
|
|
|
408
421
|
// If getter function reverts, we return a 0 address by default and continue execution.
|
|
409
422
|
try IMsgSender(sender).msgSender() returns (address _swapper) {
|
|
@@ -431,6 +444,11 @@ contract ZoraV4CoinHook is
|
|
|
431
444
|
delete poolCoins[poolKeyHash];
|
|
432
445
|
}
|
|
433
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
|
+
|
|
434
452
|
/// @notice Receives ETH from the pool manager for ETH-backed coins during fee collection.
|
|
435
453
|
/// @dev Only required for coins using ETH as backing currency (currency = address(0)).
|
|
436
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,18 @@
|
|
|
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
|
+
/// @title ITrustedMsgSenderProviderLookup
|
|
11
|
+
/// @notice Interface for contracts that can determine if an address is a trusted message sender
|
|
12
|
+
/// @dev This interface allows the hook to delegate the trusted sender check to an external contract
|
|
13
|
+
interface ITrustedMsgSenderProviderLookup {
|
|
14
|
+
/// @notice Checks if an address is a trusted message sender provider
|
|
15
|
+
/// @param sender The address to check
|
|
16
|
+
/// @return true if the sender is trusted, false otherwise
|
|
17
|
+
function isTrustedMsgSenderProvider(address sender) external view returns (bool);
|
|
18
|
+
}
|