@zoralabs/coins 1.1.2 → 2.1.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 +107 -110
- package/CHANGELOG.md +50 -0
- package/README.md +48 -1
- package/abis/BaseCoin.json +442 -0
- package/abis/BaseZoraV4CoinHook.json +6 -2
- package/abis/CoinTest.json +3 -246
- package/abis/CoinUniV4Test.json +20 -0
- package/abis/ContentCoinHook.json +6 -2
- package/abis/CreatorCoinHook.json +6 -2
- package/abis/FactoryTest.json +8 -133
- package/abis/FeeEstimatorHook.json +6 -2
- package/abis/HooksTest.json +0 -26
- package/abis/ICoin.json +378 -0
- package/abis/ICoinV3.json +378 -0
- package/abis/IZoraFactory.json +0 -18
- package/abis/IZoraV4CoinHook.json +2 -2
- package/abis/LiquidityMigrationTest.json +101 -0
- package/abis/MockBadFactory.json +15 -0
- package/abis/Ownable2StepUpgradeable.json +138 -0
- package/abis/ZoraFactoryImpl.json +38 -65
- package/addresses/8453.json +5 -5
- package/dist/index.cjs +272 -268
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +270 -266
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +397 -470
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +275 -271
- package/package.json +3 -3
- package/script/DeployPostDeploymentHooks.s.sol +2 -2
- package/script/TestBackingCoinSwap.s.sol +9 -9
- package/script/TestV4Swap.s.sol +9 -9
- package/script/UpgradeFactoryImpl.s.sol +0 -1
- package/src/BaseCoin.sol +109 -6
- package/src/ContentCoin.sol +45 -0
- package/src/CreatorCoin.sol +7 -5
- package/src/ZoraFactoryImpl.sol +12 -95
- package/src/deployment/CoinsDeployerBase.sol +13 -30
- package/src/hooks/BaseZoraV4CoinHook.sol +8 -6
- package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
- package/src/interfaces/ICoin.sol +67 -1
- package/src/interfaces/ICreatorCoin.sol +2 -2
- package/src/interfaces/IZoraFactory.sol +0 -5
- package/src/interfaces/IZoraV4CoinHook.sol +1 -1
- package/src/libs/CoinConfigurationVersions.sol +1 -39
- package/src/libs/CoinRewardsV4.sol +2 -2
- package/src/libs/CoinSetup.sol +1 -4
- package/src/libs/UniV4SwapHelper.sol +1 -1
- package/src/libs/UniV4SwapToCurrency.sol +2 -2
- package/src/libs/V4Liquidity.sol +1 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +112 -535
- package/test/CoinUniV4.t.sol +66 -10
- package/test/DeploymentHooks.t.sol +5 -102
- package/test/Factory.t.sol +49 -291
- package/test/LiquidityMigration.t.sol +160 -2
- package/test/MultiOwnable.t.sol +36 -36
- package/test/Upgrades.t.sol +23 -42
- package/test/utils/BaseTest.sol +39 -84
- package/test/utils/FeeEstimatorHook.sol +3 -3
- package/wagmi.config.ts +2 -2
- package/abis/Coin.json +0 -1912
- package/abis/DopplerUniswapV3Test.json +0 -800
- package/abis/ICoinV4.json +0 -1048
- package/abis/Simulate.json +0 -29
- package/abis/UniV3BuySell.json +0 -12
- package/abis/UniV3Errors.json +0 -32
- package/script/Simulate.s.sol +0 -59
- package/src/Coin.sol +0 -236
- package/src/CoinV4.sol +0 -151
- package/src/interfaces/ICoinV4.sol +0 -74
- package/src/libs/CoinDopplerUniV3.sol +0 -50
- package/src/libs/CoinRewards.sol +0 -201
- package/src/libs/CoinSetupV3.sol +0 -50
- package/src/libs/UniV3BuySell.sol +0 -231
- package/src/libs/UniV3Errors.sol +0 -11
- package/test/CoinDopplerUniV3.t.sol +0 -310
- /package/abis/{CoinV4.json → ContentCoin.json} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoralabs/coins",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"tsx": "^3.13.0",
|
|
36
36
|
"typescript": "^5.2.2",
|
|
37
37
|
"viem": "^2.21.18",
|
|
38
|
-
"@zoralabs/
|
|
38
|
+
"@zoralabs/tsconfig": "^0.0.1",
|
|
39
39
|
"@zoralabs/shared-scripts": "^0.0.0",
|
|
40
|
-
"@zoralabs/
|
|
40
|
+
"@zoralabs/shared-contracts": "^0.0.5"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "pnpm run wagmi:generate && pnpm run copy-abis && pnpm run prettier:write && tsup",
|
|
@@ -10,9 +10,9 @@ contract DeployHooks is CoinsDeployerBase {
|
|
|
10
10
|
|
|
11
11
|
vm.startBroadcast();
|
|
12
12
|
|
|
13
|
-
address buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
|
|
13
|
+
// address buySupplyWithSwapRouterHook = address(deployBuySupplyWithSwapRouterHook(deployment));
|
|
14
14
|
|
|
15
|
-
deployment.buySupplyWithSwapRouterHook = buySupplyWithSwapRouterHook;
|
|
15
|
+
// deployment.buySupplyWithSwapRouterHook = buySupplyWithSwapRouterHook;
|
|
16
16
|
|
|
17
17
|
vm.stopBroadcast();
|
|
18
18
|
|
|
@@ -8,7 +8,7 @@ import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
|
|
|
8
8
|
import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
|
|
9
9
|
import {MarketConstants} from "../src/libs/MarketConstants.sol";
|
|
10
10
|
import {UniV4SwapHelper} from "../src/libs/UniV4SwapHelper.sol";
|
|
11
|
-
import {
|
|
11
|
+
import {ContentCoin} from "../src/ContentCoin.sol";
|
|
12
12
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
13
13
|
import {IUniversalRouter} from "@uniswap/universal-router/contracts/interfaces/IUniversalRouter.sol";
|
|
14
14
|
import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
|
|
@@ -16,7 +16,7 @@ import {MockERC20} from "../test/mocks/MockERC20.sol";
|
|
|
16
16
|
import {MarketConstants} from "../src/libs/MarketConstants.sol";
|
|
17
17
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
18
18
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
19
|
-
import {
|
|
19
|
+
import {ICoin} from "../src/interfaces/ICoin.sol";
|
|
20
20
|
|
|
21
21
|
import {console} from "forge-std/console.sol";
|
|
22
22
|
|
|
@@ -34,7 +34,7 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
34
34
|
string memory uri,
|
|
35
35
|
address createReferral,
|
|
36
36
|
bytes32 salt
|
|
37
|
-
) internal returns (
|
|
37
|
+
) internal returns (ICoin coin) {
|
|
38
38
|
CoinsDeployment memory deployment = readDeployment();
|
|
39
39
|
address[] memory owners = new address[](1);
|
|
40
40
|
owners[0] = creator;
|
|
@@ -54,10 +54,10 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
54
54
|
salt
|
|
55
55
|
);
|
|
56
56
|
|
|
57
|
-
coin =
|
|
57
|
+
coin = ICoin(coinAddress);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
function _swap(address currencyIn, uint128 amountIn,
|
|
60
|
+
function _swap(address currencyIn, uint128 amountIn, ICoin coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
|
|
61
61
|
uint128 minAmountOut = 0;
|
|
62
62
|
|
|
63
63
|
PoolKey memory poolKey = coin.getPoolKey();
|
|
@@ -106,8 +106,8 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
106
106
|
address createReferral = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
|
|
107
107
|
address tradeReferral = 0xC077e4cC02fa01A5b7fAca1acE9BBe9f5ac5Af9F;
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
ICoin backingCoin = _deployCoin(zora, trader, "Backing Coin", "BACK", "https://testc.com", createReferral, bytes32("creator"));
|
|
110
|
+
ICoin contentCoin = _deployCoin(
|
|
111
111
|
address(backingCoin),
|
|
112
112
|
trader,
|
|
113
113
|
"Content Coin",
|
|
@@ -116,8 +116,8 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
116
116
|
createReferral,
|
|
117
117
|
bytes32("content coin")
|
|
118
118
|
);
|
|
119
|
-
//
|
|
120
|
-
//
|
|
119
|
+
// ICoin backingCoin = ICoin(0xeA734b5997F35cD469921cCa7BB9A03C104f2f64);
|
|
120
|
+
// ICoin contentCoin = ICoin(0x72218BFEEc7D556BD3Dd8eFf2a317CEd49533769);
|
|
121
121
|
|
|
122
122
|
console.log("backingCoin", address(backingCoin));
|
|
123
123
|
console.log("contentCoin", address(contentCoin));
|
package/script/TestV4Swap.s.sol
CHANGED
|
@@ -8,7 +8,7 @@ import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
|
|
|
8
8
|
import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
|
|
9
9
|
import {MarketConstants} from "../src/libs/MarketConstants.sol";
|
|
10
10
|
import {UniV4SwapHelper} from "../src/libs/UniV4SwapHelper.sol";
|
|
11
|
-
import {
|
|
11
|
+
import {ContentCoin} from "../src/ContentCoin.sol";
|
|
12
12
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
13
13
|
import {IUniversalRouter} from "@uniswap/universal-router/contracts/interfaces/IUniversalRouter.sol";
|
|
14
14
|
import {IPermit2} from "permit2/src/interfaces/IPermit2.sol";
|
|
@@ -16,7 +16,7 @@ import {MockERC20} from "../test/mocks/MockERC20.sol";
|
|
|
16
16
|
import {MarketConstants} from "../src/libs/MarketConstants.sol";
|
|
17
17
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
18
18
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
19
|
-
import {
|
|
19
|
+
import {ICoin} from "../src/interfaces/ICoin.sol";
|
|
20
20
|
|
|
21
21
|
import {console} from "forge-std/console.sol";
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
31
31
|
currency.mint(getUniswapV4PoolManager(), 1000000 ether);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function _deployMockCoin(address currency, address creator, address createReferral, bytes32 salt) internal returns (
|
|
34
|
+
function _deployMockCoin(address currency, address creator, address createReferral, bytes32 salt) internal returns (ICoin coin) {
|
|
35
35
|
CoinsDeployment memory deployment = readDeployment();
|
|
36
36
|
address[] memory owners = new address[](1);
|
|
37
37
|
owners[0] = creator;
|
|
@@ -51,10 +51,10 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
51
51
|
salt
|
|
52
52
|
);
|
|
53
53
|
|
|
54
|
-
coin =
|
|
54
|
+
coin = ICoin(coinAddress);
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function _swap(address currencyIn, uint128 amountIn,
|
|
57
|
+
function _swap(address currencyIn, uint128 amountIn, ICoin coin, address trader, address tradeReferral) internal returns (uint256 amountOut) {
|
|
58
58
|
uint128 minAmountOut = 0;
|
|
59
59
|
|
|
60
60
|
PoolKey memory poolKey = coin.getPoolKey();
|
|
@@ -101,12 +101,12 @@ contract TestV4Swap is CoinsDeployerBase {
|
|
|
101
101
|
|
|
102
102
|
// MockERC20 currency = _deployMockCurrency();
|
|
103
103
|
|
|
104
|
-
//
|
|
105
|
-
//
|
|
104
|
+
// ICoin backingCoin = _deployMockCoin(address(currency), trader, createReferral, bytes32("backing coin"));
|
|
105
|
+
// ICoin contentCoin = _deployMockCoin(address(backingCoin), trader, createReferral, bytes32("content coin"));
|
|
106
106
|
|
|
107
107
|
MockERC20 currency = MockERC20(0x1b183Bd0E2c03Fc830F4d813bA37E82F9F97cA21);
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
ICoin backingCoin = ICoin(0x7D74416C4c295A592Fc6F9232911C945354b253C);
|
|
109
|
+
ICoin contentCoin = ICoin(0xf6d6660bcdA588F7f99e2961f279f500fB501730);
|
|
110
110
|
|
|
111
111
|
console.log("currency", address(currency));
|
|
112
112
|
console.log("backingCoin", address(backingCoin));
|
package/src/BaseCoin.sol
CHANGED
|
@@ -19,6 +19,15 @@ import {IAirlock} from "./interfaces/IAirlock.sol";
|
|
|
19
19
|
import {IProtocolRewards} from "./interfaces/IProtocolRewards.sol";
|
|
20
20
|
import {IWETH} from "./interfaces/IWETH.sol";
|
|
21
21
|
|
|
22
|
+
import {IPoolManager, PoolKey, Currency, IHooks} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
23
|
+
import {IHasPoolKey, IHasSwapPath} from "./interfaces/ICoin.sol";
|
|
24
|
+
import {PoolConfiguration} from "./types/PoolConfiguration.sol";
|
|
25
|
+
import {UniV4SwapToCurrency} from "./libs/UniV4SwapToCurrency.sol";
|
|
26
|
+
import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
|
|
27
|
+
import {IDeployedCoinVersionLookup} from "./interfaces/IDeployedCoinVersionLookup.sol";
|
|
28
|
+
import {IUpgradeableV4Hook} from "./interfaces/IUpgradeableV4Hook.sol";
|
|
29
|
+
import {CoinCommon} from "./libs/CoinCommon.sol";
|
|
30
|
+
|
|
22
31
|
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
|
|
23
32
|
import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
|
|
24
33
|
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
|
|
@@ -33,8 +42,6 @@ import {CoinConstants} from "./libs/CoinConstants.sol";
|
|
|
33
42
|
import {MarketConstants} from "./libs/MarketConstants.sol";
|
|
34
43
|
import {LpPosition} from "./types/LpPosition.sol";
|
|
35
44
|
import {PoolState} from "./types/PoolState.sol";
|
|
36
|
-
import {CoinSetupV3, UniV3Config, CoinV3Config} from "./libs/CoinSetupV3.sol";
|
|
37
|
-
import {UniV3BuySell, CoinConfig} from "./libs/UniV3BuySell.sol";
|
|
38
45
|
|
|
39
46
|
/*
|
|
40
47
|
$$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
|
|
@@ -56,6 +63,15 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
56
63
|
/// @notice The address of the Airlock contract, ownership is used for a protocol fee split.
|
|
57
64
|
address public immutable airlock;
|
|
58
65
|
|
|
66
|
+
/// @notice The Uniswap v4 pool manager singleton contract reference.
|
|
67
|
+
IPoolManager public immutable poolManager;
|
|
68
|
+
|
|
69
|
+
/// @notice The pool key for the coin. Type from Uniswap V4 core.
|
|
70
|
+
PoolKey internal poolKey;
|
|
71
|
+
|
|
72
|
+
/// @notice The configuration for the pool.
|
|
73
|
+
PoolConfiguration internal poolConfiguration;
|
|
74
|
+
|
|
59
75
|
/// @notice The metadata URI
|
|
60
76
|
string public tokenURI;
|
|
61
77
|
/// @notice The address of the coin creator
|
|
@@ -76,24 +92,53 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
76
92
|
* @param _protocolRewards The address of the protocol rewards contract
|
|
77
93
|
* @param _airlock The address of the Airlock contract
|
|
78
94
|
*/
|
|
79
|
-
constructor(address _protocolRewardRecipient, address _protocolRewards, address _airlock) initializer {
|
|
95
|
+
constructor(address _protocolRewardRecipient, address _protocolRewards, IPoolManager poolManager_, address _airlock) initializer {
|
|
80
96
|
if (_protocolRewardRecipient == address(0)) {
|
|
81
97
|
revert AddressZero();
|
|
82
98
|
}
|
|
83
99
|
if (_protocolRewards == address(0)) {
|
|
84
100
|
revert AddressZero();
|
|
85
101
|
}
|
|
86
|
-
|
|
102
|
+
if (address(poolManager_) == address(0)) {
|
|
103
|
+
revert AddressZero();
|
|
104
|
+
}
|
|
87
105
|
if (_airlock == address(0)) {
|
|
88
106
|
revert AddressZero();
|
|
89
107
|
}
|
|
90
108
|
|
|
91
109
|
protocolRewardRecipient = _protocolRewardRecipient;
|
|
92
110
|
protocolRewards = _protocolRewards;
|
|
111
|
+
poolManager = poolManager_;
|
|
93
112
|
airlock = _airlock;
|
|
94
113
|
}
|
|
95
114
|
|
|
96
|
-
/// @
|
|
115
|
+
/// @inheritdoc ICoin
|
|
116
|
+
function initialize(
|
|
117
|
+
address payoutRecipient_,
|
|
118
|
+
address[] memory owners_,
|
|
119
|
+
string memory tokenURI_,
|
|
120
|
+
string memory name_,
|
|
121
|
+
string memory symbol_,
|
|
122
|
+
address platformReferrer_,
|
|
123
|
+
address currency_,
|
|
124
|
+
PoolKey memory poolKey_,
|
|
125
|
+
uint160 sqrtPriceX96,
|
|
126
|
+
PoolConfiguration memory poolConfiguration_
|
|
127
|
+
) public virtual initializer {
|
|
128
|
+
currency = currency_;
|
|
129
|
+
// we need to set this before initialization, because
|
|
130
|
+
// distributing currency relies on the poolkey being set since the hooks
|
|
131
|
+
// are retrieved from there
|
|
132
|
+
poolKey = poolKey_;
|
|
133
|
+
poolConfiguration = poolConfiguration_;
|
|
134
|
+
|
|
135
|
+
_initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
|
|
136
|
+
|
|
137
|
+
// initialize the pool - the hook will mint its positions in the afterInitialize callback
|
|
138
|
+
poolManager.initialize(poolKey, sqrtPriceX96);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/// @notice Initializes a new coin (internal version)
|
|
97
142
|
/// @param payoutRecipient_ The address of the coin creator
|
|
98
143
|
/// @param tokenURI_ The metadata URI
|
|
99
144
|
/// @param name_ The coin name
|
|
@@ -210,7 +255,9 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
210
255
|
interfaceId == type(ICoin).interfaceId ||
|
|
211
256
|
interfaceId == type(ICoinComments).interfaceId ||
|
|
212
257
|
interfaceId == type(IERC7572).interfaceId ||
|
|
213
|
-
interfaceId == type(IHasRewardsRecipients).interfaceId
|
|
258
|
+
interfaceId == type(IHasRewardsRecipients).interfaceId ||
|
|
259
|
+
interfaceId == type(IHasPoolKey).interfaceId ||
|
|
260
|
+
type(IHasSwapPath).interfaceId == interfaceId;
|
|
214
261
|
}
|
|
215
262
|
|
|
216
263
|
/// @dev Overrides ERC20's _update function to emit a superset `CoinTransfer` event
|
|
@@ -245,4 +292,60 @@ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable
|
|
|
245
292
|
function dopplerFeeRecipient() public view returns (address) {
|
|
246
293
|
return IAirlock(airlock).owner();
|
|
247
294
|
}
|
|
295
|
+
|
|
296
|
+
/// @inheritdoc IHasPoolKey
|
|
297
|
+
function getPoolKey() public view returns (PoolKey memory) {
|
|
298
|
+
return poolKey;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// @inheritdoc ICoin
|
|
302
|
+
function getPoolConfiguration() public view returns (PoolConfiguration memory) {
|
|
303
|
+
return poolConfiguration;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/// @inheritdoc ICoin
|
|
307
|
+
function hooks() external view returns (IHooks) {
|
|
308
|
+
return poolKey.hooks;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// @notice Migrate liquidity from current hook to a new hook implementation
|
|
312
|
+
/// @param newHook Address of the new hook implementation
|
|
313
|
+
/// @param additionalData Additional data to pass to the new hook during initialization
|
|
314
|
+
function migrateLiquidity(address newHook, bytes calldata additionalData) external onlyOwner returns (PoolKey memory newPoolKey) {
|
|
315
|
+
newPoolKey = IUpgradeableV4Hook(address(poolKey.hooks)).migrateLiquidity(newHook, poolKey, additionalData);
|
|
316
|
+
|
|
317
|
+
emit LiquidityMigrated(poolKey, CoinCommon.hashPoolKey(poolKey), newPoolKey, CoinCommon.hashPoolKey(newPoolKey));
|
|
318
|
+
|
|
319
|
+
poolKey = newPoolKey;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/// @inheritdoc IHasSwapPath
|
|
323
|
+
function getPayoutSwapPath(IDeployedCoinVersionLookup coinVersionLookup) external view returns (IHasSwapPath.PayoutSwapPath memory payoutSwapPath) {
|
|
324
|
+
// if to swap in is this currency,
|
|
325
|
+
// if backing currency is a coin, then recursively get the path from the coin
|
|
326
|
+
payoutSwapPath.currencyIn = Currency.wrap(address(this));
|
|
327
|
+
|
|
328
|
+
// swap to backing currency
|
|
329
|
+
PathKey memory thisPathKey = PathKey({
|
|
330
|
+
intermediateCurrency: Currency.wrap(currency),
|
|
331
|
+
fee: poolKey.fee,
|
|
332
|
+
tickSpacing: poolKey.tickSpacing,
|
|
333
|
+
hooks: poolKey.hooks,
|
|
334
|
+
hookData: ""
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// get backing currency swap path - if the backing currency is a v4 coin and has a swap path.
|
|
338
|
+
PathKey[] memory subPath = UniV4SwapToCurrency.getSubSwapPath(currency, coinVersionLookup);
|
|
339
|
+
|
|
340
|
+
if (subPath.length > 0) {
|
|
341
|
+
payoutSwapPath.path = new PathKey[](1 + subPath.length);
|
|
342
|
+
payoutSwapPath.path[0] = thisPathKey;
|
|
343
|
+
for (uint256 i = 0; i < subPath.length; i++) {
|
|
344
|
+
payoutSwapPath.path[i + 1] = subPath[i];
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
payoutSwapPath.path = new PathKey[](1);
|
|
348
|
+
payoutSwapPath.path[0] = thisPathKey;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
248
351
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// SPDX-License-Identifier: ZORA-DELAYED-OSL-v1
|
|
2
|
+
// This software is licensed under the Zora Delayed Open Source License.
|
|
3
|
+
// Under this license, you may use, copy, modify, and distribute this software for
|
|
4
|
+
// non-commercial purposes only. Commercial use and competitive products are prohibited
|
|
5
|
+
// until the "Open Date" (3 years from first public distribution or earlier at Zora's discretion),
|
|
6
|
+
// at which point this software automatically becomes available under the MIT License.
|
|
7
|
+
// Full license terms available at: https://docs.zora.co/coins/license
|
|
8
|
+
pragma solidity ^0.8.23;
|
|
9
|
+
|
|
10
|
+
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
11
|
+
import {BaseCoin} from "./BaseCoin.sol";
|
|
12
|
+
import {CoinConstants} from "./libs/CoinConstants.sol";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @title ContentCoin
|
|
16
|
+
* @notice Content coin implementation that uses creator coins as backing currency
|
|
17
|
+
* @dev Inherits from BaseCoin and implements content-specific distribution logic
|
|
18
|
+
*/
|
|
19
|
+
contract ContentCoin is BaseCoin {
|
|
20
|
+
/// @notice The constructor for the static ContentCoin contract deployment shared across all content coins.
|
|
21
|
+
/// @dev All arguments are required and cannot be set to the 0 address.
|
|
22
|
+
/// @param protocolRewardRecipient_ The address of the protocol reward recipient
|
|
23
|
+
/// @param protocolRewards_ The address of the protocol rewards contract
|
|
24
|
+
/// @param poolManager_ The address of the pool manager
|
|
25
|
+
/// @param airlock_ The address of the Airlock contract, ownership is used for a protocol fee split.
|
|
26
|
+
constructor(
|
|
27
|
+
address protocolRewardRecipient_,
|
|
28
|
+
address protocolRewards_,
|
|
29
|
+
IPoolManager poolManager_,
|
|
30
|
+
address airlock_
|
|
31
|
+
) BaseCoin(protocolRewardRecipient_, protocolRewards_, poolManager_, airlock_) {}
|
|
32
|
+
|
|
33
|
+
/// @dev The initial mint and distribution of the coin supply.
|
|
34
|
+
/// Implements content coin specific distribution: 990M to liquidity pool, 10M to creator.
|
|
35
|
+
function _handleInitialDistribution() internal virtual override {
|
|
36
|
+
// Mint the total supply to the coin contract
|
|
37
|
+
_mint(address(this), CoinConstants.MAX_TOTAL_SUPPLY);
|
|
38
|
+
|
|
39
|
+
// Distribute the creator launch reward to the payout recipient
|
|
40
|
+
_transfer(address(this), payoutRecipient, CoinConstants.CREATOR_LAUNCH_REWARD);
|
|
41
|
+
|
|
42
|
+
// Transfer the market supply to the hook for liquidity
|
|
43
|
+
_transfer(address(this), address(poolKey.hooks), balanceOf(address(this)));
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/CreatorCoin.sol
CHANGED
|
@@ -9,9 +9,11 @@ pragma solidity ^0.8.28;
|
|
|
9
9
|
|
|
10
10
|
import {ICreatorCoin} from "./interfaces/ICreatorCoin.sol";
|
|
11
11
|
import {CreatorCoinConstants} from "./libs/CreatorCoinConstants.sol";
|
|
12
|
-
import {IHooks, PoolConfiguration, PoolKey,
|
|
12
|
+
import {IHooks, PoolConfiguration, PoolKey, ICoin} from "./interfaces/ICoin.sol";
|
|
13
|
+
import {IPoolManager} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
|
|
14
|
+
import {BaseCoin} from "./BaseCoin.sol";
|
|
13
15
|
|
|
14
|
-
contract CreatorCoin is ICreatorCoin,
|
|
16
|
+
contract CreatorCoin is ICreatorCoin, BaseCoin {
|
|
15
17
|
uint256 public vestingStartTime;
|
|
16
18
|
uint256 public vestingEndTime;
|
|
17
19
|
uint256 public totalClaimed;
|
|
@@ -21,7 +23,7 @@ contract CreatorCoin is ICreatorCoin, CoinV4 {
|
|
|
21
23
|
address _protocolRewards,
|
|
22
24
|
IPoolManager _poolManager,
|
|
23
25
|
address _airlock
|
|
24
|
-
)
|
|
26
|
+
) BaseCoin(_protocolRewardRecipient, _protocolRewards, _poolManager, _airlock) initializer {}
|
|
25
27
|
|
|
26
28
|
function initialize(
|
|
27
29
|
address payoutRecipient_,
|
|
@@ -34,7 +36,7 @@ contract CreatorCoin is ICreatorCoin, CoinV4 {
|
|
|
34
36
|
PoolKey memory poolKey_,
|
|
35
37
|
uint160 sqrtPriceX96,
|
|
36
38
|
PoolConfiguration memory poolConfiguration_
|
|
37
|
-
) public override(
|
|
39
|
+
) public override(BaseCoin, ICoin) {
|
|
38
40
|
require(currency_ == CreatorCoinConstants.CURRENCY, InvalidCurrency());
|
|
39
41
|
|
|
40
42
|
super.initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_, currency_, poolKey_, sqrtPriceX96, poolConfiguration_);
|
|
@@ -44,7 +46,7 @@ contract CreatorCoin is ICreatorCoin, CoinV4 {
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/// @dev The initial mint and distribution of the coin supply.
|
|
47
|
-
///
|
|
49
|
+
/// Implements creator coin specific distribution: 500M to liquidity pool, 500M vested to creator.
|
|
48
50
|
function _handleInitialDistribution() internal override {
|
|
49
51
|
_mint(address(this), CreatorCoinConstants.TOTAL_SUPPLY);
|
|
50
52
|
|
package/src/ZoraFactoryImpl.sol
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
pragma solidity ^0.8.23;
|
|
9
9
|
|
|
10
10
|
import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol";
|
|
11
|
-
import {
|
|
11
|
+
import {Ownable2StepUpgradeable} from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
|
|
12
12
|
import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
|
|
13
13
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
14
14
|
import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol";
|
|
@@ -20,18 +20,13 @@ import {IWETH} from "./interfaces/IWETH.sol";
|
|
|
20
20
|
import {IZoraFactory} from "./interfaces/IZoraFactory.sol";
|
|
21
21
|
import {IHasAfterCoinDeploy} from "./hooks/deployment/BaseCoinDeployHook.sol";
|
|
22
22
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
23
|
-
import {Coin} from "./Coin.sol";
|
|
24
|
-
import {CoinV4} from "./CoinV4.sol";
|
|
25
23
|
import {ICoin, PoolKeyStruct} from "./interfaces/ICoin.sol";
|
|
26
|
-
import {
|
|
27
|
-
import {ICoinV4} from "./interfaces/ICoinV4.sol";
|
|
24
|
+
import {ICoin} from "./interfaces/ICoin.sol";
|
|
28
25
|
import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
|
|
29
26
|
import {ContractVersionBase} from "./version/ContractVersionBase.sol";
|
|
30
27
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
31
28
|
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
32
29
|
import {CoinCommon} from "./libs/CoinCommon.sol";
|
|
33
|
-
import {UniV3Config} from "./libs/CoinSetupV3.sol";
|
|
34
|
-
import {CoinSetupV3} from "./libs/CoinSetupV3.sol";
|
|
35
30
|
import {PoolConfiguration} from "./types/PoolConfiguration.sol";
|
|
36
31
|
import {LpPosition} from "./types/LpPosition.sol";
|
|
37
32
|
import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersionedContract.sol";
|
|
@@ -45,7 +40,7 @@ contract ZoraFactoryImpl is
|
|
|
45
40
|
IZoraFactory,
|
|
46
41
|
UUPSUpgradeable,
|
|
47
42
|
ReentrancyGuardUpgradeable,
|
|
48
|
-
|
|
43
|
+
Ownable2StepUpgradeable,
|
|
49
44
|
IHasContractName,
|
|
50
45
|
ContractVersionBase,
|
|
51
46
|
DeployedCoinVersionLookup
|
|
@@ -53,16 +48,14 @@ contract ZoraFactoryImpl is
|
|
|
53
48
|
using SafeERC20 for IERC20;
|
|
54
49
|
|
|
55
50
|
/// @notice The coin contract implementation address
|
|
56
|
-
address public immutable coinImpl;
|
|
57
51
|
address public immutable coinV4Impl;
|
|
58
52
|
address public immutable creatorCoinImpl;
|
|
59
53
|
address public immutable contentCoinHook;
|
|
60
54
|
address public immutable creatorCoinHook;
|
|
61
55
|
|
|
62
|
-
constructor(address
|
|
56
|
+
constructor(address _coinV4Impl, address _creatorCoinImpl, address _contentCoinHook, address _creatorCoinHook) {
|
|
63
57
|
_disableInitializers();
|
|
64
58
|
|
|
65
|
-
coinImpl = _coinImpl;
|
|
66
59
|
coinV4Impl = _coinV4Impl;
|
|
67
60
|
creatorCoinImpl = _creatorCoinImpl;
|
|
68
61
|
contentCoinHook = _contentCoinHook;
|
|
@@ -180,13 +173,13 @@ contract ZoraFactoryImpl is
|
|
|
180
173
|
string memory symbol,
|
|
181
174
|
bytes memory poolConfig,
|
|
182
175
|
address platformReferrer,
|
|
183
|
-
uint256 orderSize
|
|
176
|
+
uint256 /*orderSize*/
|
|
184
177
|
) public payable nonReentrant returns (address, uint256) {
|
|
185
178
|
bytes32 salt = _randomSalt(payoutRecipient, uri, bytes32(0));
|
|
186
179
|
|
|
187
180
|
ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
|
|
188
181
|
|
|
189
|
-
uint256 coinsPurchased =
|
|
182
|
+
uint256 coinsPurchased = 0;
|
|
190
183
|
|
|
191
184
|
return (address(coin), coinsPurchased);
|
|
192
185
|
}
|
|
@@ -225,15 +218,11 @@ contract ZoraFactoryImpl is
|
|
|
225
218
|
|
|
226
219
|
ICoin coin = _createAndInitializeCoin(payoutRecipient, owners, uri, name, symbol, poolConfig, platformReferrer, salt);
|
|
227
220
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return (address(coin), coinsPurchased);
|
|
221
|
+
return (address(coin), 0);
|
|
231
222
|
}
|
|
232
223
|
|
|
233
224
|
function getCoinImpl(uint8 version) internal view returns (address) {
|
|
234
|
-
if (CoinConfigurationVersions.
|
|
235
|
-
return coinImpl;
|
|
236
|
-
} else if (CoinConfigurationVersions.isV4(version)) {
|
|
225
|
+
if (CoinConfigurationVersions.isV4(version)) {
|
|
237
226
|
return coinV4Impl;
|
|
238
227
|
}
|
|
239
228
|
|
|
@@ -244,44 +233,8 @@ contract ZoraFactoryImpl is
|
|
|
244
233
|
return payable(Clones.cloneDeterministic(getCoinImpl(version), salt));
|
|
245
234
|
}
|
|
246
235
|
|
|
247
|
-
function _setupV3Coin(
|
|
248
|
-
ICoinV3 coin,
|
|
249
|
-
address currency,
|
|
250
|
-
bool isCoinToken0,
|
|
251
|
-
uint160 sqrtPriceX96,
|
|
252
|
-
PoolConfiguration memory poolConfiguration,
|
|
253
|
-
address payoutRecipient,
|
|
254
|
-
address[] memory owners,
|
|
255
|
-
string memory uri,
|
|
256
|
-
string memory name,
|
|
257
|
-
string memory symbol,
|
|
258
|
-
address platformReferrer
|
|
259
|
-
) internal {
|
|
260
|
-
address v3Factory = coin.v3Factory();
|
|
261
|
-
|
|
262
|
-
address poolAddress = CoinSetupV3.createV3Pool(address(coin), currency, isCoinToken0, sqrtPriceX96, v3Factory);
|
|
263
|
-
|
|
264
|
-
LpPosition[] memory positions = CoinDopplerMultiCurve.calculatePositions(isCoinToken0, poolConfiguration, MarketConstants.POOL_LAUNCH_SUPPLY);
|
|
265
|
-
|
|
266
|
-
// Initialize coin with pre-configured pool
|
|
267
|
-
coin.initialize(payoutRecipient, owners, uri, name, symbol, platformReferrer, currency, poolAddress, poolConfiguration, positions);
|
|
268
|
-
|
|
269
|
-
emit CoinCreated(
|
|
270
|
-
msg.sender,
|
|
271
|
-
payoutRecipient,
|
|
272
|
-
platformReferrer,
|
|
273
|
-
currency,
|
|
274
|
-
uri,
|
|
275
|
-
name,
|
|
276
|
-
symbol,
|
|
277
|
-
address(coin),
|
|
278
|
-
poolAddress,
|
|
279
|
-
IVersionedContract(address(coin)).contractVersion()
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
236
|
function _setupV4Coin(
|
|
284
|
-
|
|
237
|
+
ICoin coin,
|
|
285
238
|
address currency,
|
|
286
239
|
bool isCoinToken0,
|
|
287
240
|
uint160 sqrtPriceX96,
|
|
@@ -335,9 +288,10 @@ contract ZoraFactoryImpl is
|
|
|
335
288
|
);
|
|
336
289
|
|
|
337
290
|
if (CoinConfigurationVersions.isV3(version)) {
|
|
338
|
-
|
|
291
|
+
// V3 is no longer supported
|
|
292
|
+
revert ICoin.InvalidPoolVersion();
|
|
339
293
|
} else if (CoinConfigurationVersions.isV4(version)) {
|
|
340
|
-
_setupV4Coin(
|
|
294
|
+
_setupV4Coin(ICoin(coin), currency, isCoinToken0, sqrtPriceX96, poolConfiguration, payoutRecipient, owners, uri, name, symbol, platformReferrer);
|
|
341
295
|
} else {
|
|
342
296
|
revert ICoin.InvalidPoolVersion();
|
|
343
297
|
}
|
|
@@ -375,43 +329,6 @@ contract ZoraFactoryImpl is
|
|
|
375
329
|
);
|
|
376
330
|
}
|
|
377
331
|
|
|
378
|
-
/// @dev Handles the first buy of a newly created coin
|
|
379
|
-
/// @param coin The newly created coin contract
|
|
380
|
-
/// @param orderSize The size of the first buy order; must match msg.value for ETH/WETH pairs
|
|
381
|
-
function _handleFirstOrder(ICoin coin, uint256 orderSize) internal returns (uint256 coinsPurchased) {
|
|
382
|
-
if (msg.value > 0 || orderSize > 0) {
|
|
383
|
-
address currency = coin.currency();
|
|
384
|
-
address payoutRecipient = coin.payoutRecipient();
|
|
385
|
-
|
|
386
|
-
if (currency != Coin(payable(address(coin))).WETH()) {
|
|
387
|
-
if (msg.value != 0) {
|
|
388
|
-
revert EthTransferInvalid();
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
_handleIncomingCurrency(currency, orderSize);
|
|
392
|
-
|
|
393
|
-
IERC20(currency).approve(address(coin), orderSize);
|
|
394
|
-
|
|
395
|
-
(, coinsPurchased) = Coin(payable(address(coin))).buy(payoutRecipient, orderSize, 0, 0, address(0));
|
|
396
|
-
} else {
|
|
397
|
-
(, coinsPurchased) = Coin(payable(address(coin))).buy{value: msg.value}(payoutRecipient, orderSize, 0, 0, address(0));
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/// @dev Safely transfers ERC20 tokens from the caller to this contract to be sent to the newly created coin
|
|
403
|
-
/// @param currency The ERC20 token address to transfer
|
|
404
|
-
/// @param orderSize The amount of tokens to transfer for the order
|
|
405
|
-
function _handleIncomingCurrency(address currency, uint256 orderSize) internal {
|
|
406
|
-
uint256 beforeBalance = IERC20(currency).balanceOf(address(this));
|
|
407
|
-
IERC20(currency).safeTransferFrom(msg.sender, address(this), orderSize);
|
|
408
|
-
uint256 afterBalance = IERC20(currency).balanceOf(address(this));
|
|
409
|
-
|
|
410
|
-
if ((afterBalance - beforeBalance) != orderSize) {
|
|
411
|
-
revert ERC20TransferAmountMismatch();
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
332
|
/// @notice Initializes the factory proxy contract
|
|
416
333
|
/// @param initialOwner Address of the contract owner
|
|
417
334
|
/// @dev Can only be called once due to initializer modifier
|