@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.
Files changed (69) hide show
  1. package/.turbo/turbo-build.log +106 -110
  2. package/CHANGELOG.md +28 -0
  3. package/README.md +30 -109
  4. package/abis/BaseCoin.json +442 -0
  5. package/abis/CoinTest.json +3 -246
  6. package/abis/FactoryTest.json +5 -137
  7. package/abis/HooksTest.json +0 -26
  8. package/abis/ICoin.json +378 -0
  9. package/abis/ICoinV3.json +378 -0
  10. package/abis/IZoraFactory.json +0 -18
  11. package/abis/LiquidityMigrationTest.json +101 -0
  12. package/abis/MockBadFactory.json +15 -0
  13. package/abis/ZoraFactoryImpl.json +1 -67
  14. package/dist/index.cjs +236 -265
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +235 -264
  17. package/dist/index.js.map +1 -1
  18. package/dist/wagmiGenerated.d.ts +389 -493
  19. package/dist/wagmiGenerated.d.ts.map +1 -1
  20. package/package/wagmiGenerated.ts +240 -269
  21. package/package.json +3 -3
  22. package/script/DeployPostDeploymentHooks.s.sol +2 -2
  23. package/script/TestBackingCoinSwap.s.sol +8 -8
  24. package/script/TestV4Swap.s.sol +8 -8
  25. package/script/UpgradeFactoryImpl.s.sol +0 -1
  26. package/src/BaseCoin.sol +109 -6
  27. package/src/ContentCoin.sol +4 -4
  28. package/src/CreatorCoin.sol +5 -5
  29. package/src/ZoraFactoryImpl.sol +10 -93
  30. package/src/deployment/CoinsDeployerBase.sol +10 -27
  31. package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
  32. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
  33. package/src/interfaces/ICoin.sol +67 -1
  34. package/src/interfaces/ICreatorCoin.sol +2 -2
  35. package/src/interfaces/IZoraFactory.sol +0 -5
  36. package/src/libs/CoinConfigurationVersions.sol +1 -39
  37. package/src/libs/CoinRewardsV4.sol +2 -2
  38. package/src/libs/CoinSetup.sol +1 -4
  39. package/src/libs/UniV4SwapHelper.sol +1 -1
  40. package/src/libs/UniV4SwapToCurrency.sol +2 -2
  41. package/src/libs/V4Liquidity.sol +1 -1
  42. package/src/version/ContractVersionBase.sol +1 -1
  43. package/test/Coin.t.sol +112 -535
  44. package/test/CoinUniV4.t.sol +5 -5
  45. package/test/DeploymentHooks.t.sol +5 -102
  46. package/test/Factory.t.sol +23 -306
  47. package/test/LiquidityMigration.t.sol +160 -2
  48. package/test/MultiOwnable.t.sol +36 -36
  49. package/test/Upgrades.t.sol +16 -35
  50. package/test/utils/BaseTest.sol +16 -69
  51. package/test/utils/FeeEstimatorHook.sol +3 -3
  52. package/wagmi.config.ts +1 -1
  53. package/abis/BaseCoinV4.json +0 -1840
  54. package/abis/Coin.json +0 -1912
  55. package/abis/DopplerUniswapV3Test.json +0 -800
  56. package/abis/ICoinV4.json +0 -1048
  57. package/abis/Simulate.json +0 -29
  58. package/abis/UniV3BuySell.json +0 -12
  59. package/abis/UniV3Errors.json +0 -32
  60. package/script/Simulate.s.sol +0 -59
  61. package/src/BaseCoinV4.sol +0 -143
  62. package/src/Coin.sol +0 -236
  63. package/src/interfaces/ICoinV4.sol +0 -74
  64. package/src/libs/CoinDopplerUniV3.sol +0 -50
  65. package/src/libs/CoinRewards.sol +0 -201
  66. package/src/libs/CoinSetupV3.sol +0 -50
  67. package/src/libs/UniV3BuySell.sol +0 -231
  68. package/src/libs/UniV3Errors.sol +0 -11
  69. package/test/CoinDopplerUniV3.t.sol +0 -310
@@ -1,29 +0,0 @@
1
- [
2
- {
3
- "type": "function",
4
- "name": "IS_SCRIPT",
5
- "inputs": [],
6
- "outputs": [
7
- {
8
- "name": "",
9
- "type": "bool",
10
- "internalType": "bool"
11
- }
12
- ],
13
- "stateMutability": "view"
14
- },
15
- {
16
- "type": "function",
17
- "name": "run",
18
- "inputs": [],
19
- "outputs": [],
20
- "stateMutability": "nonpayable"
21
- },
22
- {
23
- "type": "function",
24
- "name": "setUp",
25
- "inputs": [],
26
- "outputs": [],
27
- "stateMutability": "nonpayable"
28
- }
29
- ]
@@ -1,12 +0,0 @@
1
- [
2
- {
3
- "type": "error",
4
- "name": "AddressZero",
5
- "inputs": []
6
- },
7
- {
8
- "type": "error",
9
- "name": "InvalidPoolVersion",
10
- "inputs": []
11
- }
12
- ]
@@ -1,32 +0,0 @@
1
- [
2
- {
3
- "type": "error",
4
- "name": "InvalidCurrency",
5
- "inputs": []
6
- },
7
- {
8
- "type": "error",
9
- "name": "InvalidPoolAddress",
10
- "inputs": []
11
- },
12
- {
13
- "type": "error",
14
- "name": "InvalidTickLower",
15
- "inputs": []
16
- },
17
- {
18
- "type": "error",
19
- "name": "InvalidTickUpper",
20
- "inputs": []
21
- },
22
- {
23
- "type": "error",
24
- "name": "InvalidUniswapV3Factory",
25
- "inputs": []
26
- },
27
- {
28
- "type": "error",
29
- "name": "InvalidWeth",
30
- "inputs": []
31
- }
32
- ]
@@ -1,59 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.13;
3
-
4
- import {Script, console} from "forge-std/Script.sol";
5
-
6
- import {Coin} from "../src/Coin.sol";
7
- import {CoinConstants} from "../src/libs/CoinConstants.sol";
8
- import {ZoraFactoryImpl} from "../src/ZoraFactoryImpl.sol";
9
- import {ZoraFactory} from "../src/proxy/ZoraFactory.sol";
10
-
11
- /// @dev For simulating pre-buys -- eg `forge script script/Simulate.s.sol --private-key $DEPLOYER_PK --rpc-url $BASE_MAINNET_RPC_URL -vvvv`
12
- contract Simulate is Script {
13
- // https://basescan.org/address/0x02B2705500096Ff83F9eF78873ca5DFB06C00Ddc
14
- address internal constant TEST_ZORA_FACTORY_ADDRESS_BASE_MAINNET = 0x02B2705500096Ff83F9eF78873ca5DFB06C00Ddc;
15
- address internal constant WETH_ADDRESS = 0x4200000000000000000000000000000000000006;
16
-
17
- ZoraFactoryImpl internal factory;
18
- Coin internal coin;
19
-
20
- function setUp() public {
21
- factory = ZoraFactoryImpl(TEST_ZORA_FACTORY_ADDRESS_BASE_MAINNET);
22
- }
23
-
24
- function run() public {
25
- vm.startBroadcast();
26
-
27
- // Filler
28
- address payoutAddress = 0x12125c8a52B8E4ed1A28e1f964023b4477f11300;
29
- address[] memory owners = new address[](1);
30
- owners[0] = 0x12125c8a52B8E4ed1A28e1f964023b4477f11300;
31
- string memory uri = "ipfs://bafybeigxwyzkb5rg2tcur4abyaeps56c4vcxytnz7ktrg3nr5dkgrgje7a";
32
- string memory name = "testcoin";
33
- string memory symbol = "testcoin";
34
-
35
- // Pool config
36
- int24 tickLower = -163600; // Starting price * 1B = Starting mcap
37
- int24 tickUpper = -170000; // Price when tail position liquidity is entered
38
- uint16 numDisoveryPositions = 99; // More positions = smoother price curve to tickUpper but higher gas cost
39
- uint256 maxDiscoverySupplyShare = 0.1e18; // Pct of supply to allocate equally across `numDisoveryPositions` between `tickLower` and `tickUpper` above
40
-
41
- bytes memory poolConfig = _generatePoolConfig(WETH_ADDRESS, tickLower, tickUpper, numDisoveryPositions, maxDiscoverySupplyShare);
42
-
43
- // Prebuy order size
44
- uint256 orderSize = 0.000111 ether;
45
- factory.deploy{value: orderSize}(payoutAddress, owners, uri, name, symbol, poolConfig, payoutAddress, orderSize);
46
-
47
- vm.stopBroadcast();
48
- }
49
-
50
- function _generatePoolConfig(
51
- address currency_,
52
- int24 tickLower_,
53
- int24 tickUpper_,
54
- uint16 numDiscoveryPositions_,
55
- uint256 maxDiscoverySupplyShare_
56
- ) internal pure returns (bytes memory) {
57
- return abi.encode(currency_, tickLower_, tickUpper_, numDiscoveryPositions_, maxDiscoverySupplyShare_);
58
- }
59
- }
@@ -1,143 +0,0 @@
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, PoolKey, Currency, IHooks} from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
11
-
12
- import {BaseCoin} from "./BaseCoin.sol";
13
- import {ICoinV4, IHasPoolKey, IHasSwapPath} from "./interfaces/ICoinV4.sol";
14
- import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
15
- import {PoolConfiguration} from "./types/PoolConfiguration.sol";
16
- import {UniV4SwapToCurrency} from "./libs/UniV4SwapToCurrency.sol";
17
- import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
18
- import {IDeployedCoinVersionLookup} from "./interfaces/IDeployedCoinVersionLookup.sol";
19
- import {CoinConstants} from "./libs/CoinConstants.sol";
20
- import {IUpgradeableV4Hook} from "./interfaces/IUpgradeableV4Hook.sol";
21
- import {CoinCommon} from "./libs/CoinCommon.sol";
22
-
23
- /**
24
- * @title BaseCoinV4
25
- * @notice Abstract base contract for Uniswap V4 integrated coins
26
- * @dev Provides shared V4 functionality for both content coins and creator coins
27
- */
28
- abstract contract BaseCoinV4 is BaseCoin, ICoinV4 {
29
- /// @notice The Uniswap v4 pool manager singleton contract reference.
30
- IPoolManager public immutable poolManager;
31
-
32
- /// @notice The pool key for the coin. Type from Uniswap V4 core.
33
- PoolKey internal poolKey;
34
-
35
- /// @notice The configuration for the pool.
36
- PoolConfiguration internal poolConfiguration;
37
-
38
- /// @notice The constructor for the static BaseCoinV4 contract deployment shared across all Coins.
39
- /// @dev All arguments are required and cannot be set to the 0 address.
40
- /// @param protocolRewardRecipient_ The address of the protocol reward recipient
41
- /// @param protocolRewards_ The address of the protocol rewards contract
42
- /// @param poolManager_ The address of the pool manager
43
- /// @param airlock_ The address of the Airlock contract, ownership is used for a protocol fee split.
44
- /// @notice Returns the pool key for the coin
45
- constructor(
46
- address protocolRewardRecipient_,
47
- address protocolRewards_,
48
- IPoolManager poolManager_,
49
- address airlock_
50
- ) BaseCoin(protocolRewardRecipient_, protocolRewards_, airlock_) {
51
- if (address(poolManager_) == address(0)) {
52
- revert AddressZero();
53
- }
54
-
55
- poolManager = poolManager_;
56
- }
57
-
58
- /// @inheritdoc IHasPoolKey
59
- function getPoolKey() public view returns (PoolKey memory) {
60
- return poolKey;
61
- }
62
-
63
- /// @inheritdoc ICoinV4
64
- function getPoolConfiguration() public view returns (PoolConfiguration memory) {
65
- return poolConfiguration;
66
- }
67
-
68
- /// @inheritdoc ICoinV4
69
- function initialize(
70
- address payoutRecipient_,
71
- address[] memory owners_,
72
- string memory tokenURI_,
73
- string memory name_,
74
- string memory symbol_,
75
- address platformReferrer_,
76
- address currency_,
77
- PoolKey memory poolKey_,
78
- uint160 sqrtPriceX96,
79
- PoolConfiguration memory poolConfiguration_
80
- ) public virtual initializer {
81
- currency = currency_;
82
- // we need to set this before initialization, because
83
- // distributing currency relies on the poolkey being set since the hooks
84
- // are retrieved from there
85
- poolKey = poolKey_;
86
- poolConfiguration = poolConfiguration_;
87
-
88
- super._initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
89
-
90
- // initialize the pool - the hook will mint its positions in the afterInitialize callback
91
- poolManager.initialize(poolKey, sqrtPriceX96);
92
- }
93
-
94
- /// @inheritdoc ICoinV4
95
- function hooks() external view returns (IHooks) {
96
- return poolKey.hooks;
97
- }
98
-
99
- /// @notice Migrate liquidity from current hook to a new hook implementation
100
- /// @param newHook Address of the new hook implementation
101
- /// @param additionalData Additional data to pass to the new hook during initialization
102
- function migrateLiquidity(address newHook, bytes calldata additionalData) external onlyOwner returns (PoolKey memory newPoolKey) {
103
- newPoolKey = IUpgradeableV4Hook(address(poolKey.hooks)).migrateLiquidity(newHook, poolKey, additionalData);
104
-
105
- emit LiquidityMigrated(poolKey, CoinCommon.hashPoolKey(poolKey), newPoolKey, CoinCommon.hashPoolKey(newPoolKey));
106
-
107
- poolKey = newPoolKey;
108
- }
109
-
110
- function supportsInterface(bytes4 interfaceId) public view virtual override(BaseCoin, IERC165) returns (bool) {
111
- return super.supportsInterface(interfaceId) || interfaceId == type(IHasPoolKey).interfaceId || type(IHasSwapPath).interfaceId == interfaceId;
112
- }
113
-
114
- /// @inheritdoc IHasSwapPath
115
- function getPayoutSwapPath(IDeployedCoinVersionLookup coinVersionLookup) external view returns (IHasSwapPath.PayoutSwapPath memory payoutSwapPath) {
116
- // if to swap in is this currency,
117
- // if backing currency is a coin, then recursively get the path from the coin
118
- payoutSwapPath.currencyIn = Currency.wrap(address(this));
119
-
120
- // swap to backing currency
121
- PathKey memory thisPathKey = PathKey({
122
- intermediateCurrency: Currency.wrap(currency),
123
- fee: poolKey.fee,
124
- tickSpacing: poolKey.tickSpacing,
125
- hooks: poolKey.hooks,
126
- hookData: ""
127
- });
128
-
129
- // get backing currency swap path - if the backing currency is a v4 coin and has a swap path.
130
- PathKey[] memory subPath = UniV4SwapToCurrency.getSubSwapPath(currency, coinVersionLookup);
131
-
132
- if (subPath.length > 0) {
133
- payoutSwapPath.path = new PathKey[](1 + subPath.length);
134
- payoutSwapPath.path[0] = thisPathKey;
135
- for (uint256 i = 0; i < subPath.length; i++) {
136
- payoutSwapPath.path[i + 1] = subPath[i];
137
- }
138
- } else {
139
- payoutSwapPath.path = new PathKey[](1);
140
- payoutSwapPath.path[0] = thisPathKey;
141
- }
142
- }
143
- }
package/src/Coin.sol DELETED
@@ -1,236 +0,0 @@
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 {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
11
- import {ICoin, PoolConfiguration} from "./interfaces/ICoin.sol";
12
- import {IUniswapV3Factory} from "./interfaces/IUniswapV3Factory.sol";
13
- import {IUniswapV3Pool} from "./interfaces/IUniswapV3Pool.sol";
14
- import {ISwapRouter} from "./interfaces/ISwapRouter.sol";
15
- import {IAirlock} from "./interfaces/IAirlock.sol";
16
- import {IProtocolRewards} from "./interfaces/IProtocolRewards.sol";
17
- import {IWETH} from "./interfaces/IWETH.sol";
18
-
19
- import {Address} from "@openzeppelin/contracts/utils/Address.sol";
20
- import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
21
- import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
22
- import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
23
- import {ContractVersionBase} from "./version/ContractVersionBase.sol";
24
- import {MultiOwnable} from "./utils/MultiOwnable.sol";
25
- import {CoinConstants} from "./libs/CoinConstants.sol";
26
- import {MarketConstants} from "./libs/MarketConstants.sol";
27
- import {LpPosition} from "./types/LpPosition.sol";
28
- import {PoolState} from "./types/PoolState.sol";
29
- import {CoinSetupV3, UniV3Config, CoinV3Config} from "./libs/CoinSetupV3.sol";
30
- import {UniV3BuySell, CoinConfig, SellResult} from "./libs/UniV3BuySell.sol";
31
- import {BaseCoin} from "./BaseCoin.sol";
32
- import {ICoinV3} from "./interfaces/ICoinV3.sol";
33
-
34
- /*
35
- $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
36
- $$ __$$\ $$ __$$\ \_$$ _|$$$\ $$ |
37
- $$ / \__|$$ / $$ | $$ | $$$$\ $$ |
38
- $$ | $$ | $$ | $$ | $$ $$\$$ |
39
- $$ | $$ | $$ | $$ | $$ \$$$$ |
40
- $$ | $$\ $$ | $$ | $$ | $$ |\$$$ |
41
- \$$$$$$ | $$$$$$ |$$$$$$\ $$ | \$$ |
42
- \______/ \______/ \______|\__| \__|
43
- */
44
- contract Coin is BaseCoin, ICoinV3 {
45
- using SafeERC20 for IERC20;
46
-
47
- address public immutable v3Factory;
48
- /// @notice The address of the Uniswap V3 swap router
49
- address public immutable swapRouter;
50
- /// @notice The address of the Uniswap V3 pool
51
- address public poolAddress;
52
-
53
- /// @notice The state of the market
54
- bytes public market;
55
- uint8 public marketVersion;
56
-
57
- /// @notice The address of the WETH contract
58
- address public immutable WETH;
59
-
60
- /// @notice deprecated
61
- PoolConfiguration public poolConfiguration;
62
-
63
- LpPosition[] public positions;
64
-
65
- /**
66
- * @notice The constructor for the static Coin contract deployment shared across all Coins.
67
- * @param protocolRewardRecipient_ The address of the protocol reward recipient
68
- * @param protocolRewards_ The address of the protocol rewards contract
69
- * @param weth_ The address of the WETH contract
70
- * @param v3Factory_ The address of the Uniswap V3 factory
71
- * @param swapRouter_ The address of the Uniswap V3 swap router
72
- * @param airlock_ The address of the Airlock contract, ownership is used for a protocol fee split.
73
- */
74
- constructor(
75
- address protocolRewardRecipient_,
76
- address protocolRewards_,
77
- address weth_,
78
- address v3Factory_,
79
- address swapRouter_,
80
- address airlock_
81
- ) BaseCoin(protocolRewardRecipient_, protocolRewards_, airlock_) initializer {
82
- if (v3Factory_ == address(0)) {
83
- revert AddressZero();
84
- }
85
- if (swapRouter_ == address(0)) {
86
- revert AddressZero();
87
- }
88
- if (airlock_ == address(0)) {
89
- revert AddressZero();
90
- }
91
- if (weth_ == address(0)) {
92
- revert AddressZero();
93
- }
94
- swapRouter = swapRouter_;
95
- v3Factory = v3Factory_;
96
-
97
- WETH = weth_;
98
- }
99
-
100
- /// @inheritdoc ICoinV3
101
- function initialize(
102
- address payoutRecipient_,
103
- address[] memory owners_,
104
- string memory tokenURI_,
105
- string memory name_,
106
- string memory symbol_,
107
- address platformReferrer_,
108
- address currency_,
109
- address poolAddress_,
110
- PoolConfiguration memory poolConfiguration_,
111
- LpPosition[] memory positions_
112
- ) public initializer {
113
- super._initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
114
-
115
- currency = currency_;
116
- poolAddress = poolAddress_;
117
- poolConfiguration = poolConfiguration_;
118
- positions = positions_;
119
-
120
- CoinSetupV3.deployLiquidity(positions_, poolAddress);
121
- }
122
-
123
- function buildConfig() internal view returns (CoinConfig memory coinConfig) {
124
- coinConfig = CoinConfig({
125
- protocolRewardRecipient: protocolRewardRecipient,
126
- platformReferrer: platformReferrer,
127
- payoutRecipient: payoutRecipient,
128
- protocolRewards: protocolRewards
129
- });
130
- }
131
-
132
- function getPoolConfiguration() public view returns (PoolConfiguration memory) {
133
- return poolConfiguration;
134
- }
135
-
136
- /// @notice Executes a buy order
137
- /// @param recipient The recipient address of the coins
138
- /// @param orderSize The amount of coins to buy
139
- /// @param tradeReferrer The address of the trade referrer
140
- /// @param sqrtPriceLimitX96 The price limit for Uniswap V3 pool swap
141
- function buy(
142
- address recipient,
143
- uint256 orderSize,
144
- uint256 minAmountOut,
145
- uint160 sqrtPriceLimitX96,
146
- address tradeReferrer
147
- ) public payable nonReentrant returns (uint256, uint256) {
148
- CoinConfig memory coinConfig = buildConfig();
149
- (uint256 amountOut, uint256 tradeReward, uint256 trueOrderSize) = UniV3BuySell.handleBuy(
150
- recipient,
151
- orderSize,
152
- minAmountOut,
153
- sqrtPriceLimitX96,
154
- tradeReferrer,
155
- coinConfig,
156
- currency,
157
- ISwapRouter(swapRouter),
158
- IWETH(WETH)
159
- );
160
-
161
- UniV3BuySell.handleMarketRewards(coinConfig, currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
162
-
163
- emit CoinBuy(msg.sender, recipient, tradeReferrer, amountOut, currency, tradeReward, trueOrderSize);
164
-
165
- return (orderSize, amountOut);
166
- }
167
-
168
- /// @notice Executes a sell order
169
- /// @param recipient The recipient of the currency
170
- /// @param orderSize The amount of coins to sell
171
- /// @param minAmountOut The minimum amount of currency to receive
172
- /// @param sqrtPriceLimitX96 The price limit for the swap
173
- /// @param tradeReferrer The address of the trade referrer
174
- function sell(
175
- address recipient,
176
- uint256 orderSize,
177
- uint256 minAmountOut,
178
- uint160 sqrtPriceLimitX96,
179
- address tradeReferrer
180
- ) public nonReentrant returns (uint256, uint256) {
181
- // Record the coin balance of this contract before the swap
182
- uint256 beforeCoinBalance = balanceOf(address(this));
183
-
184
- // Transfer the coins from the seller to this contract
185
- transfer(address(this), orderSize);
186
-
187
- // Approve the Uniswap V3 swap router
188
- this.approve(swapRouter, orderSize);
189
-
190
- CoinConfig memory coinConfig = buildConfig();
191
-
192
- SellResult memory result = UniV3BuySell.handleSell(
193
- recipient,
194
- beforeCoinBalance,
195
- orderSize,
196
- minAmountOut,
197
- sqrtPriceLimitX96,
198
- tradeReferrer,
199
- coinConfig,
200
- currency,
201
- ISwapRouter(swapRouter),
202
- IWETH(WETH)
203
- );
204
-
205
- UniV3BuySell.handleMarketRewards(coinConfig, currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
206
-
207
- emit ICoin.CoinSell(msg.sender, recipient, tradeReferrer, result.trueOrderSize, currency, result.tradeReward, result.payoutSize);
208
-
209
- return (result.trueOrderSize, result.payoutSize);
210
- }
211
-
212
- /// @notice Force claim any accrued secondary rewards from the market's liquidity position.
213
- /// @dev This function is a fallback, secondary rewards will be claimed automatically on each buy and sell.
214
- /// @param pushEthRewards Whether to push the ETH directly to the recipients.
215
- function claimSecondaryRewards(bool pushEthRewards) external nonReentrant {
216
- MarketRewards memory rewards = UniV3BuySell.handleMarketRewards(buildConfig(), currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
217
-
218
- if (pushEthRewards && rewards.totalAmountCurrency > 0 && currency == WETH) {
219
- IProtocolRewards(protocolRewards).withdrawFor(payoutRecipient, rewards.creatorPayoutAmountCurrency);
220
- IProtocolRewards(protocolRewards).withdrawFor(platformReferrer, rewards.platformReferrerAmountCurrency);
221
- IProtocolRewards(protocolRewards).withdrawFor(protocolRewardRecipient, rewards.protocolAmountCurrency);
222
- }
223
- }
224
-
225
- /// @dev Called by the pool after minting liquidity to transfer the associated coins
226
- function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata) external {
227
- if (msg.sender != poolAddress) revert OnlyPool(msg.sender, poolAddress);
228
-
229
- IERC20(address(this)).safeTransfer(poolAddress, amount0Owed == 0 ? amount1Owed : amount0Owed);
230
- }
231
-
232
- /// @notice Receives ETH converted from WETH
233
- receive() external payable {
234
- require(msg.sender == WETH, OnlyWeth());
235
- }
236
- }
@@ -1,74 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- import {ICoin} from "./ICoin.sol";
5
- import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
6
- import {PoolConfiguration} from "../types/PoolConfiguration.sol";
7
- import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
8
- import {PathKey} from "@uniswap/v4-periphery/src/libraries/PathKey.sol";
9
- import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
10
- import {IDeployedCoinVersionLookup} from "./IDeployedCoinVersionLookup.sol";
11
-
12
- /// @notice Returns the pool key for the coin
13
- interface IHasPoolKey {
14
- /// @notice Returns the Uniswap V4 pool key associated with this coin
15
- /// @return The PoolKey struct containing pool identification parameters
16
- function getPoolKey() external view returns (PoolKey memory);
17
- }
18
-
19
- /// @notice Returns the pool configuration for the coin
20
- interface IHasSwapPath {
21
- /// @notice Struct containing the swap path configuration for converting fees to payout currency
22
- /// @param path Array of PathKey structs defining the multi-hop swap route
23
- /// @param currencyIn The input currency to start the swap path from
24
- struct PayoutSwapPath {
25
- PathKey[] path;
26
- Currency currencyIn;
27
- }
28
-
29
- /// @notice Returns the swap path configuration for converting this coin to its final payout currency
30
- /// @dev This enables multi-hop swaps through intermediate currencies to reach the target payout token
31
- /// @param coinVersionLookup Contract for looking up deployed coin versions to build recursive paths
32
- /// @return PayoutSwapPath struct containing the complete swap route configuration
33
- function getPayoutSwapPath(IDeployedCoinVersionLookup coinVersionLookup) external view returns (PayoutSwapPath memory);
34
- }
35
-
36
- interface ICoinV4 is ICoin, IHasPoolKey, IHasSwapPath {
37
- /// @notice Returns the pool configuration settings for this coin's Uniswap V4 pool
38
- /// @return PoolConfiguration struct containing pool-specific settings and parameters
39
- function getPoolConfiguration() external view returns (PoolConfiguration memory);
40
-
41
- /// @notice Emitted when a hook is upgraded
42
- /// @param fromPoolKey The pool key being upgraded
43
- /// @param toPoolKey The new pool key returned from the destination hook
44
- event LiquidityMigrated(PoolKey fromPoolKey, bytes32 fromPoolKeyHash, PoolKey toPoolKey, bytes32 toPoolKeyHash);
45
-
46
- /// @notice Returns the hooks contract used by this coin's Uniswap V4 pool
47
- /// @return The IHooks contract interface that handles pool lifecycle events
48
- function hooks() external view returns (IHooks);
49
-
50
- /// @notice Initializes the coin
51
- /// @dev Called by the factory contract when the contract is deployed.
52
- /// @param payoutRecipient_ The address of the payout recipient. Can be updated by the owner. Cannot be 0 address.
53
- /// @param owners_ The addresses of the owners. All owners have the same full admin access. Cannot be 0 address.
54
- /// @param tokenURI_ The URI of the token. Can be updated by the owner.
55
- /// @param name_ The name of the token. Cannot be updated.
56
- /// @param symbol_ The symbol of the token. Cannot be updated.
57
- /// @param platformReferrer_ The address of the platform referrer. Cannot be updated.
58
- /// @param currency_ The currency of the coin. Cannot be updated. Can be the zero address for ETH.
59
- /// @param poolKey_ The pool key for the coin. Derived in the factory.
60
- /// @param sqrtPriceX96 The initial sqrt price for the pool
61
- /// @param poolConfiguration_ The configuration for the pool
62
- function initialize(
63
- address payoutRecipient_,
64
- address[] memory owners_,
65
- string memory tokenURI_,
66
- string memory name_,
67
- string memory symbol_,
68
- address platformReferrer_,
69
- address currency_,
70
- PoolKey memory poolKey_,
71
- uint160 sqrtPriceX96,
72
- PoolConfiguration memory poolConfiguration_
73
- ) external;
74
- }
@@ -1,50 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- import {TickMath} from "../utils/uniswap/TickMath.sol";
5
- import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
6
- import {ICoin} from "../interfaces/ICoin.sol";
7
- import {LpPosition} from "../types/LpPosition.sol";
8
- import {MarketConstants} from "./MarketConstants.sol";
9
- import {FullMath} from "../utils/uniswap/FullMath.sol";
10
- import {SqrtPriceMath} from "../utils/uniswap/SqrtPriceMath.sol";
11
- import {LiquidityAmounts} from "../utils/uniswap/LiquidityAmounts.sol";
12
- import {IDopplerErrors} from "../interfaces/IDopplerErrors.sol";
13
- import {DopplerMath} from "./DopplerMath.sol";
14
- import {PoolConfiguration} from "../types/PoolConfiguration.sol";
15
-
16
- library CoinDopplerUniV3 {
17
- function setupPool(bool isCoinToken0, bytes memory poolConfig_) internal pure returns (uint160 sqrtPriceX96, PoolConfiguration memory poolConfiguration) {
18
- (, , int24 tickLower_, int24 tickUpper_, uint16 numDiscoveryPositions_, uint256 maxDiscoverySupplyShare_) = CoinConfigurationVersions
19
- .decodeDopplerUniV3(poolConfig_);
20
-
21
- require(numDiscoveryPositions_ > 1 && numDiscoveryPositions_ <= 200, IDopplerErrors.NumDiscoveryPositionsOutOfRange());
22
-
23
- if (maxDiscoverySupplyShare_ > MarketConstants.WAD) {
24
- revert IDopplerErrors.MaxShareToBeSoldExceeded(maxDiscoverySupplyShare_, MarketConstants.WAD);
25
- }
26
-
27
- uint256[] memory maxDiscoverySupplyShare = new uint256[](1);
28
- uint16[] memory numDiscoveryPositions = new uint16[](1);
29
- int24[] memory savedTickLower = new int24[](1);
30
- int24[] memory savedTickUpper = new int24[](1);
31
-
32
- maxDiscoverySupplyShare[0] = maxDiscoverySupplyShare_;
33
- numDiscoveryPositions[0] = numDiscoveryPositions_;
34
- savedTickLower[0] = isCoinToken0 ? tickLower_ : -tickUpper_;
35
- savedTickUpper[0] = isCoinToken0 ? tickUpper_ : -tickLower_;
36
-
37
- sqrtPriceX96 = TickMath.getSqrtPriceAtTick(isCoinToken0 ? savedTickLower[0] : savedTickUpper[0]);
38
-
39
- poolConfiguration = PoolConfiguration({
40
- version: CoinConfigurationVersions.DOPPLER_UNI_V3_POOL_VERSION,
41
- fee: MarketConstants.LP_FEE,
42
- tickSpacing: MarketConstants.TICK_SPACING,
43
- tickLower: savedTickLower,
44
- tickUpper: savedTickUpper,
45
- numPositions: numDiscoveryPositions_ + 1, // Add one for the final tail position
46
- maxDiscoverySupplyShare: maxDiscoverySupplyShare,
47
- numDiscoveryPositions: numDiscoveryPositions
48
- });
49
- }
50
- }