@zoralabs/coins 2.0.0 → 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 +106 -110
- package/CHANGELOG.md +28 -0
- package/README.md +30 -109
- package/abis/BaseCoin.json +442 -0
- package/abis/CoinTest.json +3 -246
- package/abis/FactoryTest.json +5 -137
- 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/LiquidityMigrationTest.json +101 -0
- package/abis/MockBadFactory.json +15 -0
- package/abis/ZoraFactoryImpl.json +1 -67
- package/dist/index.cjs +236 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +235 -264
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +389 -493
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +240 -269
- package/package.json +3 -3
- package/script/DeployPostDeploymentHooks.s.sol +2 -2
- package/script/TestBackingCoinSwap.s.sol +8 -8
- package/script/TestV4Swap.s.sol +8 -8
- package/script/UpgradeFactoryImpl.s.sol +0 -1
- package/src/BaseCoin.sol +109 -6
- package/src/ContentCoin.sol +4 -4
- package/src/CreatorCoin.sol +5 -5
- package/src/ZoraFactoryImpl.sol +10 -93
- package/src/deployment/CoinsDeployerBase.sol +10 -27
- package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
- 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/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 +5 -5
- package/test/DeploymentHooks.t.sol +5 -102
- package/test/Factory.t.sol +23 -306
- package/test/LiquidityMigration.t.sol +160 -2
- package/test/MultiOwnable.t.sol +36 -36
- package/test/Upgrades.t.sol +16 -35
- package/test/utils/BaseTest.sol +16 -69
- package/test/utils/FeeEstimatorHook.sol +3 -3
- package/wagmi.config.ts +1 -1
- package/abis/BaseCoinV4.json +0 -1840
- 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/BaseCoinV4.sol +0 -143
- package/src/Coin.sol +0 -236
- 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/test/CoinUniV4.t.sol
CHANGED
|
@@ -29,7 +29,7 @@ import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
|
29
29
|
import {PoolStateReader} from "../src/libs/PoolStateReader.sol";
|
|
30
30
|
import {CustomRevert} from "@uniswap/v4-core/src/libraries/CustomRevert.sol";
|
|
31
31
|
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
|
|
32
|
-
import {
|
|
32
|
+
import {ICoin, IHasSwapPath, PathKey} from "../src/interfaces/ICoin.sol";
|
|
33
33
|
import {IDeployedCoinVersionLookup} from "../src/interfaces/IDeployedCoinVersionLookup.sol";
|
|
34
34
|
|
|
35
35
|
contract CoinUniV4Test is BaseTest {
|
|
@@ -705,9 +705,9 @@ contract CoinUniV4Test is BaseTest {
|
|
|
705
705
|
|
|
706
706
|
function test_getSwapPath_whenBackingCurrencyProvidesPath() public {
|
|
707
707
|
address zora = address(mockERC20A);
|
|
708
|
-
|
|
708
|
+
ICoin backingCoin = _deployV4Coin(zora);
|
|
709
709
|
// now create a final coin paired with the backing coin
|
|
710
|
-
|
|
710
|
+
ICoin contentCoin = _deployV4Coin(address(backingCoin));
|
|
711
711
|
|
|
712
712
|
PathKey[] memory path = contentCoin.getPayoutSwapPath(IDeployedCoinVersionLookup(address(factory))).path;
|
|
713
713
|
|
|
@@ -746,9 +746,9 @@ contract CoinUniV4Test is BaseTest {
|
|
|
746
746
|
mockERC20A.mint(address(poolManager), 10000000000000000 ether);
|
|
747
747
|
|
|
748
748
|
// backing coin is a mock coin that is paired with zora
|
|
749
|
-
|
|
749
|
+
ICoin backingCoin = _deployV4Coin(zora);
|
|
750
750
|
// now create a final coin paired with the backing coin
|
|
751
|
-
|
|
751
|
+
ICoin contentCoin = _deployV4Coin(address(backingCoin));
|
|
752
752
|
|
|
753
753
|
vm.assume(amountIn > 0.000000000001 ether);
|
|
754
754
|
vm.assume(amountIn < 10000000000000000 ether);
|
|
@@ -5,7 +5,6 @@ import {BaseTest} from "./utils/BaseTest.sol";
|
|
|
5
5
|
import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
|
|
6
6
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
7
7
|
import {IUniswapV3Pool} from "../src/interfaces/IUniswapV3Pool.sol";
|
|
8
|
-
import {Coin} from "../src/Coin.sol";
|
|
9
8
|
import {CoinConfigurationVersions} from "../src/libs/CoinConfigurationVersions.sol";
|
|
10
9
|
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
|
|
11
10
|
import {ICoin} from "../src/interfaces/ICoin.sol";
|
|
@@ -13,6 +12,7 @@ import {IHasAfterCoinDeploy} from "../src/hooks/deployment/BaseCoinDeployHook.so
|
|
|
13
12
|
import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
|
|
14
13
|
import {ISwapRouter} from "../src/interfaces/ISwapRouter.sol";
|
|
15
14
|
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
15
|
+
import {ContentCoin} from "../src/ContentCoin.sol";
|
|
16
16
|
|
|
17
17
|
// Create a fake hook that doesn't support the IHasAfterCoinDeploy interface
|
|
18
18
|
contract FakeHookNoInterface {
|
|
@@ -26,15 +26,7 @@ contract HooksTest is BaseTest {
|
|
|
26
26
|
BuySupplyWithSwapRouterHook hook;
|
|
27
27
|
|
|
28
28
|
function _generateDefaultPoolConfig(address currency) internal pure returns (bytes memory) {
|
|
29
|
-
return
|
|
30
|
-
_generatePoolConfig(
|
|
31
|
-
CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
|
|
32
|
-
currency,
|
|
33
|
-
DEFAULT_DISCOVERY_TICK_LOWER,
|
|
34
|
-
DEFAULT_DISCOVERY_TICK_UPPER,
|
|
35
|
-
DEFAULT_NUM_DISCOVERY_POSITIONS,
|
|
36
|
-
DEFAULT_DISCOVERY_SUPPLY_SHARE
|
|
37
|
-
);
|
|
29
|
+
return _generatePoolConfig(currency);
|
|
38
30
|
}
|
|
39
31
|
|
|
40
32
|
function setUp() public override {
|
|
@@ -71,50 +63,6 @@ contract HooksTest is BaseTest {
|
|
|
71
63
|
return _encodeAfterCoinDeploy(buyRecipient, abi.encodeWithSelector(ISwapRouter.exactInput.selector, params));
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
function test_buySupplyWithEthUsingV3Hook_withExactInputSingle(uint256 initialOrderSize) public {
|
|
75
|
-
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
76
|
-
vm.assume(initialOrderSize < 1 ether);
|
|
77
|
-
|
|
78
|
-
vm.deal(users.creator, initialOrderSize);
|
|
79
|
-
|
|
80
|
-
bytes memory hookData = _encodeExactInputSingle(
|
|
81
|
-
users.creator,
|
|
82
|
-
ISwapRouter.ExactInputSingleParams({
|
|
83
|
-
tokenIn: address(weth),
|
|
84
|
-
tokenOut: zora,
|
|
85
|
-
fee: 3000,
|
|
86
|
-
recipient: address(hook),
|
|
87
|
-
amountIn: initialOrderSize,
|
|
88
|
-
amountOutMinimum: 0,
|
|
89
|
-
sqrtPriceLimitX96: 0
|
|
90
|
-
})
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
vm.prank(users.creator);
|
|
94
|
-
(address coinAddress, bytes memory hookDataOut) = factory.deployWithHook{value: initialOrderSize}(
|
|
95
|
-
users.creator,
|
|
96
|
-
_getDefaultOwners(),
|
|
97
|
-
"https://test.com",
|
|
98
|
-
"Testcoin",
|
|
99
|
-
"TEST",
|
|
100
|
-
_generateDefaultPoolConfig(zora),
|
|
101
|
-
users.platformReferrer,
|
|
102
|
-
address(hook),
|
|
103
|
-
hookData
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
coin = Coin(payable(coinAddress));
|
|
107
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
108
|
-
|
|
109
|
-
(uint256 amountCurrency, uint256 coinsPurchased) = abi.decode(hookDataOut, (uint256, uint256));
|
|
110
|
-
|
|
111
|
-
assertEq(coin.currency(), zora, "currency");
|
|
112
|
-
assertGt(amountCurrency, 0, "amountCurrency > 0");
|
|
113
|
-
assertGt(coinsPurchased, 0, "coinsPurchased > 0");
|
|
114
|
-
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
|
|
115
|
-
assertGt(IERC20(zora).balanceOf(address(pool)), 0, "Pool ZORA balance");
|
|
116
|
-
}
|
|
117
|
-
|
|
118
66
|
function test_buySupplyWithEthUsingV4Hook_withExactInputMultiHop(uint256 initialOrderSize) public {
|
|
119
67
|
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
120
68
|
vm.assume(initialOrderSize < 1 ether);
|
|
@@ -150,62 +98,17 @@ contract HooksTest is BaseTest {
|
|
|
150
98
|
hookData
|
|
151
99
|
);
|
|
152
100
|
|
|
153
|
-
|
|
101
|
+
coinV4 = ContentCoin(payable(coinAddress));
|
|
154
102
|
|
|
155
103
|
(uint256 amountCurrency, uint256 coinsPurchased) = abi.decode(hookDataOut, (uint256, uint256));
|
|
156
104
|
|
|
157
|
-
assertEq(
|
|
105
|
+
assertEq(coinV4.currency(), zora, "currency");
|
|
158
106
|
assertGt(amountCurrency, 0, "amountCurrency > 0");
|
|
159
107
|
assertGt(coinsPurchased, 0, "coinsPurchased > 0");
|
|
160
|
-
assertEq(
|
|
108
|
+
assertEq(coinV4.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
|
|
161
109
|
// assertGt(IERC20(zora).balanceOf(address(pool)), 0, "Pool ZORA balance");
|
|
162
110
|
}
|
|
163
111
|
|
|
164
|
-
function test_buySupplyWithEthUsingV3Hook_withExactInputMultiHop(uint256 initialOrderSize) public {
|
|
165
|
-
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
166
|
-
vm.assume(initialOrderSize < 1 ether);
|
|
167
|
-
|
|
168
|
-
vm.deal(users.creator, initialOrderSize);
|
|
169
|
-
|
|
170
|
-
// lets try weth to usdc to zora
|
|
171
|
-
|
|
172
|
-
uint24 poolFee = 3000;
|
|
173
|
-
|
|
174
|
-
bytes memory hookData = _encodeExactInput(
|
|
175
|
-
users.creator,
|
|
176
|
-
ISwapRouter.ExactInputParams({
|
|
177
|
-
path: abi.encodePacked(address(weth), poolFee, USDC_ADDRESS, poolFee, zora),
|
|
178
|
-
recipient: address(hook),
|
|
179
|
-
amountIn: initialOrderSize,
|
|
180
|
-
amountOutMinimum: 0
|
|
181
|
-
})
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
vm.prank(users.creator);
|
|
185
|
-
(address coinAddress, bytes memory hookDataOut) = factory.deployWithHook{value: initialOrderSize}(
|
|
186
|
-
users.creator,
|
|
187
|
-
_getDefaultOwners(),
|
|
188
|
-
"https://test.com",
|
|
189
|
-
"Testcoin",
|
|
190
|
-
"TEST",
|
|
191
|
-
_generateDefaultPoolConfig(zora),
|
|
192
|
-
users.platformReferrer,
|
|
193
|
-
address(hook),
|
|
194
|
-
hookData
|
|
195
|
-
);
|
|
196
|
-
|
|
197
|
-
coin = Coin(payable(coinAddress));
|
|
198
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
199
|
-
|
|
200
|
-
(uint256 amountCurrency, uint256 coinsPurchased) = abi.decode(hookDataOut, (uint256, uint256));
|
|
201
|
-
|
|
202
|
-
assertEq(coin.currency(), zora, "currency");
|
|
203
|
-
assertGt(amountCurrency, 0, "amountCurrency > 0");
|
|
204
|
-
assertGt(coinsPurchased, 0, "coinsPurchased > 0");
|
|
205
|
-
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased, "balanceOf creator");
|
|
206
|
-
assertGt(IERC20(zora).balanceOf(address(pool)), 0, "Pool ZORA balance");
|
|
207
|
-
}
|
|
208
|
-
|
|
209
112
|
function test_buySupplyWithEthUsingV3Hook_revertsWhenBadCall() public {
|
|
210
113
|
vm.deal(users.creator, 0.0001 ether);
|
|
211
114
|
|
package/test/Factory.t.sol
CHANGED
|
@@ -3,6 +3,8 @@ pragma solidity ^0.8.13;
|
|
|
3
3
|
|
|
4
4
|
import "./utils/BaseTest.sol";
|
|
5
5
|
import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
6
|
+
import {IHasContractName} from "@zoralabs/shared-contracts/interfaces/IContractMetadata.sol";
|
|
7
|
+
import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
|
|
6
8
|
|
|
7
9
|
contract FactoryTest is BaseTest {
|
|
8
10
|
function setUp() public override {
|
|
@@ -11,14 +13,7 @@ contract FactoryTest is BaseTest {
|
|
|
11
13
|
|
|
12
14
|
function test_factory_constructor_and_proxy_setup() public {
|
|
13
15
|
// Impl constructor test
|
|
14
|
-
ZoraFactoryImpl impl = new ZoraFactoryImpl(
|
|
15
|
-
address(coinV3Impl),
|
|
16
|
-
address(coinV4Impl),
|
|
17
|
-
address(creatorCoinImpl),
|
|
18
|
-
address(contentCoinHook),
|
|
19
|
-
address(creatorCoinHook)
|
|
20
|
-
);
|
|
21
|
-
assertEq(ZoraFactoryImpl(address(factory)).coinImpl(), address(coinV3Impl));
|
|
16
|
+
ZoraFactoryImpl impl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
|
|
22
17
|
assertEq(ZoraFactoryImpl(address(factory)).owner(), users.factoryOwner);
|
|
23
18
|
assertEq(ZoraFactoryImpl(address(factory)).coinV4Impl(), address(coinV4Impl));
|
|
24
19
|
|
|
@@ -44,7 +39,7 @@ contract FactoryTest is BaseTest {
|
|
|
44
39
|
assertEq(ZoraFactoryImpl(address(factory)).pendingOwner(), address(0));
|
|
45
40
|
|
|
46
41
|
address newFactoryImpl = address(
|
|
47
|
-
new ZoraFactoryImpl(address(
|
|
42
|
+
new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook))
|
|
48
43
|
);
|
|
49
44
|
|
|
50
45
|
// Upgrade to current / new impl
|
|
@@ -70,296 +65,8 @@ contract FactoryTest is BaseTest {
|
|
|
70
65
|
assertEq(ZoraFactoryImpl(address(factory)).owner(), newOwner);
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
function test_deploy_no_eth() public {
|
|
74
|
-
address[] memory owners = new address[](1);
|
|
75
|
-
owners[0] = users.creator;
|
|
76
|
-
|
|
77
|
-
(address coinAddress, ) = factory.deploy(
|
|
78
|
-
users.creator,
|
|
79
|
-
owners,
|
|
80
|
-
"https://test2.com",
|
|
81
|
-
"Test2 Token",
|
|
82
|
-
"TEST2",
|
|
83
|
-
_generatePoolConfig(address(weth)),
|
|
84
|
-
users.platformReferrer,
|
|
85
|
-
0
|
|
86
|
-
);
|
|
87
|
-
coin = Coin(payable(coinAddress));
|
|
88
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
89
|
-
vm.label(address(coin), "COIN");
|
|
90
|
-
vm.label(address(pool), "POOL");
|
|
91
|
-
|
|
92
|
-
uint160 sqrtPriceX96 = pool.slot0().sqrtPriceX96;
|
|
93
|
-
uint256 poolCoinBalance = coin.balanceOf(address(pool));
|
|
94
|
-
uint256 poolEthBalance = weth.balanceOf(address(pool));
|
|
95
|
-
|
|
96
|
-
console.log("POOL_TOKEN_0: ", pool.token0());
|
|
97
|
-
console.log("POOL_TOKEN_1: ", pool.token1());
|
|
98
|
-
console.log("POOL_SQRT_PRICE_X96: ", sqrtPriceX96);
|
|
99
|
-
console.log("");
|
|
100
|
-
console.log("POOL_COIN_BALANCE: ", poolCoinBalance);
|
|
101
|
-
console.log("POOL_ETH_BALANCE: ", poolEthBalance);
|
|
102
|
-
console.log("");
|
|
103
|
-
|
|
104
|
-
assertEq(coin.payoutRecipient(), users.creator, "payoutRecipient");
|
|
105
|
-
assertEq(coin.protocolRewardRecipient(), users.feeRecipient, "protocolRewardRecipient");
|
|
106
|
-
assertEq(coin.platformReferrer(), users.platformReferrer, "platformReferrer");
|
|
107
|
-
assertEq(coin.tokenURI(), "https://test2.com", "tokenURI");
|
|
108
|
-
assertEq(coin.name(), "Test2 Token", "name");
|
|
109
|
-
assertEq(coin.symbol(), "TEST2", "symbol");
|
|
110
|
-
assertEq(coin.currency(), address(weth), "currency");
|
|
111
|
-
assertEq(coin.totalSupply(), 1_000_000_000e18, "totalSupply");
|
|
112
|
-
assertEq(coin.balanceOf(users.creator), 10_000_000e18, "balanceOf creator");
|
|
113
|
-
assertGt(coin.balanceOf(coin.poolAddress()), 989_999_999e18, "balanceOf pool");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function test_deploy_with_eth(uint256 initialOrderSize) public {
|
|
117
|
-
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
118
|
-
vm.assume(initialOrderSize < 10 ether);
|
|
119
|
-
|
|
120
|
-
address[] memory owners = new address[](1);
|
|
121
|
-
owners[0] = users.creator;
|
|
122
|
-
|
|
123
|
-
vm.deal(users.creator, initialOrderSize);
|
|
124
|
-
vm.prank(users.creator);
|
|
125
|
-
(address coinAddress, ) = factory.deploy{value: initialOrderSize}(
|
|
126
|
-
users.creator,
|
|
127
|
-
owners,
|
|
128
|
-
"https://test2.com",
|
|
129
|
-
"Test2 Token",
|
|
130
|
-
"TEST2",
|
|
131
|
-
_generatePoolConfig(address(weth)),
|
|
132
|
-
users.platformReferrer,
|
|
133
|
-
initialOrderSize
|
|
134
|
-
);
|
|
135
|
-
coin = Coin(payable(coinAddress));
|
|
136
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
137
|
-
vm.label(address(coin), "COIN");
|
|
138
|
-
vm.label(address(pool), "POOL");
|
|
139
|
-
|
|
140
|
-
uint160 sqrtPriceX96 = pool.slot0().sqrtPriceX96;
|
|
141
|
-
uint256 poolCoinBalance = coin.balanceOf(address(pool));
|
|
142
|
-
uint256 poolEthBalance = weth.balanceOf(address(pool));
|
|
143
|
-
|
|
144
|
-
console.log("POOL_TOKEN_0: ", pool.token0());
|
|
145
|
-
console.log("POOL_TOKEN_1: ", pool.token1());
|
|
146
|
-
console.log("POOL_SQRT_PRICE_X96: ", sqrtPriceX96);
|
|
147
|
-
console.log("");
|
|
148
|
-
console.log("POOL_COIN_BALANCE: ", poolCoinBalance);
|
|
149
|
-
console.log("POOL_ETH_BALANCE: ", poolEthBalance);
|
|
150
|
-
console.log("");
|
|
151
|
-
console.log("BUYER_COIN_BALANCE ", coin.balanceOf(users.creator) - 10_000_000e18);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function test_deploy_with_weth(uint256 initialOrderSize) public {
|
|
155
|
-
vm.assume(initialOrderSize > CoinConstants.MIN_ORDER_SIZE);
|
|
156
|
-
vm.assume(initialOrderSize < 10 ether);
|
|
157
|
-
|
|
158
|
-
address[] memory owners = new address[](1);
|
|
159
|
-
owners[0] = users.creator;
|
|
160
|
-
|
|
161
|
-
vm.deal(users.creator, initialOrderSize);
|
|
162
|
-
|
|
163
|
-
vm.startPrank(users.creator);
|
|
164
|
-
weth.deposit{value: initialOrderSize}();
|
|
165
|
-
|
|
166
|
-
weth.approve(address(factory), type(uint256).max);
|
|
167
|
-
|
|
168
|
-
// Expect this to revert because WETH needs to be sent with msg.value.
|
|
169
|
-
vm.expectRevert();
|
|
170
|
-
factory.deploy(
|
|
171
|
-
users.creator,
|
|
172
|
-
owners,
|
|
173
|
-
"https://test2.com",
|
|
174
|
-
"Test2 Token",
|
|
175
|
-
"TEST2",
|
|
176
|
-
_generatePoolConfig(address(weth)),
|
|
177
|
-
users.platformReferrer,
|
|
178
|
-
initialOrderSize
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function test_deploy_with_one_eth() public {
|
|
183
|
-
address[] memory owners = new address[](1);
|
|
184
|
-
owners[0] = users.creator;
|
|
185
|
-
|
|
186
|
-
uint256 orderSize = 1 ether;
|
|
187
|
-
vm.deal(users.creator, orderSize);
|
|
188
|
-
|
|
189
|
-
(address coinAddress, ) = factory.deploy{value: orderSize}(
|
|
190
|
-
users.creator,
|
|
191
|
-
owners,
|
|
192
|
-
"https://test2.com",
|
|
193
|
-
"Test2 Token",
|
|
194
|
-
"TEST2",
|
|
195
|
-
_generatePoolConfig(address(weth)),
|
|
196
|
-
users.platformReferrer,
|
|
197
|
-
orderSize
|
|
198
|
-
);
|
|
199
|
-
coin = Coin(payable(coinAddress));
|
|
200
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
201
|
-
vm.label(address(coin), "COIN");
|
|
202
|
-
vm.label(address(pool), "POOL");
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function test_deploy_with_usdc() public {
|
|
206
|
-
address[] memory owners = new address[](1);
|
|
207
|
-
owners[0] = users.creator;
|
|
208
|
-
|
|
209
|
-
(address coinAddress, ) = factory.deploy(
|
|
210
|
-
users.creator,
|
|
211
|
-
owners,
|
|
212
|
-
"https://testcoinusdcpair.com",
|
|
213
|
-
"Testcoinusdcpair",
|
|
214
|
-
"TESTCOINUSDCPAIR",
|
|
215
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
216
|
-
users.platformReferrer,
|
|
217
|
-
0
|
|
218
|
-
);
|
|
219
|
-
coin = Coin(payable(coinAddress));
|
|
220
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
221
|
-
vm.label(address(coin), "COIN");
|
|
222
|
-
vm.label(address(pool), "POOL");
|
|
223
|
-
|
|
224
|
-
assertEq(coin.currency(), USDC_ADDRESS, "currency");
|
|
225
|
-
assertEq(coin.payoutRecipient(), users.creator, "payoutRecipient");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function test_deploy_with_usdc_order() public {
|
|
229
|
-
address[] memory owners = new address[](1);
|
|
230
|
-
owners[0] = users.creator;
|
|
231
|
-
|
|
232
|
-
uint256 orderSize = dealUSDC(users.creator, 100);
|
|
233
|
-
|
|
234
|
-
vm.prank(users.creator);
|
|
235
|
-
usdc.approve(address(factory), orderSize);
|
|
236
|
-
|
|
237
|
-
assertEq(usdc.balanceOf(users.creator), orderSize);
|
|
238
|
-
assertEq(usdc.allowance(users.creator, address(factory)), orderSize);
|
|
239
|
-
|
|
240
|
-
vm.prank(users.creator);
|
|
241
|
-
(address coinAddress, uint256 coinsPurchased) = factory.deploy(
|
|
242
|
-
users.creator,
|
|
243
|
-
owners,
|
|
244
|
-
"https://testcoinusdcpair.com",
|
|
245
|
-
"Testcoinusdcpair",
|
|
246
|
-
"TESTCOINUSDCPAIR",
|
|
247
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
248
|
-
users.platformReferrer,
|
|
249
|
-
orderSize
|
|
250
|
-
);
|
|
251
|
-
coin = Coin(payable(coinAddress));
|
|
252
|
-
pool = IUniswapV3Pool(coin.poolAddress());
|
|
253
|
-
vm.label(address(coin), "COIN");
|
|
254
|
-
vm.label(address(pool), "POOL");
|
|
255
|
-
|
|
256
|
-
assertEq(coin.currency(), USDC_ADDRESS, "currency");
|
|
257
|
-
assertEq(coin.balanceOf(users.creator), CoinConstants.CREATOR_LAUNCH_REWARD + coinsPurchased);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function test_deploy_with_usdc_revert_payout_recipient_zero() public {
|
|
261
|
-
address[] memory owners = new address[](1);
|
|
262
|
-
owners[0] = users.creator;
|
|
263
|
-
|
|
264
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
265
|
-
factory.deploy(
|
|
266
|
-
address(0),
|
|
267
|
-
owners,
|
|
268
|
-
"https://testcoinusdcpair.com",
|
|
269
|
-
"Testcoinusdcpair",
|
|
270
|
-
"TESTCOINUSDCPAIR",
|
|
271
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
272
|
-
users.platformReferrer,
|
|
273
|
-
0
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function test_deploy_with_usdc_revert_one_owner_required() public {
|
|
278
|
-
address[] memory owners = new address[](0);
|
|
279
|
-
|
|
280
|
-
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OneOwnerRequired.selector));
|
|
281
|
-
factory.deploy(
|
|
282
|
-
users.creator,
|
|
283
|
-
owners,
|
|
284
|
-
"https://testcoinusdcpair.com",
|
|
285
|
-
"Testcoinusdcpair",
|
|
286
|
-
"TESTCOINUSDCPAIR",
|
|
287
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
288
|
-
users.platformReferrer,
|
|
289
|
-
0
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
function test_deploy_with_usdc_platform_referrer_zero() public {
|
|
294
|
-
address[] memory owners = new address[](1);
|
|
295
|
-
owners[0] = users.creator;
|
|
296
|
-
|
|
297
|
-
(address coinAddress, ) = factory.deploy(
|
|
298
|
-
users.creator,
|
|
299
|
-
owners,
|
|
300
|
-
"https://testcoinusdcpair.com",
|
|
301
|
-
"Testcoinusdcpair",
|
|
302
|
-
"TESTCOINUSDCPAIR",
|
|
303
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
304
|
-
address(0),
|
|
305
|
-
0
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
coin = Coin(payable(coinAddress));
|
|
309
|
-
|
|
310
|
-
assertEq(coin.platformReferrer(), coin.protocolRewardRecipient(), "platformReferrer");
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function test_deploy_with_usdc_revert_invalid_eth_transfer() public {
|
|
314
|
-
address[] memory owners = new address[](1);
|
|
315
|
-
owners[0] = users.creator;
|
|
316
|
-
|
|
317
|
-
dealUSDC(users.creator, 1);
|
|
318
|
-
|
|
319
|
-
vm.deal(users.creator, 1e6);
|
|
320
|
-
|
|
321
|
-
vm.prank(users.creator);
|
|
322
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.EthTransferInvalid.selector));
|
|
323
|
-
|
|
324
|
-
factory.deploy{value: 1e6}(
|
|
325
|
-
users.creator,
|
|
326
|
-
owners,
|
|
327
|
-
"https://testcoinusdcpair.com",
|
|
328
|
-
"Testcoinusdcpair",
|
|
329
|
-
"TESTCOINUSDCPAIR",
|
|
330
|
-
_generatePoolConfig(USDC_ADDRESS),
|
|
331
|
-
users.platformReferrer,
|
|
332
|
-
0
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function test_deploy_without_initial_order() public {
|
|
337
|
-
address[] memory owners = new address[](1);
|
|
338
|
-
owners[0] = users.creator;
|
|
339
|
-
|
|
340
|
-
(address coinAddress, ) = factory.deploy(
|
|
341
|
-
users.creator,
|
|
342
|
-
owners,
|
|
343
|
-
"https://test.com",
|
|
344
|
-
"Test Token",
|
|
345
|
-
"TEST",
|
|
346
|
-
_generatePoolConfig(address(weth)),
|
|
347
|
-
users.platformReferrer,
|
|
348
|
-
0
|
|
349
|
-
);
|
|
350
|
-
coin = Coin(payable(coinAddress));
|
|
351
|
-
|
|
352
|
-
assertEq(coin.balanceOf(users.creator), 10_000_000e18, "Should only have initial creator allocation");
|
|
353
|
-
}
|
|
354
|
-
|
|
355
68
|
function test_upgrade() public {
|
|
356
|
-
ZoraFactoryImpl newImpl = new ZoraFactoryImpl(
|
|
357
|
-
address(coinV3Impl),
|
|
358
|
-
address(coinV4Impl),
|
|
359
|
-
address(creatorCoinImpl),
|
|
360
|
-
address(contentCoinHook),
|
|
361
|
-
address(creatorCoinHook)
|
|
362
|
-
);
|
|
69
|
+
ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
|
|
363
70
|
|
|
364
71
|
vm.prank(users.factoryOwner);
|
|
365
72
|
ZoraFactoryImpl(address(factory)).upgradeToAndCall(address(newImpl), "");
|
|
@@ -380,13 +87,7 @@ contract FactoryTest is BaseTest {
|
|
|
380
87
|
}
|
|
381
88
|
|
|
382
89
|
function test_revert_invalid_owner() public {
|
|
383
|
-
ZoraFactoryImpl newImpl = new ZoraFactoryImpl(
|
|
384
|
-
address(coinV3Impl),
|
|
385
|
-
address(coinV4Impl),
|
|
386
|
-
address(creatorCoinImpl),
|
|
387
|
-
address(contentCoinHook),
|
|
388
|
-
address(creatorCoinHook)
|
|
389
|
-
);
|
|
90
|
+
ZoraFactoryImpl newImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(contentCoinHook), address(creatorCoinHook));
|
|
390
91
|
|
|
391
92
|
vm.prank(users.creator);
|
|
392
93
|
vm.expectRevert(abi.encodeWithSelector(OwnableUpgradeable.OwnableUnauthorizedAccount.selector, users.creator));
|
|
@@ -417,7 +118,7 @@ contract FactoryTest is BaseTest {
|
|
|
417
118
|
address platformReferrer = users.platformReferrer;
|
|
418
119
|
|
|
419
120
|
bytes memory poolConfig = CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(address(weth));
|
|
420
|
-
bytes memory poolConfigForGettingAddress = poolConfigChanged ? CoinConfigurationVersions.
|
|
121
|
+
bytes memory poolConfigForGettingAddress = poolConfigChanged ? CoinConfigurationVersions.defaultDopplerMultiCurveUniV4(address(0)) : poolConfig;
|
|
421
122
|
|
|
422
123
|
address expectedCoinAddress = factory.coinAddress(msgSender, name, symbol, poolConfigForGettingAddress, platformReferrer, salt);
|
|
423
124
|
|
|
@@ -453,4 +154,20 @@ contract FactoryTest is BaseTest {
|
|
|
453
154
|
assertEq(coinAddress, expectedCoinAddress, "coinAddress should match");
|
|
454
155
|
}
|
|
455
156
|
}
|
|
157
|
+
|
|
158
|
+
function test_upgrade_with_mismatched_contract_name() public {
|
|
159
|
+
// Create a mock implementation with different contract name
|
|
160
|
+
MockBadFactory badImpl = new MockBadFactory();
|
|
161
|
+
|
|
162
|
+
vm.prank(users.factoryOwner);
|
|
163
|
+
vm.expectRevert(abi.encodeWithSelector(IZoraFactory.UpgradeToMismatchedContractName.selector, "ZoraCoinFactory", "BadFactory"));
|
|
164
|
+
ZoraFactoryImpl(address(factory)).upgradeToAndCall(address(badImpl), "");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Mock contracts for testing
|
|
169
|
+
contract MockBadFactory is IHasContractName {
|
|
170
|
+
function contractName() external pure returns (string memory) {
|
|
171
|
+
return "BadFactory";
|
|
172
|
+
}
|
|
456
173
|
}
|