@zoralabs/coins 0.7.1 → 1.0.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.log +106 -84
- package/CHANGELOG.md +68 -0
- package/abis/BadImpl.json +15 -0
- package/abis/BalanceDeltaLibrary.json +15 -0
- package/abis/BaseCoin.json +1350 -0
- package/abis/BaseCoinDeployHook.json +78 -0
- package/abis/BaseHook.json +897 -0
- package/abis/BaseTest.json +60 -91
- package/abis/BeforeSwapDeltaLibrary.json +15 -0
- package/abis/BuySupplyWithSwapRouterHook.json +126 -0
- package/abis/Coin.json +214 -150
- package/abis/CoinConstants.json +65 -0
- package/abis/CoinDopplerMultiCurve.json +38 -0
- package/abis/CoinRewardsV4.json +54 -0
- package/abis/CoinTest.json +66 -111
- package/abis/CoinUniV4Test.json +1053 -0
- package/abis/CoinV4.json +1687 -0
- package/abis/CurrencyLibrary.json +25 -0
- package/abis/DeployHooks.json +9 -0
- package/abis/DeployScript.json +47 -0
- package/abis/DeployedCoinVersionLookup.json +21 -0
- package/abis/DeployedCoinVersionLookupTest.json +716 -0
- package/abis/DifferentNamespaceVersionLookup.json +39 -0
- package/abis/DopplerUniswapV3Test.json +62 -184
- package/abis/ERC20.json +310 -0
- package/abis/FactoryTest.json +98 -98
- package/abis/FakeHookNoInterface.json +21 -0
- package/abis/FeeEstimatorHook.json +1528 -0
- package/abis/Hooks.json +28 -0
- package/abis/HooksDeployment.json +23 -0
- package/abis/HooksTest.json +698 -0
- package/abis/IAllowanceTransfer.json +486 -0
- package/abis/ICoin.json +62 -69
- package/abis/ICoinDeployHook.json +31 -0
- package/abis/ICoinV3.json +879 -0
- package/abis/ICoinV4.json +915 -0
- package/abis/IContractMetadata.json +28 -0
- package/abis/IDeployedCoinVersionLookup.json +21 -0
- package/abis/IEIP712.json +15 -0
- package/abis/IEIP712_v4.json +15 -0
- package/abis/IERC20Minimal.json +172 -0
- package/abis/IERC6909Claims.json +288 -0
- package/abis/IERC721.json +36 -36
- package/abis/IERC721Permit_v4.json +88 -0
- package/abis/IExtsload.json +64 -0
- package/abis/IExttload.json +40 -0
- package/abis/IHasAfterCoinDeploy.json +31 -0
- package/abis/IHasContractName.json +15 -0
- package/abis/IHasPoolKey.json +42 -0
- package/abis/IHasRewardsRecipients.json +54 -0
- package/abis/IHasSwapPath.json +60 -0
- package/abis/IHooks.json +789 -0
- package/abis/IImmutableState.json +15 -0
- package/abis/IMsgSender.json +15 -0
- package/abis/IMulticall_v4.json +21 -0
- package/abis/INotifier.json +187 -0
- package/abis/IPermit2.json +865 -0
- package/abis/IPermit2Forwarder.json +138 -0
- package/abis/IPoolConfigEncoding.json +46 -0
- package/abis/IPoolInitializer_v4.json +53 -0
- package/abis/IPoolManager.json +1286 -0
- package/abis/IPositionManager.json +712 -0
- package/abis/IProtocolFees.json +174 -0
- package/abis/ISignatureTransfer.json +394 -0
- package/abis/ISubscriber.json +89 -0
- package/abis/ISwapPathRouter.json +92 -0
- package/abis/ISwapRouter.json +82 -0
- package/abis/IUniversalRouter.json +61 -0
- package/abis/IUnlockCallback.json +21 -0
- package/abis/IUnorderedNonce.json +44 -0
- package/abis/IV4Quoter.json +310 -0
- package/abis/IV4Router.json +47 -0
- package/abis/IZoraFactory.json +328 -4
- package/abis/IZoraV4CoinHook.json +427 -0
- package/abis/ImmutableState.json +36 -0
- package/abis/LPFeeLibrary.json +65 -0
- package/abis/MockERC20.json +21 -0
- package/abis/MultiOwnableTest.json +60 -91
- package/abis/{CoinConfigurationVersions.json → Position.json} +1 -1
- package/abis/PrintUpgradeCommand.json +9 -0
- package/abis/ProxyShim.json +24 -0
- package/abis/Simulate.json +0 -91
- package/abis/StateLibrary.json +80 -0
- package/abis/TestDeployedCoinVersionLookupImplementation.json +39 -0
- package/abis/TestV4Swap.json +9 -0
- package/abis/{CoinSetup.json → UniV3BuySell.json} +5 -0
- package/abis/UniV3Errors.json +32 -0
- package/abis/UpgradeCoinImpl.json +47 -0
- package/abis/UpgradeFactoryImpl.json +9 -0
- package/abis/UpgradesTest.json +671 -0
- package/abis/Vm.json +1482 -111
- package/abis/VmSafe.json +856 -32
- package/abis/ZoraFactoryImpl.json +450 -1
- package/abis/ZoraV4CoinHook.json +1439 -0
- package/addresses/8453.json +8 -3
- package/addresses/84532.json +8 -3
- package/dist/index.cjs +1998 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1989 -178
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +2852 -688
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +1992 -173
- package/package.json +7 -2
- package/remappings.txt +6 -1
- package/script/CoinsDeployerBase.sol +105 -10
- package/script/DeployDevFactory.s.sol +21 -0
- package/script/DeployHooks.s.sol +22 -0
- package/script/PrintUpgradeCommand.s.sol +13 -0
- package/script/Simulate.s.sol +4 -12
- package/script/TestBackingCoinSwap.s.sol +146 -0
- package/script/TestV4Swap.s.sol +136 -0
- package/script/UpgradeCoinImpl.sol +2 -2
- package/script/UpgradeFactoryImpl.s.sol +23 -0
- package/src/BaseCoin.sol +176 -0
- package/src/Coin.sol +93 -515
- package/src/CoinV4.sol +121 -0
- package/src/ZoraFactoryImpl.sol +257 -57
- package/src/hooks/ZoraV4CoinHook.sol +195 -0
- package/src/hooks/deployment/BaseCoinDeployHook.sol +62 -0
- package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +80 -0
- package/src/interfaces/ICoin.sol +35 -39
- package/src/interfaces/ICoinDeployHook.sol +8 -0
- package/src/interfaces/ICoinV3.sol +71 -0
- package/src/interfaces/ICoinV4.sol +69 -0
- package/src/interfaces/IDeployedCoinVersionLookup.sol +11 -0
- package/src/interfaces/IMsgSender.sol +9 -0
- package/src/interfaces/IPoolConfigEncoding.sol +14 -0
- package/src/interfaces/ISwapPathRouter.sol +14 -0
- package/src/interfaces/ISwapRouter.sol +1 -35
- package/src/interfaces/IZoraFactory.sol +97 -7
- package/src/interfaces/IZoraV4CoinHook.sol +116 -0
- package/src/libs/CoinCommon.sol +15 -0
- package/src/libs/CoinConfigurationVersions.sol +116 -1
- package/src/{utils → libs}/CoinConstants.sol +11 -6
- package/src/libs/CoinDopplerMultiCurve.sol +134 -0
- package/src/libs/CoinDopplerUniV3.sol +19 -171
- package/src/libs/CoinRewards.sol +195 -0
- package/src/libs/CoinRewardsV4.sol +180 -0
- package/src/libs/CoinSetup.sol +40 -20
- package/src/libs/CoinSetupV3.sol +50 -0
- package/src/libs/DopplerMath.sol +156 -0
- package/src/libs/HooksDeployment.sol +84 -0
- package/src/libs/MarketConstants.sol +4 -0
- package/src/libs/PoolStateReader.sol +22 -0
- package/src/libs/UniV3BuySell.sol +231 -0
- package/src/libs/UniV3Errors.sol +11 -0
- package/src/libs/UniV4SwapHelper.sol +65 -0
- package/src/libs/UniV4SwapToCurrency.sol +109 -0
- package/src/libs/V4Liquidity.sol +129 -0
- package/src/types/PoolConfiguration.sol +15 -0
- package/src/utils/DeployedCoinVersionLookup.sol +52 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +94 -101
- package/test/CoinDopplerUniV3.t.sol +35 -184
- package/test/CoinUniV4.t.sol +752 -0
- package/test/DeploymentHooks.t.sol +270 -0
- package/test/Factory.t.sol +84 -50
- package/test/MultiOwnable.t.sol +6 -3
- package/test/Upgrades.t.sol +68 -0
- package/test/mocks/MockERC20.sol +12 -0
- package/test/utils/BaseTest.sol +124 -59
- package/test/utils/DeployedCoinVersionLookup.t.sol +127 -0
- package/test/utils/FeeEstimatorHook.sol +84 -0
- package/test/utils/ProxyShim.sol +17 -0
- package/wagmi.config.ts +10 -9
- package/src/libs/CoinLegacy.sol +0 -48
package/src/CoinV4.sol
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.23;
|
|
3
|
+
|
|
4
|
+
import {IPoolManager, PoolKey, Currency, IHooks} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
5
|
+
|
|
6
|
+
import {BaseCoin} from "./BaseCoin.sol";
|
|
7
|
+
import {ICoinV4, IHasPoolKey, IHasSwapPath} from "./interfaces/ICoinV4.sol";
|
|
8
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
9
|
+
import {PoolConfiguration} from "./types/PoolConfiguration.sol";
|
|
10
|
+
import {UniV4SwapToCurrency} from "./libs/UniV4SwapToCurrency.sol";
|
|
11
|
+
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
|
|
12
|
+
import {IDeployedCoinVersionLookup} from "./interfaces/IDeployedCoinVersionLookup.sol";
|
|
13
|
+
|
|
14
|
+
contract CoinV4 is BaseCoin, ICoinV4 {
|
|
15
|
+
/// @notice The Uniswap v4 pool manager singleton contract reference.
|
|
16
|
+
IPoolManager public immutable poolManager;
|
|
17
|
+
|
|
18
|
+
/// @notice The hooks contract used by this coin.
|
|
19
|
+
IHooks public immutable hooks;
|
|
20
|
+
|
|
21
|
+
/// @notice The pool key for the coin. Type from Uniswap V4 core.
|
|
22
|
+
PoolKey private poolKey;
|
|
23
|
+
|
|
24
|
+
/// @notice The configuration for the pool.
|
|
25
|
+
PoolConfiguration private poolConfiguration;
|
|
26
|
+
|
|
27
|
+
/// @notice The constructor for the static CoinV4 contract deployment shared across all Coins.
|
|
28
|
+
/// @dev All arguments are required and cannot be set to teh 0 address.
|
|
29
|
+
/// @param protocolRewardRecipient_ The address of the protocol reward recipient
|
|
30
|
+
/// @param protocolRewards_ The address of the protocol rewards contract
|
|
31
|
+
/// @param poolManager_ The address of the pool manager
|
|
32
|
+
/// @param airlock_ The address of the Airlock contract, ownership is used for a protocol fee split.
|
|
33
|
+
/// @param hooks_ The address of the hooks contract
|
|
34
|
+
/// @notice Returns the pool key for the coin
|
|
35
|
+
constructor(
|
|
36
|
+
address protocolRewardRecipient_,
|
|
37
|
+
address protocolRewards_,
|
|
38
|
+
IPoolManager poolManager_,
|
|
39
|
+
address airlock_,
|
|
40
|
+
IHooks hooks_
|
|
41
|
+
) BaseCoin(protocolRewardRecipient_, protocolRewards_, airlock_) {
|
|
42
|
+
if (address(poolManager_) == address(0)) {
|
|
43
|
+
revert AddressZero();
|
|
44
|
+
}
|
|
45
|
+
if (address(hooks_) == address(0)) {
|
|
46
|
+
revert AddressZero();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
poolManager = poolManager_;
|
|
50
|
+
hooks = hooks_;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// @inheritdoc IHasPoolKey
|
|
54
|
+
function getPoolKey() public view returns (PoolKey memory) {
|
|
55
|
+
return poolKey;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// @inheritdoc ICoinV4
|
|
59
|
+
function getPoolConfiguration() public view returns (PoolConfiguration memory) {
|
|
60
|
+
return poolConfiguration;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// @inheritdoc ICoinV4
|
|
64
|
+
function initialize(
|
|
65
|
+
address payoutRecipient_,
|
|
66
|
+
address[] memory owners_,
|
|
67
|
+
string memory tokenURI_,
|
|
68
|
+
string memory name_,
|
|
69
|
+
string memory symbol_,
|
|
70
|
+
address platformReferrer_,
|
|
71
|
+
address currency_,
|
|
72
|
+
PoolKey memory poolKey_,
|
|
73
|
+
uint160 sqrtPriceX96,
|
|
74
|
+
PoolConfiguration memory poolConfiguration_
|
|
75
|
+
) public initializer {
|
|
76
|
+
super._initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
|
|
77
|
+
|
|
78
|
+
currency = currency_;
|
|
79
|
+
poolKey = poolKey_;
|
|
80
|
+
poolConfiguration = poolConfiguration_;
|
|
81
|
+
|
|
82
|
+
// transfer the supply to the hook
|
|
83
|
+
_transfer(address(this), address(hooks), balanceOf(address(this)));
|
|
84
|
+
// initialize the pool - the hook will mint its positions in the afterInitialize callback
|
|
85
|
+
poolManager.initialize(poolKey, sqrtPriceX96);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function supportsInterface(bytes4 interfaceId) public pure virtual override(BaseCoin, IERC165) returns (bool) {
|
|
89
|
+
return interfaceId == type(IHasPoolKey).interfaceId || type(IHasSwapPath).interfaceId == interfaceId || super.supportsInterface(interfaceId);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// @inheritdoc IHasSwapPath
|
|
93
|
+
function getPayoutSwapPath(IDeployedCoinVersionLookup coinVersionLookup) external view returns (IHasSwapPath.PayoutSwapPath memory payoutSwapPath) {
|
|
94
|
+
// if to swap in is this currency,
|
|
95
|
+
// if backing currency is a coin, then recursively get the path from the coin
|
|
96
|
+
payoutSwapPath.currencyIn = Currency.wrap(address(this));
|
|
97
|
+
|
|
98
|
+
// swap to backing currency
|
|
99
|
+
PathKey memory thisPathKey = PathKey({
|
|
100
|
+
intermediateCurrency: Currency.wrap(currency),
|
|
101
|
+
fee: poolKey.fee,
|
|
102
|
+
tickSpacing: poolKey.tickSpacing,
|
|
103
|
+
hooks: poolKey.hooks,
|
|
104
|
+
hookData: ""
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// get backing currency swap path - if the backing currency is a v4 coin and has a swap path.
|
|
108
|
+
PathKey[] memory subPath = UniV4SwapToCurrency.getSubSwapPath(currency, coinVersionLookup);
|
|
109
|
+
|
|
110
|
+
if (subPath.length > 0) {
|
|
111
|
+
payoutSwapPath.path = new PathKey[](1 + subPath.length);
|
|
112
|
+
payoutSwapPath.path[0] = thisPathKey;
|
|
113
|
+
for (uint256 i = 0; i < subPath.length; i++) {
|
|
114
|
+
payoutSwapPath.path[i + 1] = subPath[i];
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
payoutSwapPath.path = new PathKey[](1);
|
|
118
|
+
payoutSwapPath.path[0] = thisPathKey;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
package/src/ZoraFactoryImpl.sol
CHANGED
|
@@ -9,29 +9,108 @@ import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.s
|
|
|
9
9
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
10
10
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
11
11
|
import {CoinConfigurationVersions} from "./libs/CoinConfigurationVersions.sol";
|
|
12
|
-
|
|
12
|
+
import {ISwapRouter} from "./interfaces/ISwapRouter.sol";
|
|
13
|
+
import {IWETH} from "./interfaces/IWETH.sol";
|
|
13
14
|
import {IZoraFactory} from "./interfaces/IZoraFactory.sol";
|
|
15
|
+
import {IHasAfterCoinDeploy} from "./hooks/deployment/BaseCoinDeployHook.sol";
|
|
16
|
+
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
14
17
|
import {Coin} from "./Coin.sol";
|
|
18
|
+
import {CoinV4} from "./CoinV4.sol";
|
|
19
|
+
import {ICoin, PoolKeyStruct} from "./interfaces/ICoin.sol";
|
|
20
|
+
import {ICoinV3} from "./interfaces/ICoinV3.sol";
|
|
21
|
+
import {ICoinV4} from "./interfaces/ICoinV4.sol";
|
|
22
|
+
import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
|
|
23
|
+
import {ContractVersionBase} from "./version/ContractVersionBase.sol";
|
|
24
|
+
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
25
|
+
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
26
|
+
import {CoinCommon} from "./libs/CoinCommon.sol";
|
|
27
|
+
import {UniV3Config} from "./libs/CoinSetupV3.sol";
|
|
28
|
+
import {CoinSetupV3} from "./libs/CoinSetupV3.sol";
|
|
29
|
+
import {PoolConfiguration} from "./types/PoolConfiguration.sol";
|
|
30
|
+
import {LpPosition} from "./types/LpPosition.sol";
|
|
31
|
+
import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
|
|
32
|
+
import {CoinSetup} from "./libs/CoinSetup.sol";
|
|
33
|
+
import {CoinDopplerMultiCurve} from "./libs/CoinDopplerMultiCurve.sol";
|
|
34
|
+
|
|
35
|
+
import {DeployedCoinVersionLookup} from "./utils/DeployedCoinVersionLookup.sol";
|
|
15
36
|
|
|
16
|
-
contract ZoraFactoryImpl is
|
|
37
|
+
contract ZoraFactoryImpl is
|
|
38
|
+
IZoraFactory,
|
|
39
|
+
UUPSUpgradeable,
|
|
40
|
+
ReentrancyGuardUpgradeable,
|
|
41
|
+
OwnableUpgradeable,
|
|
42
|
+
IHasContractName,
|
|
43
|
+
ContractVersionBase,
|
|
44
|
+
DeployedCoinVersionLookup
|
|
45
|
+
{
|
|
17
46
|
using SafeERC20 for IERC20;
|
|
18
47
|
|
|
19
48
|
/// @notice The coin contract implementation address
|
|
20
49
|
address public immutable coinImpl;
|
|
50
|
+
address public immutable coinV4Impl;
|
|
21
51
|
|
|
22
|
-
constructor(address _coinImpl) initializer {
|
|
52
|
+
constructor(address _coinImpl, address _coinV4Impl) initializer {
|
|
23
53
|
coinImpl = _coinImpl;
|
|
54
|
+
coinV4Impl = _coinV4Impl;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// @inheritdoc IZoraFactory
|
|
58
|
+
function deploy(
|
|
59
|
+
address payoutRecipient,
|
|
60
|
+
address[] memory owners,
|
|
61
|
+
string memory uri,
|
|
62
|
+
string memory name,
|
|
63
|
+
string memory symbol,
|
|
64
|
+
bytes memory poolConfig,
|
|
65
|
+
address platformReferrer,
|
|
66
|
+
address postDeployHook,
|
|
67
|
+
bytes calldata postDeployHookData,
|
|
68
|
+
bytes32 coinSalt
|
|
69
|
+
) external payable returns (address coin, bytes memory postDeployHookDataOut) {
|
|
70
|
+
bytes32 salt = _buildSalt(msg.sender, name, symbol, poolConfig, platformReferrer, coinSalt);
|
|
71
|
+
return _deployWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, postDeployHook, postDeployHookData, salt);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function coinAddress(
|
|
75
|
+
address msgSender,
|
|
76
|
+
string memory name,
|
|
77
|
+
string memory symbol,
|
|
78
|
+
bytes memory poolConfig,
|
|
79
|
+
address platformReferrer,
|
|
80
|
+
bytes32 coinSalt
|
|
81
|
+
) external view returns (address) {
|
|
82
|
+
bytes32 salt = _buildSalt(msgSender, name, symbol, poolConfig, platformReferrer, coinSalt);
|
|
83
|
+
return Clones.predictDeterministicAddress(getCoinImpl(CoinConfigurationVersions.getVersion(poolConfig)), salt, address(this));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _deployWithHook(
|
|
87
|
+
address payoutRecipient,
|
|
88
|
+
address[] memory owners,
|
|
89
|
+
string memory uri,
|
|
90
|
+
string memory name,
|
|
91
|
+
string memory symbol,
|
|
92
|
+
bytes memory poolConfig,
|
|
93
|
+
address platformReferrer,
|
|
94
|
+
address hook,
|
|
95
|
+
bytes calldata hookData,
|
|
96
|
+
bytes32 salt
|
|
97
|
+
) internal returns (address coin, bytes memory hookDataOut) {
|
|
98
|
+
coin = address(_createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt));
|
|
99
|
+
|
|
100
|
+
if (hook != address(0)) {
|
|
101
|
+
if (!IERC165(hook).supportsInterface(type(IHasAfterCoinDeploy).interfaceId)) {
|
|
102
|
+
revert InvalidHook();
|
|
103
|
+
}
|
|
104
|
+
hookDataOut = IHasAfterCoinDeploy(hook).afterCoinDeploy{value: msg.value}(msg.sender, ICoin(coin), hookData);
|
|
105
|
+
} else if (msg.value > 0) {
|
|
106
|
+
// cannot send eth without a hook
|
|
107
|
+
revert EthTransferInvalid();
|
|
108
|
+
}
|
|
24
109
|
}
|
|
25
110
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
/// @
|
|
29
|
-
/// @param uri The coin metadata uri
|
|
30
|
-
/// @param name The name of the coin
|
|
31
|
-
/// @param symbol The symbol of the coin
|
|
32
|
-
/// @param poolConfig The config parameters for the Uniswap v3 pool; `abi.encode(address currency, int24 tickLower, int24 tickUpper, uint16 numDiscoveryPositions, uint256 maxDiscoverySupplyShare)`
|
|
33
|
-
/// @param platformReferrer The address of the platform referrer
|
|
34
|
-
/// @param orderSize The order size for the first buy; must match msg.value for ETH/WETH pairs
|
|
111
|
+
/** Deprecated deploy functions */
|
|
112
|
+
|
|
113
|
+
/// @dev Deprecated: use `deploy` instead that has a salt and hook specified
|
|
35
114
|
function deploy(
|
|
36
115
|
address payoutRecipient,
|
|
37
116
|
address[] memory owners,
|
|
@@ -42,40 +121,32 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
42
121
|
address platformReferrer,
|
|
43
122
|
uint256 orderSize
|
|
44
123
|
) public payable nonReentrant returns (address, uint256) {
|
|
45
|
-
bytes32 salt =
|
|
124
|
+
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
46
125
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
coin.initialize(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer);
|
|
126
|
+
ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
|
|
50
127
|
|
|
51
128
|
uint256 coinsPurchased = _handleFirstOrder(coin, orderSize);
|
|
52
129
|
|
|
53
|
-
emit CoinCreated(
|
|
54
|
-
msg.sender,
|
|
55
|
-
payoutRecipient,
|
|
56
|
-
coin.platformReferrer(),
|
|
57
|
-
coin.currency(),
|
|
58
|
-
uri,
|
|
59
|
-
name,
|
|
60
|
-
symbol,
|
|
61
|
-
address(coin),
|
|
62
|
-
coin.poolAddress(),
|
|
63
|
-
coin.contractVersion()
|
|
64
|
-
);
|
|
65
|
-
|
|
66
130
|
return (address(coin), coinsPurchased);
|
|
67
131
|
}
|
|
68
132
|
|
|
69
|
-
/// @
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
133
|
+
/// @dev Deprecated: use `deploy` instead that has a salt and hook specified
|
|
134
|
+
function deployWithHook(
|
|
135
|
+
address payoutRecipient,
|
|
136
|
+
address[] memory owners,
|
|
137
|
+
string memory uri,
|
|
138
|
+
string memory name,
|
|
139
|
+
string memory symbol,
|
|
140
|
+
bytes memory poolConfig,
|
|
141
|
+
address platformReferrer,
|
|
142
|
+
address hook,
|
|
143
|
+
bytes calldata hookData
|
|
144
|
+
) public payable nonReentrant returns (address coin, bytes memory hookDataOut) {
|
|
145
|
+
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
146
|
+
return _deployWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, hook, hookData, salt);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// @dev deprecated Use deploy() with poolConfig instead
|
|
79
150
|
function deploy(
|
|
80
151
|
address payoutRecipient,
|
|
81
152
|
address[] memory owners,
|
|
@@ -84,37 +155,148 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
84
155
|
string memory symbol,
|
|
85
156
|
address platformReferrer,
|
|
86
157
|
address currency,
|
|
87
|
-
|
|
158
|
+
// tickLower is no longer used
|
|
159
|
+
int24 /*tickLower*/,
|
|
88
160
|
uint256 orderSize
|
|
89
161
|
) public payable nonReentrant returns (address, uint256) {
|
|
90
|
-
|
|
162
|
+
bytes memory poolConfig = CoinConfigurationVersions.defaultConfig(currency);
|
|
163
|
+
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
164
|
+
|
|
165
|
+
ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
|
|
91
166
|
|
|
92
|
-
|
|
167
|
+
uint256 coinsPurchased = _handleFirstOrder(coin, orderSize);
|
|
93
168
|
|
|
94
|
-
|
|
169
|
+
return (address(coin), coinsPurchased);
|
|
170
|
+
}
|
|
95
171
|
|
|
96
|
-
|
|
172
|
+
function getCoinImpl(uint8 version) internal view returns (address) {
|
|
173
|
+
if (CoinConfigurationVersions.isV3(version)) {
|
|
174
|
+
return coinImpl;
|
|
175
|
+
} else if (CoinConfigurationVersions.isV4(version)) {
|
|
176
|
+
return coinV4Impl;
|
|
177
|
+
}
|
|
97
178
|
|
|
98
|
-
|
|
179
|
+
revert ICoin.InvalidPoolVersion();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function _createCoin(uint8 version, bytes32 salt) internal returns (address payable) {
|
|
183
|
+
return payable(Clones.cloneDeterministic(getCoinImpl(version), salt));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function _setupV3Coin(
|
|
187
|
+
ICoinV3 coin,
|
|
188
|
+
address currency,
|
|
189
|
+
bool isCoinToken0,
|
|
190
|
+
uint160 sqrtPriceX96,
|
|
191
|
+
PoolConfiguration memory poolConfiguration,
|
|
192
|
+
address payoutRecipient,
|
|
193
|
+
address[] memory owners,
|
|
194
|
+
string memory uri,
|
|
195
|
+
string memory name,
|
|
196
|
+
string memory symbol,
|
|
197
|
+
address platformReferrer
|
|
198
|
+
) internal {
|
|
199
|
+
address v3Factory = coin.v3Factory();
|
|
200
|
+
|
|
201
|
+
address poolAddress = CoinSetupV3.createV3Pool(address(coin), currency, isCoinToken0, sqrtPriceX96, v3Factory);
|
|
202
|
+
|
|
203
|
+
LpPosition[] memory positions = CoinDopplerMultiCurve.calculatePositions(isCoinToken0, poolConfiguration);
|
|
204
|
+
|
|
205
|
+
// Initialize coin with pre-configured pool
|
|
206
|
+
coin.initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolAddress, poolConfiguration, positions);
|
|
99
207
|
|
|
100
208
|
emit CoinCreated(
|
|
101
209
|
msg.sender,
|
|
102
210
|
payoutRecipient,
|
|
103
|
-
|
|
104
|
-
|
|
211
|
+
platformReferrer,
|
|
212
|
+
currency,
|
|
105
213
|
uri,
|
|
106
214
|
name,
|
|
107
215
|
symbol,
|
|
108
216
|
address(coin),
|
|
109
|
-
|
|
110
|
-
coin.contractVersion()
|
|
217
|
+
poolAddress,
|
|
218
|
+
IVersionedContract(address(coin)).contractVersion()
|
|
111
219
|
);
|
|
220
|
+
}
|
|
112
221
|
|
|
113
|
-
|
|
222
|
+
function _setupV4Coin(
|
|
223
|
+
ICoinV4 coin,
|
|
224
|
+
address currency,
|
|
225
|
+
bool isCoinToken0,
|
|
226
|
+
uint160 sqrtPriceX96,
|
|
227
|
+
PoolConfiguration memory poolConfiguration,
|
|
228
|
+
address payoutRecipient,
|
|
229
|
+
address[] memory owners,
|
|
230
|
+
string memory uri,
|
|
231
|
+
string memory name,
|
|
232
|
+
string memory symbol,
|
|
233
|
+
address platformReferrer
|
|
234
|
+
) internal {
|
|
235
|
+
PoolKey memory poolKey = CoinSetup.buildPoolKey(address(coin), currency, isCoinToken0, coin.hooks());
|
|
236
|
+
|
|
237
|
+
// Initialize coin with pre-configured pool
|
|
238
|
+
coin.initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolKey, sqrtPriceX96, poolConfiguration);
|
|
239
|
+
|
|
240
|
+
emit CoinCreatedV4(
|
|
241
|
+
msg.sender,
|
|
242
|
+
payoutRecipient,
|
|
243
|
+
platformReferrer,
|
|
244
|
+
currency,
|
|
245
|
+
uri,
|
|
246
|
+
name,
|
|
247
|
+
symbol,
|
|
248
|
+
address(coin),
|
|
249
|
+
poolKey,
|
|
250
|
+
CoinCommon.hashPoolKey(poolKey),
|
|
251
|
+
IVersionedContract(address(coin)).contractVersion()
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function _createAndInitializeCoin(
|
|
256
|
+
address payoutRecipient,
|
|
257
|
+
address[] memory owners,
|
|
258
|
+
string memory uri,
|
|
259
|
+
string memory name,
|
|
260
|
+
string memory symbol,
|
|
261
|
+
bytes memory poolConfig,
|
|
262
|
+
address platformReferrer,
|
|
263
|
+
bytes32 coinSalt
|
|
264
|
+
) internal returns (ICoin) {
|
|
265
|
+
uint8 version = CoinConfigurationVersions.getVersion(poolConfig);
|
|
266
|
+
|
|
267
|
+
address payable coin = _createCoin(version, coinSalt);
|
|
268
|
+
|
|
269
|
+
_setVersionForDeployedCoin(address(coin), version);
|
|
270
|
+
|
|
271
|
+
(, address currency, uint160 sqrtPriceX96, bool isCoinToken0, PoolConfiguration memory poolConfiguration) = CoinSetup.generatePoolConfig(
|
|
272
|
+
address(coin),
|
|
273
|
+
poolConfig
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
if (CoinConfigurationVersions.isV3(version)) {
|
|
277
|
+
_setupV3Coin(ICoinV3(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
|
|
278
|
+
} else if (CoinConfigurationVersions.isV4(version)) {
|
|
279
|
+
_setupV4Coin(ICoinV4(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
|
|
280
|
+
} else {
|
|
281
|
+
revert ICoin.InvalidPoolVersion();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return ICoin(coin);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function _buildSalt(
|
|
288
|
+
address msgSender,
|
|
289
|
+
string memory name,
|
|
290
|
+
string memory symbol,
|
|
291
|
+
bytes memory poolConfig,
|
|
292
|
+
address platformReferrer,
|
|
293
|
+
bytes32 coinSalt
|
|
294
|
+
) internal pure returns (bytes32) {
|
|
295
|
+
return keccak256(abi.encodePacked(msgSender, name, symbol, poolConfig, platformReferrer, coinSalt));
|
|
114
296
|
}
|
|
115
297
|
|
|
116
298
|
/// @dev Generates a unique salt for deterministic deployment
|
|
117
|
-
function
|
|
299
|
+
function _randomSalt(address payoutRecipient, string memory uri, bytes32 coinSalt) internal view returns (bytes32) {
|
|
118
300
|
return
|
|
119
301
|
keccak256(
|
|
120
302
|
abi.encodePacked(
|
|
@@ -126,7 +308,8 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
126
308
|
block.prevrandao,
|
|
127
309
|
block.timestamp,
|
|
128
310
|
tx.gasprice,
|
|
129
|
-
tx.origin
|
|
311
|
+
tx.origin,
|
|
312
|
+
coinSalt
|
|
130
313
|
)
|
|
131
314
|
);
|
|
132
315
|
}
|
|
@@ -134,12 +317,12 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
134
317
|
/// @dev Handles the first buy of a newly created coin
|
|
135
318
|
/// @param coin The newly created coin contract
|
|
136
319
|
/// @param orderSize The size of the first buy order; must match msg.value for ETH/WETH pairs
|
|
137
|
-
function _handleFirstOrder(
|
|
320
|
+
function _handleFirstOrder(ICoin coin, uint256 orderSize) internal returns (uint256 coinsPurchased) {
|
|
138
321
|
if (msg.value > 0 || orderSize > 0) {
|
|
139
322
|
address currency = coin.currency();
|
|
140
323
|
address payoutRecipient = coin.payoutRecipient();
|
|
141
324
|
|
|
142
|
-
if (currency != coin.WETH()) {
|
|
325
|
+
if (currency != Coin(payable(address(coin))).WETH()) {
|
|
143
326
|
if (msg.value != 0) {
|
|
144
327
|
revert EthTransferInvalid();
|
|
145
328
|
}
|
|
@@ -148,9 +331,9 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
148
331
|
|
|
149
332
|
IERC20(currency).approve(address(coin), orderSize);
|
|
150
333
|
|
|
151
|
-
(, coinsPurchased) = coin.buy(payoutRecipient, orderSize, 0, 0, address(0));
|
|
334
|
+
(, coinsPurchased) = Coin(payable(address(coin))).buy(payoutRecipient, orderSize, 0, 0, address(0));
|
|
152
335
|
} else {
|
|
153
|
-
(, coinsPurchased) = coin.buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
|
|
336
|
+
(, coinsPurchased) = Coin(payable(address(coin))).buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
|
|
154
337
|
}
|
|
155
338
|
}
|
|
156
339
|
}
|
|
@@ -182,7 +365,24 @@ contract ZoraFactoryImpl is IZoraFactory, UUPSUpgradeable, ReentrancyGuardUpgrad
|
|
|
182
365
|
return ERC1967Utils.getImplementation();
|
|
183
366
|
}
|
|
184
367
|
|
|
368
|
+
/// @inheritdoc IHasContractName
|
|
369
|
+
function contractName() public pure override returns (string memory) {
|
|
370
|
+
return "ZoraCoinFactory";
|
|
371
|
+
}
|
|
372
|
+
|
|
185
373
|
/// @dev Authorizes an upgrade to a new implementation
|
|
186
374
|
/// @param newImpl The new implementation address
|
|
187
|
-
function _authorizeUpgrade(address newImpl) internal override onlyOwner {
|
|
375
|
+
function _authorizeUpgrade(address newImpl) internal override onlyOwner {
|
|
376
|
+
// try to get the existing contract name - if it reverts, the existing contract was an older version that didn't have the contract name
|
|
377
|
+
// unfortunately we cannot use supportsInterface here because the existing implementation did not have that function
|
|
378
|
+
try IHasContractName(newImpl).contractName() returns (string memory name) {
|
|
379
|
+
if (!_equals(name, contractName())) {
|
|
380
|
+
revert UpgradeToMismatchedContractName(contractName(), name);
|
|
381
|
+
}
|
|
382
|
+
} catch {}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function _equals(string memory a, string memory b) internal pure returns (bool) {
|
|
386
|
+
return (keccak256(bytes(a)) == keccak256(bytes(b)));
|
|
387
|
+
}
|
|
188
388
|
}
|