@zoralabs/coins 0.6.1 → 0.7.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 +69 -55
- package/CHANGELOG.md +12 -0
- package/abis/BaseTest.json +0 -23
- package/abis/Coin.json +186 -77
- package/abis/CoinConfigurationVersions.json +7 -0
- package/abis/CoinSetup.json +7 -0
- package/abis/CoinTest.json +5 -49
- package/abis/CustomRevert.json +28 -0
- package/abis/DopplerUniswapV3Test.json +891 -0
- package/abis/FactoryTest.json +7 -23
- package/abis/IAirlock.json +15 -0
- package/abis/ICoin.json +52 -34
- package/abis/IDopplerErrors.json +44 -0
- package/abis/INonfungiblePositionManager.json +13 -0
- package/abis/IUniswapV3Factory.json +198 -0
- package/abis/IUniswapV3Pool.json +135 -0
- package/abis/MultiOwnableTest.json +0 -23
- package/abis/SafeCast.json +7 -0
- package/abis/Simulate.json +120 -0
- package/abis/SqrtPriceMath.json +22 -0
- package/abis/TickMath.json +24 -0
- package/abis/ZoraFactoryImpl.json +59 -0
- package/addresses/8453.json +3 -3
- package/dist/index.cjs +160 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +160 -39
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +349 -67
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +161 -40
- package/package.json +3 -3
- package/script/CoinsDeployerBase.sol +1 -1
- package/script/Simulate.s.sol +67 -0
- package/src/Coin.sol +159 -90
- package/src/ZoraFactoryImpl.sol +47 -1
- package/src/interfaces/IAirlock.sol +6 -0
- package/src/interfaces/ICoin.sol +18 -2
- package/src/interfaces/IDopplerErrors.sol +14 -0
- package/src/interfaces/INonfungiblePositionManager.sol +2 -0
- package/src/interfaces/IUniswapV3Factory.sol +64 -0
- package/src/interfaces/IUniswapV3Pool.sol +48 -0
- package/src/libs/CoinConfigurationVersions.sol +9 -0
- package/src/libs/CoinDopplerUniV3.sol +202 -0
- package/src/libs/CoinLegacy.sol +48 -0
- package/src/libs/CoinSetup.sol +37 -0
- package/src/libs/MarketConstants.sol +25 -0
- package/src/types/LpPosition.sol +8 -0
- package/src/types/PoolState.sol +24 -0
- package/src/utils/CoinConstants.sol +5 -12
- package/src/utils/uniswap/BitMath.sol +55 -0
- package/src/utils/uniswap/CustomRevert.sol +111 -0
- package/src/utils/uniswap/FixedPoint96.sol +11 -0
- package/src/utils/uniswap/FullMath.sol +118 -0
- package/src/utils/uniswap/LiquidityAmounts.sol +117 -0
- package/src/utils/uniswap/SafeCast.sol +61 -0
- package/src/utils/uniswap/SqrtPriceMath.sol +249 -0
- package/src/utils/uniswap/TickMath.sol +244 -0
- package/src/utils/uniswap/UnsafeMath.sol +30 -0
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +65 -65
- package/test/CoinDopplerUniV3.t.sol +452 -0
- package/test/Factory.t.sol +49 -7
- package/test/utils/BaseTest.sol +26 -7
- package/wagmi.config.ts +1 -1
- package/abis/IERC721Receiver.json +0 -36
- package/src/utils/TickMath.sol +0 -210
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
import {BitMath} from "./BitMath.sol";
|
|
5
|
+
import {CustomRevert} from "./CustomRevert.sol";
|
|
6
|
+
|
|
7
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/libraries/TickMath.sol
|
|
8
|
+
/// @title Math library for computing sqrt prices from ticks and vice versa
|
|
9
|
+
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
|
|
10
|
+
/// prices between 2**-128 and 2**128
|
|
11
|
+
library TickMath {
|
|
12
|
+
using CustomRevert for bytes4;
|
|
13
|
+
|
|
14
|
+
/// @notice Thrown when the tick passed to #getSqrtPriceAtTick is not between MIN_TICK and MAX_TICK
|
|
15
|
+
error InvalidTick(int24 tick);
|
|
16
|
+
/// @notice Thrown when the price passed to #getTickAtSqrtPrice does not correspond to a price between MIN_TICK and MAX_TICK
|
|
17
|
+
error InvalidSqrtPrice(uint160 sqrtPriceX96);
|
|
18
|
+
|
|
19
|
+
/// @dev The minimum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**-128
|
|
20
|
+
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
|
|
21
|
+
int24 internal constant MIN_TICK = -887272;
|
|
22
|
+
/// @dev The maximum tick that may be passed to #getSqrtPriceAtTick computed from log base 1.0001 of 2**128
|
|
23
|
+
/// @dev If ever MIN_TICK and MAX_TICK are not centered around 0, the absTick logic in getSqrtPriceAtTick cannot be used
|
|
24
|
+
int24 internal constant MAX_TICK = 887272;
|
|
25
|
+
|
|
26
|
+
/// @dev The minimum tick spacing value drawn from the range of type int16 that is greater than 0, i.e. min from the range [1, 32767]
|
|
27
|
+
int24 internal constant MIN_TICK_SPACING = 1;
|
|
28
|
+
/// @dev The maximum tick spacing value drawn from the range of type int16, i.e. max from the range [1, 32767]
|
|
29
|
+
int24 internal constant MAX_TICK_SPACING = type(int16).max;
|
|
30
|
+
|
|
31
|
+
/// @dev The minimum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MIN_TICK)
|
|
32
|
+
uint160 internal constant MIN_SQRT_PRICE = 4295128739;
|
|
33
|
+
/// @dev The maximum value that can be returned from #getSqrtPriceAtTick. Equivalent to getSqrtPriceAtTick(MAX_TICK)
|
|
34
|
+
uint160 internal constant MAX_SQRT_PRICE = 1461446703485210103287273052203988822378723970342;
|
|
35
|
+
/// @dev A threshold used for optimized bounds check, equals `MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1`
|
|
36
|
+
uint160 internal constant MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE = 1461446703485210103287273052203988822378723970342 - 4295128739 - 1;
|
|
37
|
+
|
|
38
|
+
/// @notice Given a tickSpacing, compute the maximum usable tick
|
|
39
|
+
function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
|
|
40
|
+
unchecked {
|
|
41
|
+
return (MAX_TICK / tickSpacing) * tickSpacing;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// @notice Given a tickSpacing, compute the minimum usable tick
|
|
46
|
+
function minUsableTick(int24 tickSpacing) internal pure returns (int24) {
|
|
47
|
+
unchecked {
|
|
48
|
+
return (MIN_TICK / tickSpacing) * tickSpacing;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// @notice Calculates sqrt(1.0001^tick) * 2^96
|
|
53
|
+
/// @dev Throws if |tick| > max tick
|
|
54
|
+
/// @param tick The input tick for the above formula
|
|
55
|
+
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the price of the two assets (currency1/currency0)
|
|
56
|
+
/// at the given tick
|
|
57
|
+
function getSqrtPriceAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
|
|
58
|
+
unchecked {
|
|
59
|
+
uint256 absTick;
|
|
60
|
+
assembly ("memory-safe") {
|
|
61
|
+
tick := signextend(2, tick)
|
|
62
|
+
// mask = 0 if tick >= 0 else -1 (all 1s)
|
|
63
|
+
let mask := sar(255, tick)
|
|
64
|
+
// if tick >= 0, |tick| = tick = 0 ^ tick
|
|
65
|
+
// if tick < 0, |tick| = ~~|tick| = ~(-|tick| - 1) = ~(tick - 1) = (-1) ^ (tick - 1)
|
|
66
|
+
// either way, |tick| = mask ^ (tick + mask)
|
|
67
|
+
absTick := xor(mask, add(mask, tick))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (absTick > uint256(int256(MAX_TICK))) InvalidTick.selector.revertWith(tick);
|
|
71
|
+
|
|
72
|
+
// The tick is decomposed into bits, and for each bit with index i that is set, the product of 1/sqrt(1.0001^(2^i))
|
|
73
|
+
// is calculated (using Q128.128). The constants used for this calculation are rounded to the nearest integer
|
|
74
|
+
|
|
75
|
+
// Equivalent to:
|
|
76
|
+
// price = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
|
|
77
|
+
// or price = int(2**128 / sqrt(1.0001)) if (absTick & 0x1) else 1 << 128
|
|
78
|
+
uint256 price;
|
|
79
|
+
assembly ("memory-safe") {
|
|
80
|
+
price := xor(shl(128, 1), mul(xor(shl(128, 1), 0xfffcb933bd6fad37aa2d162d1a594001), and(absTick, 0x1)))
|
|
81
|
+
}
|
|
82
|
+
if (absTick & 0x2 != 0) price = (price * 0xfff97272373d413259a46990580e213a) >> 128;
|
|
83
|
+
if (absTick & 0x4 != 0) price = (price * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
|
|
84
|
+
if (absTick & 0x8 != 0) price = (price * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
|
|
85
|
+
if (absTick & 0x10 != 0) price = (price * 0xffcb9843d60f6159c9db58835c926644) >> 128;
|
|
86
|
+
if (absTick & 0x20 != 0) price = (price * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
|
|
87
|
+
if (absTick & 0x40 != 0) price = (price * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
|
|
88
|
+
if (absTick & 0x80 != 0) price = (price * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
|
|
89
|
+
if (absTick & 0x100 != 0) price = (price * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
|
|
90
|
+
if (absTick & 0x200 != 0) price = (price * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
|
|
91
|
+
if (absTick & 0x400 != 0) price = (price * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
|
|
92
|
+
if (absTick & 0x800 != 0) price = (price * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
|
|
93
|
+
if (absTick & 0x1000 != 0) price = (price * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
|
|
94
|
+
if (absTick & 0x2000 != 0) price = (price * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
|
|
95
|
+
if (absTick & 0x4000 != 0) price = (price * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
|
|
96
|
+
if (absTick & 0x8000 != 0) price = (price * 0x31be135f97d08fd981231505542fcfa6) >> 128;
|
|
97
|
+
if (absTick & 0x10000 != 0) price = (price * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
|
|
98
|
+
if (absTick & 0x20000 != 0) price = (price * 0x5d6af8dedb81196699c329225ee604) >> 128;
|
|
99
|
+
if (absTick & 0x40000 != 0) price = (price * 0x2216e584f5fa1ea926041bedfe98) >> 128;
|
|
100
|
+
if (absTick & 0x80000 != 0) price = (price * 0x48a170391f7dc42444e8fa2) >> 128;
|
|
101
|
+
|
|
102
|
+
assembly ("memory-safe") {
|
|
103
|
+
// if (tick > 0) price = type(uint256).max / price;
|
|
104
|
+
if sgt(tick, 0) {
|
|
105
|
+
price := div(not(0), price)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
|
|
109
|
+
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
|
|
110
|
+
// we round up in the division so getTickAtSqrtPrice of the output price is always consistent
|
|
111
|
+
// `sub(shl(32, 1), 1)` is `type(uint32).max`
|
|
112
|
+
// `price + type(uint32).max` will not overflow because `price` fits in 192 bits
|
|
113
|
+
sqrtPriceX96 := shr(32, add(price, sub(shl(32, 1), 1)))
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// @notice Calculates the greatest tick value such that getSqrtPriceAtTick(tick) <= sqrtPriceX96
|
|
119
|
+
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_PRICE, as MIN_SQRT_PRICE is the lowest value getSqrtPriceAtTick may
|
|
120
|
+
/// ever return.
|
|
121
|
+
/// @param sqrtPriceX96 The sqrt price for which to compute the tick as a Q64.96
|
|
122
|
+
/// @return tick The greatest tick for which the getSqrtPriceAtTick(tick) is less than or equal to the input sqrtPriceX96
|
|
123
|
+
function getTickAtSqrtPrice(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
|
|
124
|
+
unchecked {
|
|
125
|
+
// Equivalent: if (sqrtPriceX96 < MIN_SQRT_PRICE || sqrtPriceX96 >= MAX_SQRT_PRICE) revert InvalidSqrtPrice();
|
|
126
|
+
// second inequality must be >= because the price can never reach the price at the max tick
|
|
127
|
+
// if sqrtPriceX96 < MIN_SQRT_PRICE, the `sub` underflows and `gt` is true
|
|
128
|
+
// if sqrtPriceX96 >= MAX_SQRT_PRICE, sqrtPriceX96 - MIN_SQRT_PRICE > MAX_SQRT_PRICE - MIN_SQRT_PRICE - 1
|
|
129
|
+
if ((sqrtPriceX96 - MIN_SQRT_PRICE) > MAX_SQRT_PRICE_MINUS_MIN_SQRT_PRICE_MINUS_ONE) {
|
|
130
|
+
InvalidSqrtPrice.selector.revertWith(sqrtPriceX96);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
uint256 price = uint256(sqrtPriceX96) << 32;
|
|
134
|
+
|
|
135
|
+
uint256 r = price;
|
|
136
|
+
uint256 msb = BitMath.mostSignificantBit(r);
|
|
137
|
+
|
|
138
|
+
if (msb >= 128) r = price >> (msb - 127);
|
|
139
|
+
else r = price << (127 - msb);
|
|
140
|
+
|
|
141
|
+
int256 log_2 = (int256(msb) - 128) << 64;
|
|
142
|
+
|
|
143
|
+
assembly ("memory-safe") {
|
|
144
|
+
r := shr(127, mul(r, r))
|
|
145
|
+
let f := shr(128, r)
|
|
146
|
+
log_2 := or(log_2, shl(63, f))
|
|
147
|
+
r := shr(f, r)
|
|
148
|
+
}
|
|
149
|
+
assembly ("memory-safe") {
|
|
150
|
+
r := shr(127, mul(r, r))
|
|
151
|
+
let f := shr(128, r)
|
|
152
|
+
log_2 := or(log_2, shl(62, f))
|
|
153
|
+
r := shr(f, r)
|
|
154
|
+
}
|
|
155
|
+
assembly ("memory-safe") {
|
|
156
|
+
r := shr(127, mul(r, r))
|
|
157
|
+
let f := shr(128, r)
|
|
158
|
+
log_2 := or(log_2, shl(61, f))
|
|
159
|
+
r := shr(f, r)
|
|
160
|
+
}
|
|
161
|
+
assembly ("memory-safe") {
|
|
162
|
+
r := shr(127, mul(r, r))
|
|
163
|
+
let f := shr(128, r)
|
|
164
|
+
log_2 := or(log_2, shl(60, f))
|
|
165
|
+
r := shr(f, r)
|
|
166
|
+
}
|
|
167
|
+
assembly ("memory-safe") {
|
|
168
|
+
r := shr(127, mul(r, r))
|
|
169
|
+
let f := shr(128, r)
|
|
170
|
+
log_2 := or(log_2, shl(59, f))
|
|
171
|
+
r := shr(f, r)
|
|
172
|
+
}
|
|
173
|
+
assembly ("memory-safe") {
|
|
174
|
+
r := shr(127, mul(r, r))
|
|
175
|
+
let f := shr(128, r)
|
|
176
|
+
log_2 := or(log_2, shl(58, f))
|
|
177
|
+
r := shr(f, r)
|
|
178
|
+
}
|
|
179
|
+
assembly ("memory-safe") {
|
|
180
|
+
r := shr(127, mul(r, r))
|
|
181
|
+
let f := shr(128, r)
|
|
182
|
+
log_2 := or(log_2, shl(57, f))
|
|
183
|
+
r := shr(f, r)
|
|
184
|
+
}
|
|
185
|
+
assembly ("memory-safe") {
|
|
186
|
+
r := shr(127, mul(r, r))
|
|
187
|
+
let f := shr(128, r)
|
|
188
|
+
log_2 := or(log_2, shl(56, f))
|
|
189
|
+
r := shr(f, r)
|
|
190
|
+
}
|
|
191
|
+
assembly ("memory-safe") {
|
|
192
|
+
r := shr(127, mul(r, r))
|
|
193
|
+
let f := shr(128, r)
|
|
194
|
+
log_2 := or(log_2, shl(55, f))
|
|
195
|
+
r := shr(f, r)
|
|
196
|
+
}
|
|
197
|
+
assembly ("memory-safe") {
|
|
198
|
+
r := shr(127, mul(r, r))
|
|
199
|
+
let f := shr(128, r)
|
|
200
|
+
log_2 := or(log_2, shl(54, f))
|
|
201
|
+
r := shr(f, r)
|
|
202
|
+
}
|
|
203
|
+
assembly ("memory-safe") {
|
|
204
|
+
r := shr(127, mul(r, r))
|
|
205
|
+
let f := shr(128, r)
|
|
206
|
+
log_2 := or(log_2, shl(53, f))
|
|
207
|
+
r := shr(f, r)
|
|
208
|
+
}
|
|
209
|
+
assembly ("memory-safe") {
|
|
210
|
+
r := shr(127, mul(r, r))
|
|
211
|
+
let f := shr(128, r)
|
|
212
|
+
log_2 := or(log_2, shl(52, f))
|
|
213
|
+
r := shr(f, r)
|
|
214
|
+
}
|
|
215
|
+
assembly ("memory-safe") {
|
|
216
|
+
r := shr(127, mul(r, r))
|
|
217
|
+
let f := shr(128, r)
|
|
218
|
+
log_2 := or(log_2, shl(51, f))
|
|
219
|
+
r := shr(f, r)
|
|
220
|
+
}
|
|
221
|
+
assembly ("memory-safe") {
|
|
222
|
+
r := shr(127, mul(r, r))
|
|
223
|
+
let f := shr(128, r)
|
|
224
|
+
log_2 := or(log_2, shl(50, f))
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // Q22.128 number
|
|
228
|
+
|
|
229
|
+
// Magic number represents the ceiling of the maximum value of the error when approximating log_sqrt10001(x)
|
|
230
|
+
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
|
|
231
|
+
|
|
232
|
+
// Magic number represents the minimum value of the error when approximating log_sqrt10001(x), when
|
|
233
|
+
// sqrtPrice is from the range (2^-64, 2^64). This is safe as MIN_SQRT_PRICE is more than 2^-64. If MIN_SQRT_PRICE
|
|
234
|
+
// is changed, this may need to be changed too
|
|
235
|
+
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
|
|
236
|
+
|
|
237
|
+
tick = tickLow == tickHi
|
|
238
|
+
? tickLow
|
|
239
|
+
: getSqrtPriceAtTick(tickHi) <= sqrtPriceX96
|
|
240
|
+
? tickHi
|
|
241
|
+
: tickLow;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
pragma solidity ^0.8.0;
|
|
3
|
+
|
|
4
|
+
/// @dev https://github.com/Uniswap/v4-core/blob/80311e34080fee64b6fc6c916e9a51a437d0e482/src/libraries/UnsafeMath.sol
|
|
5
|
+
/// @title Math functions that do not check inputs or outputs
|
|
6
|
+
/// @notice Contains methods that perform common math functions but do not do any overflow or underflow checks
|
|
7
|
+
library UnsafeMath {
|
|
8
|
+
/// @notice Returns ceil(x / y)
|
|
9
|
+
/// @dev division by 0 will return 0, and should be checked externally
|
|
10
|
+
/// @param x The dividend
|
|
11
|
+
/// @param y The divisor
|
|
12
|
+
/// @return z The quotient, ceil(x / y)
|
|
13
|
+
function divRoundingUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
|
|
14
|
+
assembly ("memory-safe") {
|
|
15
|
+
z := add(div(x, y), gt(mod(x, y), 0))
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/// @notice Calculates floor(a×b÷denominator)
|
|
20
|
+
/// @dev division by 0 will return 0, and should be checked externally
|
|
21
|
+
/// @param a The multiplicand
|
|
22
|
+
/// @param b The multiplier
|
|
23
|
+
/// @param denominator The divisor
|
|
24
|
+
/// @return result The 256-bit result, floor(a×b÷denominator)
|
|
25
|
+
function simpleMulDiv(uint256 a, uint256 b, uint256 denominator) internal pure returns (uint256 result) {
|
|
26
|
+
assembly ("memory-safe") {
|
|
27
|
+
result := div(mul(a, b), denominator)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
|
|
|
9
9
|
contract ContractVersionBase is IVersionedContract {
|
|
10
10
|
/// @notice The version of the contract
|
|
11
11
|
function contractVersion() external pure override returns (string memory) {
|
|
12
|
-
return "0.
|
|
12
|
+
return "0.7.0";
|
|
13
13
|
}
|
|
14
14
|
}
|
package/test/Coin.t.sol
CHANGED
|
@@ -12,7 +12,7 @@ contract CoinTest is BaseTest {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function test_contract_version() public view {
|
|
15
|
-
assertEq(coin.contractVersion(), "0.
|
|
15
|
+
assertEq(coin.contractVersion(), "0.7.0");
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function test_supply_constants() public view {
|
|
@@ -29,25 +29,27 @@ contract CoinTest is BaseTest {
|
|
|
29
29
|
|
|
30
30
|
function test_constructor_validation() public {
|
|
31
31
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
32
|
-
new Coin(address(0), address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER);
|
|
32
|
+
new Coin(address(0), address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
33
33
|
|
|
34
34
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
35
|
-
new Coin(users.feeRecipient, address(0), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER);
|
|
35
|
+
new Coin(users.feeRecipient, address(0), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
36
36
|
|
|
37
37
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
38
|
-
new Coin(users.feeRecipient, address(protocolRewards), address(0), NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER);
|
|
38
|
+
new Coin(users.feeRecipient, address(protocolRewards), address(0), NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
39
39
|
|
|
40
40
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
41
|
-
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, address(0), SWAP_ROUTER);
|
|
41
|
+
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, address(0), SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
42
42
|
|
|
43
43
|
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
44
|
-
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, address(0));
|
|
44
|
+
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, address(0), DOPPLER_AIRLOCK);
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
vm.expectRevert(abi.encodeWithSelector(ICoin.AddressZero.selector));
|
|
47
|
+
new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, address(0));
|
|
48
|
+
|
|
49
|
+
Coin newToken = new Coin(users.feeRecipient, address(protocolRewards), WETH_ADDRESS, NONFUNGIBLE_POSITION_MANAGER, SWAP_ROUTER, DOPPLER_AIRLOCK);
|
|
47
50
|
assertEq(address(newToken.protocolRewardRecipient()), users.feeRecipient);
|
|
48
51
|
assertEq(address(newToken.protocolRewards()), address(protocolRewards));
|
|
49
52
|
assertEq(address(newToken.WETH()), WETH_ADDRESS);
|
|
50
|
-
assertEq(address(newToken.nonfungiblePositionManager()), NONFUNGIBLE_POSITION_MANAGER);
|
|
51
53
|
assertEq(address(newToken.swapRouter()), SWAP_ROUTER);
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -64,12 +66,22 @@ contract CoinTest is BaseTest {
|
|
|
64
66
|
"INIT",
|
|
65
67
|
users.platformReferrer,
|
|
66
68
|
address(weth),
|
|
67
|
-
LP_TICK_LOWER_WETH,
|
|
69
|
+
MarketConstants.LP_TICK_LOWER_WETH,
|
|
68
70
|
0
|
|
69
71
|
);
|
|
70
72
|
coin = Coin(payable(coinAddress));
|
|
71
73
|
|
|
72
|
-
(coinAddress, ) = factory.deploy(
|
|
74
|
+
(coinAddress, ) = factory.deploy(
|
|
75
|
+
users.creator,
|
|
76
|
+
owners,
|
|
77
|
+
"https://init.com",
|
|
78
|
+
"Init Token",
|
|
79
|
+
"INIT",
|
|
80
|
+
address(0),
|
|
81
|
+
address(weth),
|
|
82
|
+
MarketConstants.LP_TICK_LOWER_WETH,
|
|
83
|
+
0
|
|
84
|
+
);
|
|
73
85
|
coin = Coin(payable(coinAddress));
|
|
74
86
|
|
|
75
87
|
assertEq(coin.payoutRecipient(), users.creator);
|
|
@@ -91,13 +103,33 @@ contract CoinTest is BaseTest {
|
|
|
91
103
|
"INIT",
|
|
92
104
|
users.platformReferrer,
|
|
93
105
|
address(weth),
|
|
94
|
-
LP_TICK_LOWER_WETH,
|
|
106
|
+
MarketConstants.LP_TICK_LOWER_WETH,
|
|
95
107
|
0
|
|
96
108
|
);
|
|
97
109
|
coin = Coin(payable(coinAddress));
|
|
98
110
|
|
|
99
111
|
vm.expectRevert(abi.encodeWithSignature("InvalidInitialization()"));
|
|
100
|
-
coin.initialize(users.creator,
|
|
112
|
+
coin.initialize(users.creator, owners, "https://init.com", "Init Token", "INIT", abi.encode(""), users.platformReferrer);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function test_revert_pool_exists() public {
|
|
116
|
+
address[] memory owners = new address[](1);
|
|
117
|
+
owners[0] = users.creator;
|
|
118
|
+
|
|
119
|
+
vm.etch(address(0x1C61DAa59b45525d4fb139106EFEC97c2D8De9be), abi.encode(bytes32(uint256(1))));
|
|
120
|
+
|
|
121
|
+
vm.expectRevert();
|
|
122
|
+
factory.deploy(
|
|
123
|
+
users.creator,
|
|
124
|
+
owners,
|
|
125
|
+
"https://init.com",
|
|
126
|
+
"Init Token",
|
|
127
|
+
"INIT",
|
|
128
|
+
users.platformReferrer,
|
|
129
|
+
address(weth),
|
|
130
|
+
MarketConstants.LP_TICK_LOWER_WETH,
|
|
131
|
+
0
|
|
132
|
+
);
|
|
101
133
|
}
|
|
102
134
|
|
|
103
135
|
function test_erc165_interface_support() public view {
|
|
@@ -209,11 +241,13 @@ contract CoinTest is BaseTest {
|
|
|
209
241
|
vm.prank(users.buyer);
|
|
210
242
|
weth.approve(address(swapRouter), 100_000);
|
|
211
243
|
|
|
244
|
+
assertEq(coin.balanceOf(users.buyer), 0, "buyer coin balance initial");
|
|
245
|
+
|
|
212
246
|
// Set up the swap parameters
|
|
213
247
|
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
214
248
|
tokenIn: WETH_ADDRESS,
|
|
215
249
|
tokenOut: address(coin),
|
|
216
|
-
fee: LP_FEE,
|
|
250
|
+
fee: MarketConstants.LP_FEE,
|
|
217
251
|
recipient: address(users.buyer),
|
|
218
252
|
amountIn: 100_000,
|
|
219
253
|
amountOutMinimum: 0,
|
|
@@ -235,7 +269,8 @@ contract CoinTest is BaseTest {
|
|
|
235
269
|
coin.claimSecondaryRewards(false);
|
|
236
270
|
assertEq(protocolRewards.balanceOf(users.creator), 499);
|
|
237
271
|
assertEq(protocolRewards.balanceOf(users.platformReferrer), 249);
|
|
238
|
-
assertEq(protocolRewards.balanceOf(users.feeRecipient),
|
|
272
|
+
assertEq(protocolRewards.balanceOf(users.feeRecipient), 202);
|
|
273
|
+
assertEq(dopplerFeeRecipient().balance, 49);
|
|
239
274
|
}
|
|
240
275
|
|
|
241
276
|
function test_sell_for_eth_direct_and_claim_secondary_push_eth() public {
|
|
@@ -251,7 +286,7 @@ contract CoinTest is BaseTest {
|
|
|
251
286
|
ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
|
|
252
287
|
tokenIn: WETH_ADDRESS,
|
|
253
288
|
tokenOut: address(coin),
|
|
254
|
-
fee: LP_FEE,
|
|
289
|
+
fee: MarketConstants.LP_FEE,
|
|
255
290
|
recipient: address(users.buyer),
|
|
256
291
|
amountIn: 100_000,
|
|
257
292
|
amountOutMinimum: 0,
|
|
@@ -406,11 +441,6 @@ contract CoinTest is BaseTest {
|
|
|
406
441
|
assertTrue(success);
|
|
407
442
|
}
|
|
408
443
|
|
|
409
|
-
function test_only_pool_callback() public {
|
|
410
|
-
vm.expectRevert(abi.encodeWithSelector(ICoin.OnlyPool.selector));
|
|
411
|
-
coin.onERC721Received(address(0), address(0), 0, "");
|
|
412
|
-
}
|
|
413
|
-
|
|
414
444
|
function test_default_platform_referrer() public {
|
|
415
445
|
address[] memory owners = new address[](1);
|
|
416
446
|
owners[0] = users.creator;
|
|
@@ -423,7 +453,7 @@ contract CoinTest is BaseTest {
|
|
|
423
453
|
"TEST",
|
|
424
454
|
users.platformReferrer,
|
|
425
455
|
address(weth),
|
|
426
|
-
LP_TICK_LOWER_WETH,
|
|
456
|
+
MarketConstants.LP_TICK_LOWER_WETH,
|
|
427
457
|
0
|
|
428
458
|
);
|
|
429
459
|
Coin newCoin = Coin(payable(newCoinAddr));
|
|
@@ -438,42 +468,6 @@ contract CoinTest is BaseTest {
|
|
|
438
468
|
assertGt(protocolRewards.balanceOf(users.feeRecipient), expectedFees.platformReferrer, "feeRecipient eth balance");
|
|
439
469
|
}
|
|
440
470
|
|
|
441
|
-
function test_invalid_weth_tick() public {
|
|
442
|
-
address[] memory owners = new address[](1);
|
|
443
|
-
owners[0] = users.creator;
|
|
444
|
-
|
|
445
|
-
vm.expectRevert(ICoin.InvalidWethLowerTick.selector);
|
|
446
|
-
(address newCoinAddr, ) = factory.deploy(
|
|
447
|
-
users.creator,
|
|
448
|
-
owners,
|
|
449
|
-
"https://test.com",
|
|
450
|
-
"Test Token",
|
|
451
|
-
"TEST",
|
|
452
|
-
users.platformReferrer,
|
|
453
|
-
address(weth),
|
|
454
|
-
LP_TICK_LOWER_WETH - 1,
|
|
455
|
-
0
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
function test_invalid_currency_tick() public {
|
|
460
|
-
address[] memory owners = new address[](1);
|
|
461
|
-
owners[0] = users.creator;
|
|
462
|
-
|
|
463
|
-
vm.expectRevert(ICoin.InvalidCurrencyLowerTick.selector);
|
|
464
|
-
(address newCoinAddr, ) = factory.deploy(
|
|
465
|
-
users.creator,
|
|
466
|
-
owners,
|
|
467
|
-
"https://test.com",
|
|
468
|
-
"Test Token",
|
|
469
|
-
"TEST",
|
|
470
|
-
users.platformReferrer,
|
|
471
|
-
address(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913),
|
|
472
|
-
20,
|
|
473
|
-
0
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
|
|
477
471
|
function test_default_order_referrer() public {
|
|
478
472
|
vm.deal(users.buyer, 1 ether);
|
|
479
473
|
vm.prank(users.buyer);
|
|
@@ -500,12 +494,6 @@ contract CoinTest is BaseTest {
|
|
|
500
494
|
coin.sell(users.coinRecipient, 1e18, type(uint256).max, 0, users.tradeReferrer);
|
|
501
495
|
}
|
|
502
496
|
|
|
503
|
-
function test_uniswap_swap_callback() public {
|
|
504
|
-
// Test swap callback
|
|
505
|
-
vm.prank(address(pool));
|
|
506
|
-
coin.uniswapV3SwapCallback(100, -100, "");
|
|
507
|
-
}
|
|
508
|
-
|
|
509
497
|
function test_eth_transfer_fail() public {
|
|
510
498
|
vm.deal(users.buyer, 1 ether);
|
|
511
499
|
vm.prank(users.buyer);
|
|
@@ -524,7 +512,8 @@ contract CoinTest is BaseTest {
|
|
|
524
512
|
vm.deal(users.buyer, 1 ether);
|
|
525
513
|
vm.prank(users.buyer);
|
|
526
514
|
vm.expectRevert(abi.encodeWithSelector(ICoin.OnlyWeth.selector));
|
|
527
|
-
address(coin).call{value: 1 ether}("");
|
|
515
|
+
(bool ignoredSuccess, ) = address(coin).call{value: 1 ether}("");
|
|
516
|
+
(ignoredSuccess);
|
|
528
517
|
|
|
529
518
|
assertEq(address(coin).balance, 0, "coin balance");
|
|
530
519
|
}
|
|
@@ -534,6 +523,7 @@ contract CoinTest is BaseTest {
|
|
|
534
523
|
uint256 initialTokenCreatorBalance = protocolRewards.balanceOf(users.creator);
|
|
535
524
|
uint256 initialOrderReferrerBalance = protocolRewards.balanceOf(users.tradeReferrer);
|
|
536
525
|
uint256 initialFeeRecipientBalance = protocolRewards.balanceOf(users.feeRecipient);
|
|
526
|
+
uint256 initialDopplerRecipientBalance = airlock.owner().balance;
|
|
537
527
|
|
|
538
528
|
uint256 buyAmount = 1 ether;
|
|
539
529
|
vm.deal(users.buyer, buyAmount);
|
|
@@ -546,7 +536,11 @@ contract CoinTest is BaseTest {
|
|
|
546
536
|
uint256 expectedLpFee = 9900000000000000; // 0.99 ETH * 1% --> ~0.00989 ETH
|
|
547
537
|
MarketRewards memory marketRewards = _calculateMarketRewards(expectedLpFee);
|
|
548
538
|
|
|
549
|
-
assertEq(
|
|
539
|
+
assertEq(
|
|
540
|
+
marketRewards.creator + marketRewards.platformReferrer + marketRewards.protocol + marketRewards.doppler,
|
|
541
|
+
expectedLpFee,
|
|
542
|
+
"Secondary rewards incorrect"
|
|
543
|
+
);
|
|
550
544
|
assertApproxEqAbs(
|
|
551
545
|
protocolRewards.balanceOf(users.creator),
|
|
552
546
|
initialTokenCreatorBalance + orderFees.creator + marketRewards.creator,
|
|
@@ -559,6 +553,12 @@ contract CoinTest is BaseTest {
|
|
|
559
553
|
0.0000000000000001 ether,
|
|
560
554
|
"Platform referrer rewards incorrect"
|
|
561
555
|
);
|
|
556
|
+
assertApproxEqAbs(
|
|
557
|
+
airlock.owner().balance,
|
|
558
|
+
initialDopplerRecipientBalance + marketRewards.doppler,
|
|
559
|
+
0.0000000000000001 ether,
|
|
560
|
+
"Doppler rewards incorrect"
|
|
561
|
+
);
|
|
562
562
|
assertApproxEqAbs(
|
|
563
563
|
protocolRewards.balanceOf(users.feeRecipient),
|
|
564
564
|
initialFeeRecipientBalance + orderFees.protocol + marketRewards.protocol,
|