@zoralabs/coins 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build$colon$js.log +152 -0
- package/CHANGELOG.md +93 -0
- package/README.md +4 -0
- package/abis/BaseCoin.json +26 -5
- package/abis/BaseTest.json +2 -7
- package/abis/ContentCoin.json +26 -5
- package/abis/CreatorCoin.json +30 -9
- package/abis/FeeEstimatorHook.json +94 -6
- package/abis/ICoin.json +26 -0
- package/abis/ICoinV3.json +26 -0
- package/abis/ICreatorCoin.json +39 -0
- package/abis/IERC721.json +36 -36
- package/abis/IHasCoinType.json +15 -0
- package/abis/IHasTotalSupplyForPositions.json +15 -0
- package/abis/{LiquidityMigrationReceiver.json → IUpgradeableDestinationV4HookWithUpdateableFee.json} +10 -18
- package/abis/IZoraFactory.json +121 -0
- package/abis/IZoraHookRegistry.json +188 -0
- package/abis/VmContractHelper226.json +233 -0
- package/abis/ZoraFactoryImpl.json +101 -6
- package/abis/ZoraHookRegistry.json +375 -0
- package/abis/{CreatorCoinHook.json → ZoraV4CoinHook.json} +95 -2
- package/addresses/8453.json +6 -5
- package/audits/report-cantinacode-zora-0827.pdf +3498 -4
- package/dist/index.cjs +93 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +93 -13
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +144 -22
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/foundry.toml +4 -1
- package/package/wagmiGenerated.ts +93 -13
- package/package.json +6 -4
- package/script/PrintRegisterUpgradePath.s.sol +0 -7
- package/script/TestBackingCoinSwap.s.sol +0 -3
- package/script/TestV4Swap.s.sol +0 -3
- package/script/UpgradeFactoryImpl.s.sol +1 -1
- package/src/BaseCoin.sol +19 -24
- package/src/ContentCoin.sol +11 -2
- package/src/CreatorCoin.sol +34 -15
- package/src/ZoraFactoryImpl.sol +163 -92
- package/src/deployment/CoinsDeployerBase.sol +24 -58
- package/src/hook-registry/ZoraHookRegistry.sol +97 -0
- package/src/hooks/{BaseZoraV4CoinHook.sol → ZoraV4CoinHook.sol} +77 -15
- package/src/interfaces/ICoin.sol +19 -1
- package/src/interfaces/ICreatorCoin.sol +4 -0
- package/src/interfaces/IUpgradeableV4Hook.sol +18 -0
- package/src/interfaces/IZoraFactory.sol +51 -10
- package/src/interfaces/IZoraHookRegistry.sol +47 -0
- package/src/libs/CoinConstants.sol +43 -32
- package/src/libs/CoinDopplerMultiCurve.sol +11 -11
- package/src/libs/CoinRewardsV4.sol +68 -37
- package/src/libs/CoinSetup.sol +2 -9
- package/src/libs/DopplerMath.sol +2 -2
- package/src/libs/HooksDeployment.sol +13 -65
- package/src/libs/V4Liquidity.sol +109 -15
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +5 -5
- package/test/CoinRewardsV4.t.sol +33 -0
- package/test/CoinUniV4.t.sol +32 -30
- package/test/ContentCoinRewards.t.sol +363 -0
- package/test/CreatorCoin.t.sol +53 -29
- package/test/CreatorCoinRewards.t.sol +375 -0
- package/test/DeploymentHooks.t.sol +64 -12
- package/test/Factory.t.sol +24 -7
- package/test/HooksDeployment.t.sol +4 -4
- package/test/LiquidityMigration.t.sol +149 -16
- package/test/Upgrades.t.sol +44 -48
- package/test/V4Liquidity.t.sol +178 -0
- package/test/ZoraHookRegistry.t.sol +266 -0
- package/test/utils/BaseTest.sol +25 -43
- package/test/utils/FeeEstimatorHook.sol +4 -6
- package/test/utils/RewardTestHelpers.sol +106 -0
- package/.turbo/turbo-build.log +0 -199
- package/abis/AutoSwapperTest.json +0 -618
- package/abis/BadImpl.json +0 -15
- package/abis/BaseZoraV4CoinHook.json +0 -1664
- package/abis/CoinConstants.json +0 -158
- package/abis/CoinRewardsV4.json +0 -67
- package/abis/CoinTest.json +0 -819
- package/abis/CoinUniV4Test.json +0 -1128
- package/abis/ContentCoinHook.json +0 -1733
- package/abis/CreatorCoinTest.json +0 -887
- package/abis/Deploy.json +0 -9
- package/abis/DeployHooks.json +0 -9
- package/abis/DeployScript.json +0 -35
- package/abis/DeployedCoinVersionLookupTest.json +0 -740
- package/abis/DifferentNamespaceVersionLookup.json +0 -39
- package/abis/FactoryTest.json +0 -748
- package/abis/FakeHookNoInterface.json +0 -21
- package/abis/GenerateDeterministicParams.json +0 -9
- package/abis/HooksDeploymentTest.json +0 -645
- package/abis/HooksTest.json +0 -709
- package/abis/InvalidLiquidityMigrationReceiver.json +0 -21
- package/abis/LiquidityMigrationTest.json +0 -889
- package/abis/MockBadFactory.json +0 -15
- package/abis/MultiOwnableTest.json +0 -766
- package/abis/PrintUpgradeCommand.json +0 -9
- package/abis/TestDeployedCoinVersionLookupImplementation.json +0 -39
- package/abis/TestV4Swap.json +0 -9
- package/abis/UpgradeFactoryImpl.json +0 -9
- package/abis/UpgradeHooks.json +0 -35
- package/abis/UpgradesTest.json +0 -723
- package/src/hooks/ContentCoinHook.sol +0 -27
- package/src/hooks/CreatorCoinHook.sol +0 -27
- package/src/libs/CreatorCoinConstants.sol +0 -16
- package/src/libs/CreatorCoinRewards.sol +0 -34
- package/src/libs/MarketConstants.sol +0 -15
package/src/BaseCoin.sol
CHANGED
|
@@ -9,7 +9,7 @@ pragma solidity ^0.8.23;
|
|
|
9
9
|
|
|
10
10
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
11
11
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
12
|
-
import {ICoin} from "./interfaces/ICoin.sol";
|
|
12
|
+
import {ICoin, IHasTotalSupplyForPositions, IHasCoinType} from "./interfaces/ICoin.sol";
|
|
13
13
|
import {IHasRewardsRecipients} from "./interfaces/IHasRewardsRecipients.sol";
|
|
14
14
|
import {ICoinComments} from "./interfaces/ICoinComments.sol";
|
|
15
15
|
import {IERC7572} from "./interfaces/IERC7572.sol";
|
|
@@ -32,7 +32,6 @@ import {CoinCommon} from "./libs/CoinCommon.sol";
|
|
|
32
32
|
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
|
|
33
33
|
import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
|
|
34
34
|
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
|
|
35
|
-
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
|
|
36
35
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
37
36
|
import {ContractVersionBase} from "./version/ContractVersionBase.sol";
|
|
38
37
|
import {MultiOwnable} from "./utils/MultiOwnable.sol";
|
|
@@ -40,7 +39,6 @@ import {FullMath} from "./utils/uniswap/FullMath.sol";
|
|
|
40
39
|
import {TickMath} from "./utils/uniswap/TickMath.sol";
|
|
41
40
|
import {LiquidityAmounts} from "./utils/uniswap/LiquidityAmounts.sol";
|
|
42
41
|
import {CoinConstants} from "./libs/CoinConstants.sol";
|
|
43
|
-
import {MarketConstants} from "./libs/MarketConstants.sol";
|
|
44
42
|
import {LpPosition} from "./types/LpPosition.sol";
|
|
45
43
|
import {PoolState} from "./types/PoolState.sol";
|
|
46
44
|
|
|
@@ -54,7 +52,7 @@ import {PoolState} from "./types/PoolState.sol";
|
|
|
54
52
|
\$$$$$$ | $$$$$$ |$$$$$$\ $$ | \$$ |
|
|
55
53
|
\______/ \______/ \______|\__| \__|
|
|
56
54
|
*/
|
|
57
|
-
abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnable,
|
|
55
|
+
abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnable, ERC165Upgradeable {
|
|
58
56
|
using SafeERC20 for IERC20;
|
|
59
57
|
|
|
60
58
|
/// @notice The address of the protocol rewards contract
|
|
@@ -89,28 +87,29 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
89
87
|
|
|
90
88
|
/**
|
|
91
89
|
* @notice The constructor for the static Coin contract deployment shared across all Coins.
|
|
92
|
-
* @param
|
|
93
|
-
* @param
|
|
94
|
-
* @param
|
|
90
|
+
* @param protocolRewardRecipient_ The address of the protocol reward recipient
|
|
91
|
+
* @param protocolRewards_ The address of the protocol rewards contract
|
|
92
|
+
* @param poolManager_ The address of the pool manager
|
|
93
|
+
* @param airlock_ The address of the Airlock contract
|
|
95
94
|
*/
|
|
96
|
-
constructor(address
|
|
97
|
-
if (
|
|
95
|
+
constructor(address protocolRewardRecipient_, address protocolRewards_, IPoolManager poolManager_, address airlock_) initializer {
|
|
96
|
+
if (protocolRewardRecipient_ == address(0)) {
|
|
98
97
|
revert AddressZero();
|
|
99
98
|
}
|
|
100
|
-
if (
|
|
99
|
+
if (protocolRewards_ == address(0)) {
|
|
101
100
|
revert AddressZero();
|
|
102
101
|
}
|
|
103
102
|
if (address(poolManager_) == address(0)) {
|
|
104
103
|
revert AddressZero();
|
|
105
104
|
}
|
|
106
|
-
if (
|
|
105
|
+
if (airlock_ == address(0)) {
|
|
107
106
|
revert AddressZero();
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
protocolRewardRecipient =
|
|
111
|
-
protocolRewards =
|
|
109
|
+
protocolRewardRecipient = protocolRewardRecipient_;
|
|
110
|
+
protocolRewards = protocolRewards_;
|
|
112
111
|
poolManager = poolManager_;
|
|
113
|
-
airlock =
|
|
112
|
+
airlock = airlock_;
|
|
114
113
|
}
|
|
115
114
|
|
|
116
115
|
/// @inheritdoc ICoin
|
|
@@ -167,7 +166,6 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
167
166
|
__ERC20Permit_init("");
|
|
168
167
|
|
|
169
168
|
__MultiOwnable_init(owners_);
|
|
170
|
-
__ReentrancyGuard_init();
|
|
171
169
|
|
|
172
170
|
// Set mutable state
|
|
173
171
|
_setPayoutRecipient(payoutRecipient_);
|
|
@@ -180,14 +178,9 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
180
178
|
_handleInitialDistribution();
|
|
181
179
|
}
|
|
182
180
|
|
|
183
|
-
/// @
|
|
184
|
-
function
|
|
185
|
-
|
|
186
|
-
_mint(address(this), CoinConstants.MAX_TOTAL_SUPPLY);
|
|
187
|
-
|
|
188
|
-
// Distribute the creator launch reward to the payout recipient
|
|
189
|
-
_transfer(address(this), payoutRecipient, CoinConstants.CREATOR_LAUNCH_REWARD);
|
|
190
|
-
}
|
|
181
|
+
/// @notice The initial mint and distribution of the coin supply.
|
|
182
|
+
/// @dev This function must be overridden by the child contract.
|
|
183
|
+
function _handleInitialDistribution() internal virtual;
|
|
191
184
|
|
|
192
185
|
/// @notice Returns the name of the token for EIP712 domain.
|
|
193
186
|
/// @notice This can change when the user changes the "name" of the token.
|
|
@@ -258,7 +251,9 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
258
251
|
interfaceId == type(IERC7572).interfaceId ||
|
|
259
252
|
interfaceId == type(IHasRewardsRecipients).interfaceId ||
|
|
260
253
|
interfaceId == type(IHasPoolKey).interfaceId ||
|
|
261
|
-
type(
|
|
254
|
+
interfaceId == type(IHasCoinType).interfaceId ||
|
|
255
|
+
interfaceId == type(IHasTotalSupplyForPositions).interfaceId ||
|
|
256
|
+
interfaceId == type(IHasSwapPath).interfaceId;
|
|
262
257
|
}
|
|
263
258
|
|
|
264
259
|
/// @dev Overrides ERC20's _update function to emit a superset `CoinTransfer` event
|
package/src/ContentCoin.sol
CHANGED
|
@@ -10,10 +10,11 @@ pragma solidity ^0.8.23;
|
|
|
10
10
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
11
11
|
import {BaseCoin} from "./BaseCoin.sol";
|
|
12
12
|
import {CoinConstants} from "./libs/CoinConstants.sol";
|
|
13
|
+
import {IHasCoinType} from "./interfaces/ICoin.sol";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* @title ContentCoin
|
|
16
|
-
* @notice Content coin implementation that uses creator coins as backing currency
|
|
17
|
+
* @notice Content coin implementation that typically uses creator coins as backing currency, but can be set to any currency as the backing currency
|
|
17
18
|
* @dev Inherits from BaseCoin and implements content-specific distribution logic
|
|
18
19
|
*/
|
|
19
20
|
contract ContentCoin is BaseCoin {
|
|
@@ -37,9 +38,17 @@ contract ContentCoin is BaseCoin {
|
|
|
37
38
|
_mint(address(this), CoinConstants.MAX_TOTAL_SUPPLY);
|
|
38
39
|
|
|
39
40
|
// Distribute the creator launch reward to the payout recipient
|
|
40
|
-
_transfer(address(this), payoutRecipient, CoinConstants.
|
|
41
|
+
_transfer(address(this), payoutRecipient, CoinConstants.CONTENT_COIN_INITIAL_CREATOR_SUPPLY);
|
|
41
42
|
|
|
42
43
|
// Transfer the market supply to the hook for liquidity
|
|
43
44
|
_transfer(address(this), address(poolKey.hooks), balanceOf(address(this)));
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
function totalSupplyForPositions() external pure override returns (uint256) {
|
|
48
|
+
return CoinConstants.CONTENT_COIN_MARKET_SUPPLY;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function coinType() external pure override returns (IHasCoinType.CoinType) {
|
|
52
|
+
return IHasCoinType.CoinType.Content;
|
|
53
|
+
}
|
|
45
54
|
}
|
package/src/CreatorCoin.sol
CHANGED
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
pragma solidity ^0.8.28;
|
|
9
9
|
|
|
10
10
|
import {ICreatorCoin} from "./interfaces/ICreatorCoin.sol";
|
|
11
|
-
import {
|
|
11
|
+
import {CoinConstants} from "./libs/CoinConstants.sol";
|
|
12
12
|
import {IHooks, PoolConfiguration, PoolKey, ICoin} from "./interfaces/ICoin.sol";
|
|
13
13
|
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
14
14
|
import {BaseCoin} from "./BaseCoin.sol";
|
|
15
|
+
import {IHasCoinType} from "./interfaces/ICoin.sol";
|
|
15
16
|
|
|
16
17
|
contract CreatorCoin is ICreatorCoin, BaseCoin {
|
|
17
18
|
uint256 public vestingStartTime;
|
|
@@ -19,11 +20,19 @@ contract CreatorCoin is ICreatorCoin, BaseCoin {
|
|
|
19
20
|
uint256 public totalClaimed;
|
|
20
21
|
|
|
21
22
|
constructor(
|
|
22
|
-
address
|
|
23
|
-
address
|
|
24
|
-
IPoolManager
|
|
25
|
-
address
|
|
26
|
-
) BaseCoin(
|
|
23
|
+
address protocolRewardRecipient_,
|
|
24
|
+
address protocolRewards_,
|
|
25
|
+
IPoolManager poolManager_,
|
|
26
|
+
address airlock_
|
|
27
|
+
) BaseCoin(protocolRewardRecipient_, protocolRewards_, poolManager_, airlock_) initializer {}
|
|
28
|
+
|
|
29
|
+
function totalSupplyForPositions() external pure override returns (uint256) {
|
|
30
|
+
return CoinConstants.CREATOR_COIN_MARKET_SUPPLY;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function coinType() external pure override returns (IHasCoinType.CoinType) {
|
|
34
|
+
return IHasCoinType.CoinType.Creator;
|
|
35
|
+
}
|
|
27
36
|
|
|
28
37
|
function initialize(
|
|
29
38
|
address payoutRecipient_,
|
|
@@ -37,24 +46,34 @@ contract CreatorCoin is ICreatorCoin, BaseCoin {
|
|
|
37
46
|
uint160 sqrtPriceX96,
|
|
38
47
|
PoolConfiguration memory poolConfiguration_
|
|
39
48
|
) public override(BaseCoin, ICoin) {
|
|
40
|
-
require(currency_ ==
|
|
41
|
-
|
|
42
|
-
super.initialize(
|
|
49
|
+
require(currency_ == CoinConstants.CREATOR_COIN_CURRENCY, InvalidCurrency());
|
|
50
|
+
|
|
51
|
+
super.initialize({
|
|
52
|
+
payoutRecipient_: payoutRecipient_,
|
|
53
|
+
owners_: owners_,
|
|
54
|
+
tokenURI_: tokenURI_,
|
|
55
|
+
name_: name_,
|
|
56
|
+
symbol_: symbol_,
|
|
57
|
+
platformReferrer_: platformReferrer_,
|
|
58
|
+
currency_: currency_,
|
|
59
|
+
poolKey_: poolKey_,
|
|
60
|
+
sqrtPriceX96: sqrtPriceX96,
|
|
61
|
+
poolConfiguration_: poolConfiguration_
|
|
62
|
+
});
|
|
43
63
|
|
|
44
64
|
vestingStartTime = block.timestamp;
|
|
45
|
-
vestingEndTime = block.timestamp +
|
|
65
|
+
vestingEndTime = block.timestamp + CoinConstants.CREATOR_VESTING_DURATION;
|
|
46
66
|
}
|
|
47
67
|
|
|
48
68
|
/// @dev The initial mint and distribution of the coin supply.
|
|
49
69
|
/// Implements creator coin specific distribution: 500M to liquidity pool, 500M vested to creator.
|
|
50
70
|
function _handleInitialDistribution() internal override {
|
|
51
|
-
_mint(address(this),
|
|
71
|
+
_mint(address(this), CoinConstants.TOTAL_SUPPLY);
|
|
52
72
|
|
|
53
|
-
_transfer(address(this), address(poolKey.hooks),
|
|
73
|
+
_transfer(address(this), address(poolKey.hooks), CoinConstants.CREATOR_COIN_MARKET_SUPPLY);
|
|
54
74
|
}
|
|
55
75
|
|
|
56
76
|
/// @notice Allows the creator payout recipient to claim vested tokens
|
|
57
|
-
/// @dev Optimized for frequent calls from Uniswap V4 hooks
|
|
58
77
|
/// @return claimAmount The amount of tokens claimed
|
|
59
78
|
function claimVesting() external returns (uint256) {
|
|
60
79
|
uint256 claimAmount = getClaimableAmount();
|
|
@@ -93,13 +112,13 @@ contract CreatorCoin is ICreatorCoin, BaseCoin {
|
|
|
93
112
|
|
|
94
113
|
// After vesting ends - fully vested
|
|
95
114
|
if (timestamp >= vestingEndTime) {
|
|
96
|
-
return
|
|
115
|
+
return CoinConstants.CREATOR_COIN_CREATOR_VESTING_SUPPLY;
|
|
97
116
|
}
|
|
98
117
|
|
|
99
118
|
// Linear vesting: (elapsed_time / total_duration) * total_amount
|
|
100
119
|
uint256 elapsedTime = timestamp - vestingStartTime;
|
|
101
120
|
|
|
102
121
|
// Multiply first to avoid precision loss
|
|
103
|
-
return (
|
|
122
|
+
return (CoinConstants.CREATOR_COIN_CREATOR_VESTING_SUPPLY * elapsedTime) / CoinConstants.CREATOR_VESTING_DURATION;
|
|
104
123
|
}
|
|
105
124
|
}
|
package/src/ZoraFactoryImpl.sol
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
pragma solidity ^0.8.23;
|
|
9
9
|
|
|
10
10
|
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
|
11
|
+
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
|
|
11
12
|
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
|
|
12
13
|
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
|
|
13
14
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
@@ -33,8 +34,8 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
|
|
|
33
34
|
import {CoinSetup} from "./libs/CoinSetup.sol";
|
|
34
35
|
import {CoinDopplerMultiCurve} from "./libs/CoinDopplerMultiCurve.sol";
|
|
35
36
|
import {ICreatorCoin} from "./interfaces/ICreatorCoin.sol";
|
|
36
|
-
import {MarketConstants} from "./libs/MarketConstants.sol";
|
|
37
37
|
import {DeployedCoinVersionLookup} from "./utils/DeployedCoinVersionLookup.sol";
|
|
38
|
+
import {IZoraHookRegistry} from "./interfaces/IZoraHookRegistry.sol";
|
|
38
39
|
|
|
39
40
|
contract ZoraFactoryImpl is
|
|
40
41
|
IZoraFactory,
|
|
@@ -47,21 +48,25 @@ contract ZoraFactoryImpl is
|
|
|
47
48
|
{
|
|
48
49
|
using SafeERC20 for IERC20;
|
|
49
50
|
|
|
50
|
-
/// @notice The coin contract implementation address
|
|
51
|
+
/// @notice The ZORA coin contract implementation address
|
|
51
52
|
address public immutable coinV4Impl;
|
|
53
|
+
/// @notice The creator coin contract implementation address
|
|
52
54
|
address public immutable creatorCoinImpl;
|
|
53
|
-
|
|
54
|
-
address public immutable
|
|
55
|
+
/// @notice The uniswap v4 coin hook address
|
|
56
|
+
address public immutable hook;
|
|
57
|
+
/// @notice The zora hook registry address
|
|
58
|
+
address public immutable zoraHookRegistry;
|
|
55
59
|
|
|
56
|
-
constructor(address
|
|
60
|
+
constructor(address coinV4Impl_, address creatorCoinImpl_, address hook_, address zoraHookRegistry_) {
|
|
57
61
|
_disableInitializers();
|
|
58
62
|
|
|
59
|
-
coinV4Impl =
|
|
60
|
-
creatorCoinImpl =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
coinV4Impl = coinV4Impl_;
|
|
64
|
+
creatorCoinImpl = creatorCoinImpl_;
|
|
65
|
+
hook = hook_;
|
|
66
|
+
zoraHookRegistry = zoraHookRegistry_;
|
|
63
67
|
}
|
|
64
68
|
|
|
69
|
+
/// @inheritdoc IZoraFactory
|
|
65
70
|
function deployCreatorCoin(
|
|
66
71
|
address payoutRecipient,
|
|
67
72
|
address[] memory owners,
|
|
@@ -73,39 +78,24 @@ contract ZoraFactoryImpl is
|
|
|
73
78
|
bytes32 coinSalt
|
|
74
79
|
) public nonReentrant returns (address) {
|
|
75
80
|
bytes32 salt = _buildSalt(msg.sender, name, symbol, poolConfig, platformReferrer, coinSalt);
|
|
81
|
+
return address(_createAndInitializeCreatorCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt));
|
|
82
|
+
}
|
|
76
83
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
ICreatorCoin(creatorCoin).initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolKey, sqrtPriceX96, poolConfiguration);
|
|
93
|
-
|
|
94
|
-
emit CreatorCoinCreated(
|
|
95
|
-
msg.sender,
|
|
96
|
-
payoutRecipient,
|
|
97
|
-
platformReferrer,
|
|
98
|
-
currency,
|
|
99
|
-
uri,
|
|
100
|
-
name,
|
|
101
|
-
symbol,
|
|
102
|
-
address(creatorCoin),
|
|
103
|
-
poolKey,
|
|
104
|
-
CoinCommon.hashPoolKey(poolKey),
|
|
105
|
-
IVersionedContract(address(creatorCoin)).contractVersion()
|
|
106
|
-
);
|
|
107
|
-
|
|
108
|
-
return creatorCoin;
|
|
84
|
+
/// @inheritdoc IZoraFactory
|
|
85
|
+
function deployCreatorCoin(
|
|
86
|
+
address payoutRecipient,
|
|
87
|
+
address[] memory owners,
|
|
88
|
+
string memory uri,
|
|
89
|
+
string memory name,
|
|
90
|
+
string memory symbol,
|
|
91
|
+
bytes memory poolConfig,
|
|
92
|
+
address platformReferrer,
|
|
93
|
+
address postDeployHook,
|
|
94
|
+
bytes calldata postDeployHookData,
|
|
95
|
+
bytes32 coinSalt
|
|
96
|
+
) external payable nonReentrant returns (address coin, bytes memory postDeployHookDataOut) {
|
|
97
|
+
bytes32 salt = _buildSalt(msg.sender, name, symbol, poolConfig, platformReferrer, coinSalt);
|
|
98
|
+
return _deployCreatorCoinWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, postDeployHook, postDeployHookData, salt);
|
|
109
99
|
}
|
|
110
100
|
|
|
111
101
|
/// @inheritdoc IZoraFactory
|
|
@@ -125,6 +115,7 @@ contract ZoraFactoryImpl is
|
|
|
125
115
|
return _deployWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, postDeployHook, postDeployHookData, salt);
|
|
126
116
|
}
|
|
127
117
|
|
|
118
|
+
/// @inheritdoc IZoraFactory
|
|
128
119
|
function coinAddress(
|
|
129
120
|
address msgSender,
|
|
130
121
|
string memory name,
|
|
@@ -137,6 +128,19 @@ contract ZoraFactoryImpl is
|
|
|
137
128
|
return Clones.predictDeterministicAddress(getCoinImpl(CoinConfigurationVersions.getVersion(poolConfig)), salt, address(this));
|
|
138
129
|
}
|
|
139
130
|
|
|
131
|
+
function _executePostDeployHook(address coin, address deployHook, bytes calldata hookData) internal returns (bytes memory hookDataOut) {
|
|
132
|
+
if (deployHook != address(0)) {
|
|
133
|
+
if (!IERC165(deployHook).supportsInterface(type(IHasAfterCoinDeploy).interfaceId)) {
|
|
134
|
+
revert InvalidHook();
|
|
135
|
+
}
|
|
136
|
+
hookDataOut = IHasAfterCoinDeploy(deployHook).afterCoinDeploy{value: msg.value}(msg.sender, ICoin(coin), hookData);
|
|
137
|
+
} else if (msg.value > 0) {
|
|
138
|
+
// cannot send eth without a hook
|
|
139
|
+
revert EthTransferInvalid();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// @dev Internal function to deploy a coin with a hook
|
|
140
144
|
function _deployWithHook(
|
|
141
145
|
address payoutRecipient,
|
|
142
146
|
address[] memory owners,
|
|
@@ -145,24 +149,34 @@ contract ZoraFactoryImpl is
|
|
|
145
149
|
string memory symbol,
|
|
146
150
|
bytes memory poolConfig,
|
|
147
151
|
address platformReferrer,
|
|
148
|
-
address
|
|
152
|
+
address deployHook,
|
|
149
153
|
bytes calldata hookData,
|
|
150
154
|
bytes32 salt
|
|
151
155
|
) internal returns (address coin, bytes memory hookDataOut) {
|
|
152
156
|
coin = address(_createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt));
|
|
157
|
+
hookDataOut = _executePostDeployHook(coin, deployHook, hookData);
|
|
158
|
+
}
|
|
153
159
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
/// @dev Internal function to deploy a creator coin with a hook
|
|
161
|
+
function _deployCreatorCoinWithHook(
|
|
162
|
+
address payoutRecipient,
|
|
163
|
+
address[] memory owners,
|
|
164
|
+
string memory uri,
|
|
165
|
+
string memory name,
|
|
166
|
+
string memory symbol,
|
|
167
|
+
bytes memory poolConfig,
|
|
168
|
+
address platformReferrer,
|
|
169
|
+
address deployHook,
|
|
170
|
+
bytes calldata hookData,
|
|
171
|
+
bytes32 salt
|
|
172
|
+
) internal returns (address coin, bytes memory hookDataOut) {
|
|
173
|
+
coin = address(_createAndInitializeCreatorCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt));
|
|
174
|
+
hookDataOut = _executePostDeployHook(coin, deployHook, hookData);
|
|
163
175
|
}
|
|
164
176
|
|
|
165
|
-
/**
|
|
177
|
+
/**
|
|
178
|
+
* Deprecated deploy functions
|
|
179
|
+
*/
|
|
166
180
|
|
|
167
181
|
/// @dev Deprecated: use `deploy` instead that has a salt and hook specified
|
|
168
182
|
function deploy(
|
|
@@ -193,11 +207,11 @@ contract ZoraFactoryImpl is
|
|
|
193
207
|
string memory symbol,
|
|
194
208
|
bytes memory poolConfig,
|
|
195
209
|
address platformReferrer,
|
|
196
|
-
address
|
|
210
|
+
address deployHook,
|
|
197
211
|
bytes calldata hookData
|
|
198
212
|
) public payable nonReentrant returns (address coin, bytes memory hookDataOut) {
|
|
199
213
|
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
200
|
-
return _deployWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer,
|
|
214
|
+
return _deployWithHook(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, deployHook, hookData, salt);
|
|
201
215
|
}
|
|
202
216
|
|
|
203
217
|
/// @dev deprecated Use deploy() with poolConfig instead
|
|
@@ -210,8 +224,9 @@ contract ZoraFactoryImpl is
|
|
|
210
224
|
address platformReferrer,
|
|
211
225
|
address currency,
|
|
212
226
|
// tickLower is no longer used
|
|
213
|
-
int24 /*tickLower*/,
|
|
214
|
-
|
|
227
|
+
int24 /* tickLower */,
|
|
228
|
+
// orderSize is no longer used
|
|
229
|
+
uint256 /* orderSize */
|
|
215
230
|
) public payable nonReentrant returns (address, uint256) {
|
|
216
231
|
bytes memory poolConfig = CoinConfigurationVersions.defaultConfig(currency);
|
|
217
232
|
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
@@ -221,6 +236,10 @@ contract ZoraFactoryImpl is
|
|
|
221
236
|
return (address(coin), 0);
|
|
222
237
|
}
|
|
223
238
|
|
|
239
|
+
/**
|
|
240
|
+
* End Deprecated deploy functions
|
|
241
|
+
*/
|
|
242
|
+
|
|
224
243
|
function getCoinImpl(uint8 version) internal view returns (address) {
|
|
225
244
|
if (CoinConfigurationVersions.isV4(version)) {
|
|
226
245
|
return coinV4Impl;
|
|
@@ -229,29 +248,55 @@ contract ZoraFactoryImpl is
|
|
|
229
248
|
revert ICoin.InvalidPoolVersion();
|
|
230
249
|
}
|
|
231
250
|
|
|
232
|
-
function
|
|
233
|
-
|
|
251
|
+
function _createCoinWithPoolConfig(
|
|
252
|
+
address _implementation,
|
|
253
|
+
bytes memory poolConfig,
|
|
254
|
+
bytes32 coinSalt,
|
|
255
|
+
address payoutRecipient,
|
|
256
|
+
address[] memory owners,
|
|
257
|
+
string memory uri,
|
|
258
|
+
string memory name,
|
|
259
|
+
string memory symbol,
|
|
260
|
+
address platformReferrer
|
|
261
|
+
) internal returns (address coin, uint8 version, PoolKey memory poolKey, address currency) {
|
|
262
|
+
version = CoinConfigurationVersions.getVersion(poolConfig);
|
|
263
|
+
coin = Clones.cloneDeterministic(_implementation, coinSalt);
|
|
264
|
+
_setVersionForDeployedCoin(coin, version);
|
|
265
|
+
|
|
266
|
+
uint160 sqrtPriceX96;
|
|
267
|
+
bool isCoinToken0;
|
|
268
|
+
PoolConfiguration memory poolConfiguration;
|
|
269
|
+
(, currency, sqrtPriceX96, isCoinToken0, poolConfiguration) = CoinSetup.generatePoolConfig(coin, poolConfig);
|
|
270
|
+
|
|
271
|
+
poolKey = CoinSetup.buildPoolKey(coin, currency, isCoinToken0, IHooks(hook));
|
|
272
|
+
ICoin(coin).initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolKey, sqrtPriceX96, poolConfiguration);
|
|
234
273
|
}
|
|
235
274
|
|
|
236
|
-
function
|
|
237
|
-
ICoin coin,
|
|
238
|
-
address currency,
|
|
239
|
-
bool isCoinToken0,
|
|
240
|
-
uint160 sqrtPriceX96,
|
|
241
|
-
PoolConfiguration memory poolConfiguration,
|
|
275
|
+
function _createAndInitializeCreatorCoin(
|
|
242
276
|
address payoutRecipient,
|
|
243
277
|
address[] memory owners,
|
|
244
278
|
string memory uri,
|
|
245
279
|
string memory name,
|
|
246
280
|
string memory symbol,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
281
|
+
bytes memory poolConfig,
|
|
282
|
+
address platformReferrer,
|
|
283
|
+
bytes32 coinSalt
|
|
284
|
+
) internal returns (ICreatorCoin) {
|
|
285
|
+
(address creatorCoin, uint8 version, PoolKey memory poolKey, address currency) = _createCoinWithPoolConfig(
|
|
286
|
+
creatorCoinImpl,
|
|
287
|
+
poolConfig,
|
|
288
|
+
coinSalt,
|
|
289
|
+
payoutRecipient,
|
|
290
|
+
owners,
|
|
291
|
+
uri,
|
|
292
|
+
name,
|
|
293
|
+
symbol,
|
|
294
|
+
platformReferrer
|
|
295
|
+
);
|
|
250
296
|
|
|
251
|
-
|
|
252
|
-
coin.initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolKey, sqrtPriceX96, poolConfiguration);
|
|
297
|
+
require(version == CoinConfigurationVersions.DOPPLER_MULTICURVE_UNI_V4_POOL_VERSION, InvalidConfig());
|
|
253
298
|
|
|
254
|
-
emit
|
|
299
|
+
emit CreatorCoinCreated(
|
|
255
300
|
msg.sender,
|
|
256
301
|
payoutRecipient,
|
|
257
302
|
platformReferrer,
|
|
@@ -259,11 +304,13 @@ contract ZoraFactoryImpl is
|
|
|
259
304
|
uri,
|
|
260
305
|
name,
|
|
261
306
|
symbol,
|
|
262
|
-
|
|
307
|
+
creatorCoin,
|
|
263
308
|
poolKey,
|
|
264
309
|
CoinCommon.hashPoolKey(poolKey),
|
|
265
|
-
IVersionedContract(
|
|
310
|
+
IVersionedContract(creatorCoin).contractVersion()
|
|
266
311
|
);
|
|
312
|
+
|
|
313
|
+
return ICreatorCoin(creatorCoin);
|
|
267
314
|
}
|
|
268
315
|
|
|
269
316
|
function _createAndInitializeCoin(
|
|
@@ -276,26 +323,34 @@ contract ZoraFactoryImpl is
|
|
|
276
323
|
address platformReferrer,
|
|
277
324
|
bytes32 coinSalt
|
|
278
325
|
) internal returns (ICoin) {
|
|
279
|
-
uint8 version =
|
|
280
|
-
|
|
281
|
-
|
|
326
|
+
(address coin, uint8 version, PoolKey memory poolKey, address currency) = _createCoinWithPoolConfig(
|
|
327
|
+
coinV4Impl,
|
|
328
|
+
poolConfig,
|
|
329
|
+
coinSalt,
|
|
330
|
+
payoutRecipient,
|
|
331
|
+
owners,
|
|
332
|
+
uri,
|
|
333
|
+
name,
|
|
334
|
+
symbol,
|
|
335
|
+
platformReferrer
|
|
336
|
+
);
|
|
282
337
|
|
|
283
|
-
|
|
338
|
+
require(version == CoinConfigurationVersions.DOPPLER_MULTICURVE_UNI_V4_POOL_VERSION, ICoin.InvalidPoolVersion());
|
|
284
339
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
340
|
+
emit CoinCreatedV4(
|
|
341
|
+
msg.sender,
|
|
342
|
+
payoutRecipient,
|
|
343
|
+
platformReferrer,
|
|
344
|
+
currency,
|
|
345
|
+
uri,
|
|
346
|
+
name,
|
|
347
|
+
symbol,
|
|
348
|
+
coin,
|
|
349
|
+
poolKey,
|
|
350
|
+
CoinCommon.hashPoolKey(poolKey),
|
|
351
|
+
IVersionedContract(coin).contractVersion()
|
|
288
352
|
);
|
|
289
353
|
|
|
290
|
-
if (CoinConfigurationVersions.isV3(version)) {
|
|
291
|
-
// V3 is no longer supported
|
|
292
|
-
revert ICoin.InvalidPoolVersion();
|
|
293
|
-
} else if (CoinConfigurationVersions.isV4(version)) {
|
|
294
|
-
_setupV4Coin(ICoin(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
|
|
295
|
-
} else {
|
|
296
|
-
revert ICoin.InvalidPoolVersion();
|
|
297
|
-
}
|
|
298
|
-
|
|
299
354
|
return ICoin(coin);
|
|
300
355
|
}
|
|
301
356
|
|
|
@@ -310,7 +365,6 @@ contract ZoraFactoryImpl is
|
|
|
310
365
|
return keccak256(abi.encodePacked(msgSender, name, symbol, poolConfig, platformReferrer, coinSalt));
|
|
311
366
|
}
|
|
312
367
|
|
|
313
|
-
/// @dev Generates a unique salt for deterministic deployment
|
|
314
368
|
function _randomSalt(address payoutRecipient, string memory uri, bytes32 coinSalt) internal view returns (bytes32) {
|
|
315
369
|
return
|
|
316
370
|
keccak256(
|
|
@@ -354,13 +408,30 @@ contract ZoraFactoryImpl is
|
|
|
354
408
|
// try to get the existing contract name - if it reverts, the existing contract was an older version that didn't have the contract name
|
|
355
409
|
// unfortunately we cannot use supportsInterface here because the existing implementation did not have that function
|
|
356
410
|
try IHasContractName(newImpl).contractName() returns (string memory name) {
|
|
357
|
-
if (!
|
|
411
|
+
if (!Strings.equal(name, contractName())) {
|
|
358
412
|
revert UpgradeToMismatchedContractName(contractName(), name);
|
|
359
413
|
}
|
|
360
414
|
} catch {}
|
|
415
|
+
|
|
416
|
+
// Auto-register the new hooks in the Zora hook registry
|
|
417
|
+
address[] memory hooks = new address[](1);
|
|
418
|
+
string[] memory tags = new string[](1);
|
|
419
|
+
|
|
420
|
+
hooks[0] = IZoraFactory(newImpl).hook();
|
|
421
|
+
tags[0] = "CoinHook";
|
|
422
|
+
|
|
423
|
+
IZoraHookRegistry(zoraHookRegistry).registerHooks(hooks, tags);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/// @notice The address of the latest creator coin hook
|
|
427
|
+
/// @dev Deprecated: use `hook` instead
|
|
428
|
+
function creatorCoinHook() external view returns (address) {
|
|
429
|
+
return hook;
|
|
361
430
|
}
|
|
362
431
|
|
|
363
|
-
|
|
364
|
-
|
|
432
|
+
/// @notice The address of the latest coin hook
|
|
433
|
+
/// @dev Deprecated: use `hook` instead
|
|
434
|
+
function contentCoinHook() external view returns (address) {
|
|
435
|
+
return hook;
|
|
365
436
|
}
|
|
366
437
|
}
|