@zoralabs/coins 2.0.0 → 2.1.1

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 (72) hide show
  1. package/.turbo/turbo-build.log +107 -114
  2. package/CHANGELOG.md +34 -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/foundry.toml +1 -3
  21. package/package/wagmiGenerated.ts +240 -269
  22. package/package.json +3 -3
  23. package/script/DeployPostDeploymentHooks.s.sol +2 -2
  24. package/script/TestBackingCoinSwap.s.sol +8 -8
  25. package/script/TestV4Swap.s.sol +8 -8
  26. package/script/UpgradeFactoryImpl.s.sol +0 -1
  27. package/src/BaseCoin.sol +111 -7
  28. package/src/ContentCoin.sol +4 -4
  29. package/src/CreatorCoin.sol +5 -5
  30. package/src/ZoraFactoryImpl.sol +10 -93
  31. package/src/deployment/CoinsDeployerBase.sol +10 -27
  32. package/src/hooks/BaseZoraV4CoinHook.sol +5 -5
  33. package/src/hooks/ContentCoinHook.sol +2 -2
  34. package/src/hooks/deployment/BuySupplyWithSwapRouterHook.sol +4 -5
  35. package/src/interfaces/ICoin.sol +67 -1
  36. package/src/interfaces/ICreatorCoin.sol +2 -2
  37. package/src/interfaces/IZoraFactory.sol +0 -5
  38. package/src/libs/CoinConfigurationVersions.sol +1 -39
  39. package/src/libs/CoinRewardsV4.sol +2 -2
  40. package/src/libs/CoinSetup.sol +1 -4
  41. package/src/libs/MarketConstants.sol +0 -4
  42. package/src/libs/UniV4SwapHelper.sol +1 -1
  43. package/src/libs/UniV4SwapToCurrency.sol +2 -2
  44. package/src/libs/V4Liquidity.sol +1 -1
  45. package/src/version/ContractVersionBase.sol +1 -1
  46. package/test/Coin.t.sol +112 -535
  47. package/test/CoinUniV4.t.sol +7 -7
  48. package/test/DeploymentHooks.t.sol +5 -102
  49. package/test/Factory.t.sol +23 -306
  50. package/test/LiquidityMigration.t.sol +160 -2
  51. package/test/MultiOwnable.t.sol +36 -36
  52. package/test/Upgrades.t.sol +16 -35
  53. package/test/utils/BaseTest.sol +16 -69
  54. package/test/utils/FeeEstimatorHook.sol +3 -3
  55. package/wagmi.config.ts +1 -1
  56. package/abis/BaseCoinV4.json +0 -1840
  57. package/abis/Coin.json +0 -1912
  58. package/abis/DopplerUniswapV3Test.json +0 -800
  59. package/abis/ICoinV4.json +0 -1048
  60. package/abis/Simulate.json +0 -29
  61. package/abis/UniV3BuySell.json +0 -12
  62. package/abis/UniV3Errors.json +0 -32
  63. package/script/Simulate.s.sol +0 -59
  64. package/src/BaseCoinV4.sol +0 -143
  65. package/src/Coin.sol +0 -236
  66. package/src/interfaces/ICoinV4.sol +0 -74
  67. package/src/libs/CoinDopplerUniV3.sol +0 -50
  68. package/src/libs/CoinRewards.sol +0 -201
  69. package/src/libs/CoinSetupV3.sol +0 -50
  70. package/src/libs/UniV3BuySell.sol +0 -231
  71. package/src/libs/UniV3Errors.sol +0 -11
  72. package/test/CoinDopplerUniV3.t.sol +0 -310
@@ -1,201 +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 {Address} from "@openzeppelin/contracts/utils/Address.sol";
12
- import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
13
- import {IProtocolRewards} from "../interfaces/IProtocolRewards.sol";
14
- import {ICoin} from "../interfaces/ICoin.sol";
15
- import {CoinConstants} from "./CoinConstants.sol";
16
- import {IWETH} from "../interfaces/IWETH.sol";
17
-
18
- struct CoinConfig {
19
- address protocolRewardRecipient;
20
- address platformReferrer;
21
- address payoutRecipient;
22
- address protocolRewards;
23
- }
24
-
25
- library CoinRewards {
26
- using SafeERC20 for IERC20;
27
-
28
- /// @dev Handles sending ETH and ERC20 payouts and refunds to recipients
29
- /// @param orderPayout The amount of currency to pay out
30
- /// @param recipient The address to receive the payout
31
- function handlePayout(uint256 orderPayout, address recipient, address currency, address weth) internal {
32
- if (currency == weth) {
33
- Address.sendValue(payable(recipient), orderPayout);
34
- } else {
35
- IERC20(currency).safeTransfer(recipient, orderPayout);
36
- }
37
- }
38
-
39
- /// @dev Handles calculating and depositing fees to an escrow protocol rewards contract
40
- function handleTradeRewards(uint256 totalValue, address _tradeReferrer, CoinConfig memory coinConfig, address currency, IWETH weth) internal {
41
- address protocolRewardRecipient = coinConfig.protocolRewardRecipient;
42
- address platformReferrer = coinConfig.platformReferrer;
43
- address payoutRecipient = coinConfig.payoutRecipient;
44
- IProtocolRewards protocolRewards = IProtocolRewards(coinConfig.protocolRewards);
45
-
46
- if (_tradeReferrer == address(0)) {
47
- _tradeReferrer = protocolRewardRecipient;
48
- }
49
-
50
- uint256 tokenCreatorFee = calculateReward(totalValue, CoinConstants.TOKEN_CREATOR_FEE_BPS);
51
- uint256 platformReferrerFee = calculateReward(totalValue, CoinConstants.PLATFORM_REFERRER_FEE_BPS);
52
- uint256 tradeReferrerFee = calculateReward(totalValue, CoinConstants.TRADE_REFERRER_FEE_BPS);
53
- uint256 protocolFee = totalValue - tokenCreatorFee - platformReferrerFee - tradeReferrerFee;
54
-
55
- if (currency == address(weth)) {
56
- address[] memory recipients = new address[](4);
57
- uint256[] memory amounts = new uint256[](4);
58
- bytes4[] memory reasons = new bytes4[](4);
59
-
60
- recipients[0] = payoutRecipient;
61
- amounts[0] = tokenCreatorFee;
62
- reasons[0] = bytes4(keccak256("COIN_CREATOR_REWARD"));
63
-
64
- recipients[1] = platformReferrer;
65
- amounts[1] = platformReferrerFee;
66
- reasons[1] = bytes4(keccak256("COIN_PLATFORM_REFERRER_REWARD"));
67
-
68
- recipients[2] = _tradeReferrer;
69
- amounts[2] = tradeReferrerFee;
70
- reasons[2] = bytes4(keccak256("COIN_TRADE_REFERRER_REWARD"));
71
-
72
- recipients[3] = protocolRewardRecipient;
73
- amounts[3] = protocolFee;
74
- reasons[3] = bytes4(keccak256("COIN_PROTOCOL_REWARD"));
75
-
76
- IProtocolRewards(protocolRewards).depositBatch{value: totalValue}(recipients, amounts, reasons, "");
77
- }
78
-
79
- if (currency != address(weth)) {
80
- IERC20(currency).safeTransfer(payoutRecipient, tokenCreatorFee);
81
- IERC20(currency).safeTransfer(platformReferrer, platformReferrerFee);
82
- IERC20(currency).safeTransfer(_tradeReferrer, tradeReferrerFee);
83
- IERC20(currency).safeTransfer(protocolRewardRecipient, protocolFee);
84
- }
85
-
86
- emit ICoin.CoinTradeRewards(
87
- payoutRecipient,
88
- platformReferrer,
89
- _tradeReferrer,
90
- protocolRewardRecipient,
91
- tokenCreatorFee,
92
- platformReferrerFee,
93
- tradeReferrerFee,
94
- protocolFee,
95
- currency
96
- );
97
- }
98
-
99
- function calculateReward(uint256 amount, uint256 bps) internal pure returns (uint256) {
100
- return (amount * bps) / 10_000;
101
- }
102
-
103
- function transferBothRewards(
104
- address token0,
105
- uint256 totalAmountToken0,
106
- address token1,
107
- uint256 totalAmountToken1,
108
- address coin,
109
- CoinConfig memory coinConfig,
110
- address currency,
111
- IWETH weth,
112
- address doppler
113
- ) internal returns (ICoin.MarketRewards memory rewards) {
114
- rewards = transferMarketRewards(token0, currency, totalAmountToken0, rewards, coin, coinConfig, weth, doppler);
115
- rewards = transferMarketRewards(token1, currency, totalAmountToken1, rewards, coin, coinConfig, weth, doppler);
116
- }
117
-
118
- struct Distribution {
119
- bool isCurrency;
120
- uint256 totalAmount;
121
- uint256 creatorPayout;
122
- uint256 platformReferrerPayout;
123
- uint256 protocolPayout;
124
- }
125
-
126
- function transferMarketRewards(
127
- address token,
128
- address currency,
129
- uint256 totalAmount,
130
- ICoin.MarketRewards memory rewards,
131
- address coin,
132
- CoinConfig memory coinConfig,
133
- IWETH weth,
134
- address dopplerRecipient
135
- ) internal returns (ICoin.MarketRewards memory) {
136
- address payoutRecipient = coinConfig.payoutRecipient;
137
- address platformReferrer = coinConfig.platformReferrer;
138
- address protocolRewardRecipient = coinConfig.protocolRewardRecipient;
139
- address protocolRewards = coinConfig.protocolRewards;
140
-
141
- if (totalAmount > 0) {
142
- uint256 dopplerPayout = calculateReward(totalAmount, CoinConstants.DOPPLER_MARKET_REWARD_BPS);
143
- uint256 creatorPayout = calculateReward(totalAmount, CoinConstants.CREATOR_MARKET_REWARD_BPS);
144
- uint256 platformReferrerPayout = calculateReward(totalAmount, CoinConstants.PLATFORM_REFERRER_MARKET_REWARD_BPS);
145
- uint256 protocolPayout = totalAmount - creatorPayout - platformReferrerPayout - dopplerPayout;
146
-
147
- bool isCurrency = token == currency;
148
-
149
- if (token == address(weth)) {
150
- IWETH(weth).withdraw(totalAmount);
151
-
152
- address[] memory recipients = new address[](4);
153
- recipients[0] = payoutRecipient;
154
- recipients[1] = platformReferrer;
155
- recipients[2] = protocolRewardRecipient;
156
- recipients[3] = dopplerRecipient;
157
-
158
- uint256[] memory amounts = new uint256[](4);
159
- amounts[0] = creatorPayout;
160
- amounts[1] = platformReferrerPayout;
161
- amounts[2] = protocolPayout;
162
- amounts[3] = dopplerPayout;
163
-
164
- bytes4[] memory reasons = new bytes4[](4);
165
- reasons[0] = bytes4(keccak256("COIN_CREATOR_MARKET_REWARD"));
166
- reasons[1] = bytes4(keccak256("COIN_PLATFORM_REFERRER_MARKET_REWARD"));
167
- reasons[2] = bytes4(keccak256("COIN_PROTOCOL_MARKET_REWARD"));
168
- reasons[3] = bytes4(keccak256("COIN_DOPPLER_MARKET_REWARD"));
169
-
170
- IProtocolRewards(protocolRewards).depositBatch{value: totalAmount}(recipients, amounts, reasons, "");
171
- IProtocolRewards(protocolRewards).withdrawFor(dopplerRecipient, dopplerPayout);
172
- } else {
173
- if (!isCurrency) {
174
- IERC20(coin).safeTransfer(payoutRecipient, creatorPayout);
175
- IERC20(coin).safeTransfer(platformReferrer, platformReferrerPayout);
176
- IERC20(coin).safeTransfer(protocolRewardRecipient, protocolPayout);
177
- IERC20(coin).safeTransfer(dopplerRecipient, dopplerPayout);
178
- } else {
179
- IERC20(currency).safeTransfer(payoutRecipient, creatorPayout);
180
- IERC20(currency).safeTransfer(platformReferrer, platformReferrerPayout);
181
- IERC20(currency).safeTransfer(protocolRewardRecipient, protocolPayout);
182
- IERC20(currency).safeTransfer(dopplerRecipient, dopplerPayout);
183
- }
184
- }
185
-
186
- if (isCurrency) {
187
- rewards.totalAmountCurrency = totalAmount;
188
- rewards.creatorPayoutAmountCurrency = creatorPayout;
189
- rewards.platformReferrerAmountCurrency = platformReferrerPayout;
190
- rewards.protocolAmountCurrency = protocolPayout;
191
- } else {
192
- rewards.totalAmountCoin = totalAmount;
193
- rewards.creatorPayoutAmountCoin = creatorPayout;
194
- rewards.platformReferrerAmountCoin = platformReferrerPayout;
195
- rewards.protocolAmountCoin = protocolPayout;
196
- }
197
- }
198
-
199
- return rewards;
200
- }
201
- }
@@ -1,50 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- import {PoolConfiguration} from "../interfaces/ICoin.sol";
5
- import {CoinDopplerUniV3} from "./CoinDopplerUniV3.sol";
6
- import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
7
- import {LpPosition} from "../types/LpPosition.sol";
8
- import {IUniswapV3Factory} from "../interfaces/IUniswapV3Factory.sol";
9
- import {MarketConstants} from "./MarketConstants.sol";
10
- import {IUniswapV3Pool} from "../interfaces/IUniswapV3Pool.sol";
11
- import {ICoin} from "../interfaces/ICoin.sol";
12
- import {CoinCommon} from "./CoinCommon.sol";
13
- struct UniV3Config {
14
- address weth;
15
- address v3Factory;
16
- address airlock;
17
- address swapRouter;
18
- }
19
-
20
- struct CoinV3Config {
21
- address currency;
22
- PoolConfiguration poolConfiguration;
23
- address poolAddress;
24
- }
25
-
26
- library CoinSetupV3 {
27
- /// @dev Deploys the Uniswap V3 pool and mints initial liquidity based on the pool configuration
28
- function deployLiquidity(LpPosition[] memory positions, address poolAddress) internal {
29
- // Calculate and mint positions
30
- _mintPositions(positions, poolAddress);
31
- }
32
-
33
- /// @dev Mints the calculated liquidity positions into the Uniswap V3 pool
34
- function _mintPositions(LpPosition[] memory lbpPositions, address poolAddress) internal {
35
- for (uint256 i; i < lbpPositions.length; i++) {
36
- IUniswapV3Pool(poolAddress).mint(address(this), lbpPositions[i].tickLower, lbpPositions[i].tickUpper, lbpPositions[i].liquidity, "");
37
- }
38
- }
39
-
40
- /// @dev Creates the Uniswap V3 pool for the coin/currency pair
41
- function createV3Pool(address coin, address currency, bool isCoinToken0, uint160 sqrtPriceX96, address v3Factory) internal returns (address pool) {
42
- address token0 = isCoinToken0 ? coin : currency;
43
- address token1 = isCoinToken0 ? currency : coin;
44
- pool = IUniswapV3Factory(v3Factory).createPool(token0, token1, MarketConstants.LP_FEE);
45
-
46
- // This pool should be new, if it has already been initialized
47
- // then we will fail the creation step prompting the user to try again.
48
- IUniswapV3Pool(pool).initialize(sqrtPriceX96);
49
- }
50
- }
@@ -1,231 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
- import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
6
- import {ISwapRouter} from "../interfaces/ISwapRouter.sol";
7
- import {IWETH} from "../interfaces/IWETH.sol";
8
- import {MarketConstants} from "./MarketConstants.sol";
9
- import {CoinConstants} from "./CoinConstants.sol";
10
- import {ICoin} from "../interfaces/ICoin.sol";
11
- import {IProtocolRewards} from "../interfaces/IProtocolRewards.sol";
12
- import {LpPosition} from "../types/LpPosition.sol";
13
- import {PoolConfiguration} from "../interfaces/ICoin.sol";
14
- import {IUniswapV3Pool} from "../interfaces/IUniswapV3Pool.sol";
15
- import {IAirlock} from "../interfaces/IAirlock.sol";
16
- import {CoinV3Config} from "./CoinSetupV3.sol";
17
- import {Address} from "@openzeppelin/contracts/utils/Address.sol";
18
- import {CoinDopplerUniV3} from "./CoinDopplerUniV3.sol";
19
- import {CoinConfigurationVersions} from "./CoinConfigurationVersions.sol";
20
- import {CoinRewards, CoinConfig} from "./CoinRewards.sol";
21
- struct SellResult {
22
- uint256 payoutSize;
23
- uint256 tradeReward;
24
- uint256 trueOrderSize;
25
- }
26
-
27
- library UniV3BuySell {
28
- using SafeERC20 for IERC20;
29
-
30
- error AddressZero();
31
- error InvalidPoolVersion();
32
-
33
- function handleBuy(
34
- address recipient,
35
- uint256 orderSize,
36
- uint256 minAmountOut,
37
- uint160 sqrtPriceLimitX96,
38
- address tradeReferrer,
39
- CoinConfig memory coinConfig,
40
- address currency,
41
- ISwapRouter swapRouter,
42
- IWETH weth
43
- ) internal returns (uint256 amountOut, uint256 tradeReward, uint256 trueOrderSize) {
44
- if (recipient == address(0)) {
45
- revert AddressZero();
46
- }
47
-
48
- // Calculate the trade reward
49
- tradeReward = _calculateReward(orderSize, CoinConstants.TOTAL_FEE_BPS);
50
-
51
- // Calculate the remaining size
52
- trueOrderSize = orderSize - tradeReward;
53
-
54
- // Handle incoming currency
55
- _handleIncomingCurrency(orderSize, trueOrderSize, currency, swapRouter, weth);
56
-
57
- // Set up the swap parameters
58
- ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
59
- tokenIn: currency,
60
- tokenOut: address(this),
61
- fee: MarketConstants.LP_FEE,
62
- recipient: recipient,
63
- amountIn: trueOrderSize,
64
- amountOutMinimum: minAmountOut,
65
- sqrtPriceLimitX96: sqrtPriceLimitX96
66
- });
67
-
68
- // Execute the swap
69
- amountOut = ISwapRouter(swapRouter).exactInputSingle(params);
70
-
71
- CoinRewards.handleTradeRewards(tradeReward, tradeReferrer, coinConfig, currency, weth);
72
- }
73
-
74
- function _executeSwap(
75
- uint256 orderSize,
76
- uint256 minAmountOut,
77
- uint160 sqrtPriceLimitX96,
78
- address currency,
79
- ISwapRouter swapRouter
80
- ) internal returns (uint256 amountOut) {
81
- ISwapRouter.ExactInputSingleParams memory params = ISwapRouter.ExactInputSingleParams({
82
- tokenIn: address(this),
83
- tokenOut: currency,
84
- fee: MarketConstants.LP_FEE,
85
- recipient: address(this),
86
- amountIn: orderSize,
87
- amountOutMinimum: minAmountOut,
88
- sqrtPriceLimitX96: sqrtPriceLimitX96
89
- });
90
-
91
- amountOut = swapRouter.exactInputSingle(params);
92
- }
93
-
94
- function _handleRefund(uint256 beforeCoinBalance, uint256 orderSize, address recipient) internal returns (uint256 trueOrderSize) {
95
- uint256 afterCoinBalance = IERC20(address(this)).balanceOf(address(this));
96
- trueOrderSize = orderSize;
97
-
98
- if (afterCoinBalance > beforeCoinBalance) {
99
- uint256 coinRefund = afterCoinBalance - beforeCoinBalance;
100
- trueOrderSize -= coinRefund;
101
- IERC20(address(this)).safeTransfer(recipient, coinRefund);
102
- }
103
- }
104
-
105
- function _handlePayoutAndRewards(
106
- uint256 amountOut,
107
- address recipient,
108
- address tradeReferrer,
109
- CoinConfig memory coinConfig,
110
- address currency,
111
- IWETH weth
112
- ) internal returns (uint256 payoutSize, uint256 tradeReward) {
113
- if (currency == address(weth)) {
114
- weth.withdraw(amountOut);
115
- }
116
-
117
- tradeReward = _calculateReward(amountOut, CoinConstants.TOTAL_FEE_BPS);
118
- payoutSize = amountOut - tradeReward;
119
-
120
- _handlePayout(payoutSize, recipient, currency, weth);
121
-
122
- CoinRewards.handleTradeRewards(tradeReward, tradeReferrer, coinConfig, currency, weth);
123
- }
124
-
125
- function handleSell(
126
- address recipient,
127
- uint256 beforeCoinBalance,
128
- uint256 orderSize,
129
- uint256 minAmountOut,
130
- uint160 sqrtPriceLimitX96,
131
- address tradeReferrer,
132
- CoinConfig memory coinConfig,
133
- address currency,
134
- ISwapRouter swapRouter,
135
- IWETH weth
136
- ) internal returns (SellResult memory result) {
137
- if (recipient == address(0)) {
138
- revert AddressZero();
139
- }
140
-
141
- uint256 amountOut = _executeSwap(orderSize, minAmountOut, sqrtPriceLimitX96, currency, swapRouter);
142
- result.trueOrderSize = _handleRefund(beforeCoinBalance, orderSize, recipient);
143
- (result.payoutSize, result.tradeReward) = _handlePayoutAndRewards(amountOut, recipient, tradeReferrer, coinConfig, currency, weth);
144
- }
145
-
146
- /// @dev Handles incoming currency transfers for buy orders; if WETH is the currency the caller has the option to send native-ETH
147
- /// @param orderSize The total size of the order in the currency
148
- /// @param trueOrderSize The actual amount being used for the swap after fees
149
- function _handleIncomingCurrency(uint256 orderSize, uint256 trueOrderSize, address currency, ISwapRouter swapRouter, IWETH weth) internal {
150
- if (currency == address(weth) && msg.value > 0) {
151
- if (msg.value != orderSize) {
152
- revert ICoin.EthAmountMismatch();
153
- }
154
-
155
- if (msg.value < CoinConstants.MIN_ORDER_SIZE) {
156
- revert ICoin.EthAmountTooSmall();
157
- }
158
-
159
- IWETH(weth).deposit{value: trueOrderSize}();
160
- IWETH(weth).approve(address(swapRouter), trueOrderSize);
161
- } else {
162
- // Ensure ETH is not sent with a non-ETH pair
163
- if (msg.value != 0) {
164
- revert ICoin.EthTransferInvalid();
165
- }
166
-
167
- uint256 beforeBalance = IERC20(currency).balanceOf(address(this));
168
- IERC20(currency).safeTransferFrom(msg.sender, address(this), orderSize);
169
- uint256 afterBalance = IERC20(currency).balanceOf(address(this));
170
-
171
- if ((afterBalance - beforeBalance) != orderSize) {
172
- revert ICoin.ERC20TransferAmountMismatch();
173
- }
174
-
175
- IERC20(currency).approve(address(swapRouter), trueOrderSize);
176
- }
177
- }
178
-
179
- /// @dev Handles sending ETH and ERC20 payouts and refunds to recipients
180
- /// @param orderPayout The amount of currency to pay out
181
- /// @param recipient The address to receive the payout
182
- function _handlePayout(uint256 orderPayout, address recipient, address currency, IWETH weth) internal {
183
- if (currency == address(weth)) {
184
- Address.sendValue(payable(recipient), orderPayout);
185
- } else {
186
- IERC20(currency).safeTransfer(recipient, orderPayout);
187
- }
188
- }
189
-
190
- function _collectFees(LpPosition[] storage positions, address poolAddress) internal returns (uint256 totalAmountToken0, uint256 totalAmountToken1) {
191
- for (uint256 i; i < positions.length; i++) {
192
- // Must burn to update the collect mapping on the pool
193
- IUniswapV3Pool(poolAddress).burn(positions[i].tickLower, positions[i].tickUpper, 0);
194
-
195
- (uint256 amount0, uint256 amount1) = IUniswapV3Pool(poolAddress).collect(
196
- address(this),
197
- positions[i].tickLower,
198
- positions[i].tickUpper,
199
- type(uint128).max,
200
- type(uint128).max
201
- );
202
-
203
- totalAmountToken0 += amount0;
204
- totalAmountToken1 += amount1;
205
- }
206
- }
207
-
208
- /// @dev Collects and distributes accrued fees from all LP positions
209
- function handleMarketRewards(
210
- CoinConfig memory coinConfig,
211
- address currency,
212
- address poolAddress,
213
- LpPosition[] storage positions,
214
- IWETH weth,
215
- address doppler
216
- ) internal returns (ICoin.MarketRewards memory rewards) {
217
- address coin = address(this);
218
- (uint256 totalAmountToken0, uint256 totalAmountToken1) = _collectFees(positions, poolAddress);
219
-
220
- address token0 = currency < coin ? currency : coin;
221
- address token1 = currency < coin ? coin : currency;
222
-
223
- rewards = CoinRewards.transferBothRewards(token0, totalAmountToken0, token1, totalAmountToken1, coin, coinConfig, currency, weth, doppler);
224
-
225
- emit ICoin.CoinMarketRewards(coinConfig.payoutRecipient, coinConfig.platformReferrer, coinConfig.protocolRewardRecipient, currency, rewards);
226
- }
227
-
228
- function _calculateReward(uint256 amount, uint256 bps) internal pure returns (uint256) {
229
- return CoinRewards.calculateReward(amount, bps);
230
- }
231
- }
@@ -1,11 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- pragma solidity ^0.8.23;
3
-
4
- library UniV3Errors {
5
- error InvalidPoolAddress();
6
- error InvalidCurrency();
7
- error InvalidWeth();
8
- error InvalidTickLower();
9
- error InvalidTickUpper();
10
- error InvalidUniswapV3Factory();
11
- }