@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/src/libs/CoinRewards.sol
DELETED
|
@@ -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
|
-
}
|
package/src/libs/CoinSetupV3.sol
DELETED
|
@@ -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
|
-
}
|
package/src/libs/UniV3Errors.sol
DELETED
|
@@ -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
|
-
}
|