@zoralabs/coins 0.9.0 → 1.0.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 (124) hide show
  1. package/.turbo/turbo-build.log +131 -114
  2. package/CHANGELOG.md +40 -0
  3. package/abis/BaseCoin.json +26 -118
  4. package/abis/BaseTest.json +47 -0
  5. package/abis/Coin.json +171 -63
  6. package/abis/CoinDopplerMultiCurve.json +38 -0
  7. package/abis/CoinRewardsV4.json +54 -0
  8. package/abis/CoinTest.json +53 -20
  9. package/abis/CoinUniV4Test.json +1053 -0
  10. package/abis/CoinV4.json +234 -211
  11. package/abis/DeployScript.json +47 -0
  12. package/abis/DeployedCoinVersionLookup.json +21 -0
  13. package/abis/DeployedCoinVersionLookupTest.json +716 -0
  14. package/abis/DifferentNamespaceVersionLookup.json +39 -0
  15. package/abis/DopplerUniswapV3Test.json +49 -93
  16. package/abis/ERC20.json +310 -0
  17. package/abis/FactoryTest.json +85 -7
  18. package/abis/FeeEstimatorHook.json +1528 -0
  19. package/abis/HooksDeployment.json +23 -0
  20. package/abis/HooksTest.json +47 -0
  21. package/abis/ICoin.json +40 -71
  22. package/abis/ICoinV3.json +879 -0
  23. package/abis/ICoinV4.json +915 -0
  24. package/abis/IDeployedCoinVersionLookup.json +21 -0
  25. package/abis/IERC721.json +36 -36
  26. package/abis/IHasPoolKey.json +42 -0
  27. package/abis/IHasRewardsRecipients.json +54 -0
  28. package/abis/IHasSwapPath.json +60 -0
  29. package/abis/IMsgSender.json +15 -0
  30. package/abis/IPoolConfigEncoding.json +46 -0
  31. package/abis/ISwapPathRouter.json +92 -0
  32. package/abis/IUniversalRouter.json +61 -0
  33. package/abis/IUnlockCallback.json +21 -0
  34. package/abis/IV4Quoter.json +310 -0
  35. package/abis/IZoraFactory.json +191 -11
  36. package/abis/IZoraV4CoinHook.json +348 -4
  37. package/abis/MockERC20.json +21 -0
  38. package/abis/MultiOwnableTest.json +47 -0
  39. package/abis/{CoinConfigurationVersions.json → Position.json} +1 -1
  40. package/abis/PrintUpgradeCommand.json +9 -0
  41. package/abis/ProxyShim.json +24 -0
  42. package/abis/StateLibrary.json +80 -0
  43. package/abis/TestDeployedCoinVersionLookupImplementation.json +39 -0
  44. package/abis/TestV4Swap.json +9 -0
  45. package/abis/UpgradeCoinImpl.json +47 -0
  46. package/abis/UpgradesTest.json +67 -0
  47. package/abis/Vm.json +1482 -111
  48. package/abis/VmSafe.json +856 -32
  49. package/abis/ZoraFactoryImpl.json +339 -1
  50. package/abis/ZoraV4CoinHook.json +455 -5
  51. package/addresses/8453.json +8 -4
  52. package/addresses/84532.json +8 -4
  53. package/dist/index.cjs +1920 -169
  54. package/dist/index.cjs.map +1 -1
  55. package/dist/index.js +1916 -169
  56. package/dist/index.js.map +1 -1
  57. package/dist/wagmiGenerated.d.ts +2599 -183
  58. package/dist/wagmiGenerated.d.ts.map +1 -1
  59. package/package/wagmiGenerated.ts +1928 -165
  60. package/package.json +8 -3
  61. package/remappings.txt +6 -1
  62. package/script/CoinsDeployerBase.sol +74 -11
  63. package/script/DeployDevFactory.s.sol +21 -0
  64. package/script/PrintUpgradeCommand.s.sol +13 -0
  65. package/script/Simulate.s.sol +1 -10
  66. package/script/TestBackingCoinSwap.s.sol +146 -0
  67. package/script/TestV4Swap.s.sol +136 -0
  68. package/script/UpgradeFactoryImpl.s.sol +1 -1
  69. package/src/BaseCoin.sol +176 -0
  70. package/src/Coin.sol +87 -202
  71. package/src/CoinV4.sol +121 -0
  72. package/src/ZoraFactoryImpl.sol +208 -36
  73. package/src/hooks/ZoraV4CoinHook.sol +195 -0
  74. package/src/hooks/{BaseCoinDeployHook.sol → deployment/BaseCoinDeployHook.sol} +3 -3
  75. package/src/hooks/{BuySupplyWithSwapRouterHook.sol → deployment/BuySupplyWithSwapRouterHook.sol} +7 -5
  76. package/src/interfaces/ICoin.sol +31 -39
  77. package/src/interfaces/ICoinV3.sol +71 -0
  78. package/src/interfaces/ICoinV4.sol +69 -0
  79. package/src/interfaces/IDeployedCoinVersionLookup.sol +11 -0
  80. package/src/interfaces/IMsgSender.sol +9 -0
  81. package/src/interfaces/IPoolConfigEncoding.sol +14 -0
  82. package/src/interfaces/ISwapPathRouter.sol +14 -0
  83. package/src/interfaces/IZoraFactory.sol +65 -27
  84. package/src/interfaces/IZoraV4CoinHook.sol +116 -0
  85. package/src/libs/CoinCommon.sol +15 -0
  86. package/src/libs/CoinConfigurationVersions.sol +116 -1
  87. package/src/libs/CoinConstants.sol +5 -0
  88. package/src/libs/CoinDopplerMultiCurve.sol +134 -0
  89. package/src/libs/CoinDopplerUniV3.sol +19 -171
  90. package/src/libs/CoinRewards.sol +195 -0
  91. package/src/libs/CoinRewardsV4.sol +180 -0
  92. package/src/libs/CoinSetup.sol +57 -0
  93. package/src/libs/CoinSetupV3.sol +6 -67
  94. package/src/libs/DopplerMath.sol +156 -0
  95. package/src/libs/HooksDeployment.sol +84 -0
  96. package/src/libs/MarketConstants.sol +4 -0
  97. package/src/libs/PoolStateReader.sol +22 -0
  98. package/src/libs/UniV3BuySell.sol +74 -292
  99. package/src/libs/UniV4SwapHelper.sol +65 -0
  100. package/src/libs/UniV4SwapToCurrency.sol +109 -0
  101. package/src/libs/V4Liquidity.sol +129 -0
  102. package/src/types/PoolConfiguration.sol +15 -0
  103. package/src/utils/DeployedCoinVersionLookup.sol +52 -0
  104. package/src/version/ContractVersionBase.sol +1 -1
  105. package/test/Coin.t.sol +78 -88
  106. package/test/CoinDopplerUniV3.t.sol +32 -171
  107. package/test/CoinUniV4.t.sol +752 -0
  108. package/test/{Hooks.t.sol → DeploymentHooks.t.sol} +2 -6
  109. package/test/Factory.t.sol +80 -47
  110. package/test/MultiOwnable.t.sol +6 -3
  111. package/test/Upgrades.t.sol +6 -5
  112. package/test/mocks/MockERC20.sol +12 -0
  113. package/test/utils/BaseTest.sol +106 -56
  114. package/test/utils/DeployedCoinVersionLookup.t.sol +127 -0
  115. package/test/utils/FeeEstimatorHook.sol +84 -0
  116. package/test/utils/ProxyShim.sol +17 -0
  117. package/wagmi.config.ts +4 -0
  118. package/.env +0 -1
  119. package/.turbo/turbo-update-contract-version.log +0 -22
  120. package/abis/CoinSetupV3.json +0 -7
  121. package/abis/HookDeployer.json +0 -68
  122. package/abis/IHookDeployer.json +0 -42
  123. package/src/libs/CoinLegacy.sol +0 -48
  124. package/src/libs/CoinLegacyMarket.sol +0 -182
@@ -0,0 +1,176 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.23;
3
+
4
+ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
+ import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
+ import {ICoin, IHasRewardsRecipients} from "./interfaces/ICoin.sol";
7
+ import {ICoinComments} from "./interfaces/ICoinComments.sol";
8
+ import {IERC7572} from "./interfaces/IERC7572.sol";
9
+ import {IAirlock} from "./interfaces/IAirlock.sol";
10
+
11
+ import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol";
12
+ import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
13
+ import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
14
+ import {ContractVersionBase} from "./version/ContractVersionBase.sol";
15
+ import {MultiOwnable} from "./utils/MultiOwnable.sol";
16
+ import {CoinConstants} from "./libs/CoinConstants.sol";
17
+
18
+ /*
19
+ $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
20
+ $$ __$$\ $$ __$$\ \_$$ _|$$$\ $$ |
21
+ $$ / \__|$$ / $$ | $$ | $$$$\ $$ |
22
+ $$ | $$ | $$ | $$ | $$ $$\$$ |
23
+ $$ | $$ | $$ | $$ | $$ \$$$$ |
24
+ $$ | $$\ $$ | $$ | $$ | $$ |\$$$ |
25
+ \$$$$$$ | $$$$$$ |$$$$$$\ $$ | \$$ |
26
+ \______/ \______/ \______|\__| \__|
27
+ */
28
+ abstract contract BaseCoin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnable, ReentrancyGuardUpgradeable {
29
+ using SafeERC20 for IERC20;
30
+
31
+ /// @notice The address of the protocol rewards contract
32
+ address public immutable protocolRewards;
33
+ /// @notice The address of the protocol reward recipient
34
+ address public immutable protocolRewardRecipient;
35
+ /// @notice The address of the Airlock contract, ownership is used for a protocol fee split.
36
+ address public immutable airlock;
37
+
38
+ /// @notice The metadata URI
39
+ string public tokenURI;
40
+ /// @notice The address of the coin creator
41
+ address public payoutRecipient;
42
+ /// @notice The address of the platform referrer
43
+ address public platformReferrer;
44
+ /// @notice The address of the currency
45
+ address public currency;
46
+
47
+ /**
48
+ * @notice The constructor for the static Coin contract deployment shared across all Coins.
49
+ * @param _protocolRewardRecipient The address of the protocol reward recipient
50
+ * @param _protocolRewards The address of the protocol rewards contract
51
+ * @param _airlock The address of the Airlock contract
52
+ */
53
+ constructor(address _protocolRewardRecipient, address _protocolRewards, address _airlock) initializer {
54
+ if (_protocolRewardRecipient == address(0)) {
55
+ revert AddressZero();
56
+ }
57
+ if (_protocolRewards == address(0)) {
58
+ revert AddressZero();
59
+ }
60
+
61
+ if (_airlock == address(0)) {
62
+ revert AddressZero();
63
+ }
64
+
65
+ protocolRewardRecipient = _protocolRewardRecipient;
66
+ protocolRewards = _protocolRewards;
67
+ airlock = _airlock;
68
+ }
69
+
70
+ /// @notice Initializes a new coin
71
+ /// @param payoutRecipient_ The address of the coin creator
72
+ /// @param tokenURI_ The metadata URI
73
+ /// @param name_ The coin name
74
+ /// @param symbol_ The coin symbol
75
+ /// @param platformReferrer_ The address of the platform referrer
76
+ function _initialize(
77
+ address payoutRecipient_,
78
+ address[] memory owners_,
79
+ string memory tokenURI_,
80
+ string memory name_,
81
+ string memory symbol_,
82
+ address platformReferrer_
83
+ ) internal {
84
+ // Validate the creation parameters
85
+ if (payoutRecipient_ == address(0)) {
86
+ revert AddressZero();
87
+ }
88
+
89
+ // Set base contract state
90
+ __ERC20_init(name_, symbol_);
91
+ __ERC20Permit_init(name_);
92
+ __MultiOwnable_init(owners_);
93
+ __ReentrancyGuard_init();
94
+
95
+ // Set mutable state
96
+ _setPayoutRecipient(payoutRecipient_);
97
+ _setContractURI(tokenURI_);
98
+
99
+ // Store the referrer or use the protocol reward recipient if not set
100
+ platformReferrer = platformReferrer_ == address(0) ? protocolRewardRecipient : platformReferrer_;
101
+
102
+ // Mint the total supply to the coin contract
103
+ _mint(address(this), CoinConstants.MAX_TOTAL_SUPPLY);
104
+
105
+ // Distribute the creator launch reward to the payout recipient
106
+ _transfer(address(this), payoutRecipient, CoinConstants.CREATOR_LAUNCH_REWARD);
107
+ }
108
+
109
+ /// @notice Enables a user to burn their tokens
110
+ /// @param amount The amount of tokens to burn
111
+ function burn(uint256 amount) external {
112
+ // This burn function sets the from as msg.sender, so having an unauthed call is safe.
113
+ _burn(msg.sender, amount);
114
+ }
115
+
116
+ /// @notice Set the creator's payout address
117
+ /// @param newPayoutRecipient The new recipient address
118
+ function setPayoutRecipient(address newPayoutRecipient) external onlyOwner {
119
+ _setPayoutRecipient(newPayoutRecipient);
120
+ }
121
+
122
+ /// @notice Set the contract URI
123
+ /// @param newURI The new URI
124
+ function setContractURI(string memory newURI) external onlyOwner {
125
+ _setContractURI(newURI);
126
+ }
127
+
128
+ /// @notice The contract metadata
129
+ function contractURI() external view returns (string memory) {
130
+ return tokenURI;
131
+ }
132
+
133
+ /// @notice ERC165 interface support
134
+ /// @param interfaceId The interface ID to check
135
+ function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {
136
+ return
137
+ interfaceId == type(ICoin).interfaceId ||
138
+ interfaceId == type(ICoinComments).interfaceId ||
139
+ interfaceId == type(IERC7572).interfaceId ||
140
+ interfaceId == type(IERC165).interfaceId ||
141
+ interfaceId == type(IHasRewardsRecipients).interfaceId;
142
+ }
143
+
144
+ /// @dev Overrides ERC20's _update function to emit a superset `CoinTransfer` event
145
+ function _update(address from, address to, uint256 value) internal virtual override {
146
+ super._update(from, to, value);
147
+
148
+ emit CoinTransfer(from, to, value, balanceOf(from), balanceOf(to));
149
+ }
150
+
151
+ /// @dev Used to set the payout recipient on coin creation and updates
152
+ /// @param newPayoutRecipient The new recipient address
153
+ function _setPayoutRecipient(address newPayoutRecipient) internal {
154
+ if (newPayoutRecipient == address(0)) {
155
+ revert AddressZero();
156
+ }
157
+
158
+ emit CoinPayoutRecipientUpdated(msg.sender, payoutRecipient, newPayoutRecipient);
159
+
160
+ payoutRecipient = newPayoutRecipient;
161
+ }
162
+
163
+ /// @dev Used to set the contract URI on coin creation and updates
164
+ /// @param newURI The new URI
165
+ function _setContractURI(string memory newURI) internal {
166
+ emit ContractMetadataUpdated(msg.sender, newURI, name());
167
+ emit ContractURIUpdated();
168
+
169
+ tokenURI = newURI;
170
+ }
171
+
172
+ /// @notice Returns the address of the Doppler protocol fee recipient
173
+ function dopplerFeeRecipient() public view returns (address) {
174
+ return IAirlock(airlock).owner();
175
+ }
176
+ }
package/src/Coin.sol CHANGED
@@ -2,10 +2,7 @@
2
2
  pragma solidity ^0.8.23;
3
3
 
4
4
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5
- import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
5
  import {ICoin, PoolConfiguration} from "./interfaces/ICoin.sol";
7
- import {ICoinComments} from "./interfaces/ICoinComments.sol";
8
- import {IERC7572} from "./interfaces/IERC7572.sol";
9
6
  import {IUniswapV3Factory} from "./interfaces/IUniswapV3Factory.sol";
10
7
  import {IUniswapV3Pool} from "./interfaces/IUniswapV3Pool.sol";
11
8
  import {ISwapRouter} from "./interfaces/ISwapRouter.sol";
@@ -19,15 +16,14 @@ import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/ut
19
16
  import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
20
17
  import {ContractVersionBase} from "./version/ContractVersionBase.sol";
21
18
  import {MultiOwnable} from "./utils/MultiOwnable.sol";
22
- import {FullMath} from "./utils/uniswap/FullMath.sol";
23
- import {TickMath} from "./utils/uniswap/TickMath.sol";
24
- import {LiquidityAmounts} from "./utils/uniswap/LiquidityAmounts.sol";
25
19
  import {CoinConstants} from "./libs/CoinConstants.sol";
26
20
  import {MarketConstants} from "./libs/MarketConstants.sol";
27
21
  import {LpPosition} from "./types/LpPosition.sol";
28
22
  import {PoolState} from "./types/PoolState.sol";
29
23
  import {CoinSetupV3, UniV3Config, CoinV3Config} from "./libs/CoinSetupV3.sol";
30
- import {UniV3BuySell, CoinConfig} from "./libs/UniV3BuySell.sol";
24
+ import {UniV3BuySell, CoinConfig, SellResult} from "./libs/UniV3BuySell.sol";
25
+ import {BaseCoin} from "./BaseCoin.sol";
26
+ import {ICoinV3} from "./interfaces/ICoinV3.sol";
31
27
 
32
28
  /*
33
29
  $$$$$$\ $$$$$$\ $$$$$$\ $$\ $$\
@@ -39,183 +35,98 @@ import {UniV3BuySell, CoinConfig} from "./libs/UniV3BuySell.sol";
39
35
  \$$$$$$ | $$$$$$ |$$$$$$\ $$ | \$$ |
40
36
  \______/ \______/ \______|\__| \__|
41
37
  */
42
- contract Coin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnable, ReentrancyGuardUpgradeable {
38
+ contract Coin is BaseCoin, ICoinV3 {
43
39
  using SafeERC20 for IERC20;
44
40
 
45
- /// @notice The address of the WETH contract
46
- address public immutable WETH;
47
- /// @notice The address of the Uniswap V3 factory
48
41
  address public immutable v3Factory;
49
42
  /// @notice The address of the Uniswap V3 swap router
50
43
  address public immutable swapRouter;
51
- /// @notice The address of the Airlock contract, ownership is used for a protocol fee split.
52
- address public immutable airlock;
53
- /// @notice The address of the protocol rewards contract
54
- address public immutable protocolRewards;
55
- /// @notice The address of the protocol reward recipient
56
- address public immutable protocolRewardRecipient;
57
-
58
- /// @notice The metadata URI
59
- string public tokenURI;
60
- /// @notice The address of the coin creator
61
- address public payoutRecipient;
62
- /// @notice The address of the platform referrer
63
- address public platformReferrer;
64
44
  /// @notice The address of the Uniswap V3 pool
65
45
  address public poolAddress;
66
- /// @notice The address of the currency
67
- address public currency;
68
46
 
69
47
  /// @notice The state of the market
70
48
  bytes public market;
71
49
  uint8 public marketVersion;
72
50
 
51
+ /// @notice The address of the WETH contract
52
+ address public immutable WETH;
53
+
73
54
  /// @notice deprecated
74
55
  PoolConfiguration public poolConfiguration;
75
56
 
76
- /// @notice Returns the state of the pool
77
- /// @dev This is a legacy function for compatibility with doppler default state
78
- /// @return asset The address of the asset
79
- /// @return numeraire The address of the numeraire
80
- /// @return tickLower The lower tick
81
- /// @return tickUpper The upper tick
82
- /// @return numPositions The number of discovery positions
83
- /// @return isInitialized Whether the pool is initialized
84
- /// @return isExited Whether the pool is exited
85
- /// @return maxShareToBeSold The maximum share to be sold
86
- /// @return totalTokensOnBondingCurve The total tokens on the bonding curve
87
- function poolState()
88
- external
89
- view
90
- returns (
91
- address asset,
92
- address numeraire,
93
- int24 tickLower,
94
- int24 tickUpper,
95
- uint16 numPositions,
96
- bool isInitialized,
97
- bool isExited,
98
- uint256 maxShareToBeSold,
99
- uint256 totalTokensOnBondingCurve
100
- )
101
- {
102
- asset = address(this);
103
- numeraire = currency;
104
- tickLower = poolConfiguration.tickLower;
105
- tickUpper = poolConfiguration.tickUpper;
106
- numPositions = poolConfiguration.numPositions;
107
- isInitialized = true;
108
- isExited = false;
109
- maxShareToBeSold = poolConfiguration.maxDiscoverySupplyShare;
110
- totalTokensOnBondingCurve = CoinConstants.POOL_LAUNCH_SUPPLY;
111
- }
57
+ LpPosition[] public positions;
112
58
 
113
59
  /**
114
60
  * @notice The constructor for the static Coin contract deployment shared across all Coins.
115
- * @param _protocolRewardRecipient The address of the protocol reward recipient
116
- * @param _protocolRewards The address of the protocol rewards contract
117
- * @param _weth The address of the WETH contract
118
- * @param _v3Factory The address of the Uniswap V3 factory
119
- * @param _swapRouter The address of the Uniswap V3 swap router
120
- * @param _airlock The address of the Airlock contract, ownership is used for a protocol fee split.
61
+ * @param protocolRewardRecipient_ The address of the protocol reward recipient
62
+ * @param protocolRewards_ The address of the protocol rewards contract
63
+ * @param weth_ The address of the WETH contract
64
+ * @param v3Factory_ The address of the Uniswap V3 factory
65
+ * @param swapRouter_ The address of the Uniswap V3 swap router
66
+ * @param airlock_ The address of the Airlock contract, ownership is used for a protocol fee split.
121
67
  */
122
68
  constructor(
123
- address _protocolRewardRecipient,
124
- address _protocolRewards,
125
- address _weth,
126
- address _v3Factory,
127
- address _swapRouter,
128
- address _airlock
129
- ) initializer {
130
- if (_protocolRewardRecipient == address(0)) {
131
- revert AddressZero();
132
- }
133
- if (_protocolRewards == address(0)) {
134
- revert AddressZero();
135
- }
136
- if (_weth == address(0)) {
69
+ address protocolRewardRecipient_,
70
+ address protocolRewards_,
71
+ address weth_,
72
+ address v3Factory_,
73
+ address swapRouter_,
74
+ address airlock_
75
+ ) BaseCoin(protocolRewardRecipient_, protocolRewards_, airlock_) initializer {
76
+ if (v3Factory_ == address(0)) {
137
77
  revert AddressZero();
138
78
  }
139
- if (_v3Factory == address(0)) {
79
+ if (swapRouter_ == address(0)) {
140
80
  revert AddressZero();
141
81
  }
142
- if (_swapRouter == address(0)) {
82
+ if (airlock_ == address(0)) {
143
83
  revert AddressZero();
144
84
  }
145
- if (_airlock == address(0)) {
85
+ if (weth_ == address(0)) {
146
86
  revert AddressZero();
147
87
  }
88
+ swapRouter = swapRouter_;
89
+ v3Factory = v3Factory_;
148
90
 
149
- protocolRewardRecipient = _protocolRewardRecipient;
150
- protocolRewards = _protocolRewards;
151
- WETH = _weth;
152
- swapRouter = _swapRouter;
153
- v3Factory = _v3Factory;
154
- airlock = _airlock;
91
+ WETH = weth_;
155
92
  }
156
93
 
157
- /// @notice Initializes a new coin
158
- /// @param payoutRecipient_ The address of the coin creator
159
- /// @param tokenURI_ The metadata URI
160
- /// @param name_ The coin name
161
- /// @param symbol_ The coin symbol
162
- /// @param poolConfig_ The parameters for the v3 pool and liquidity
163
- /// @param platformReferrer_ The address of the platform referrer
94
+ /// @inheritdoc ICoinV3
164
95
  function initialize(
165
96
  address payoutRecipient_,
166
97
  address[] memory owners_,
167
98
  string memory tokenURI_,
168
99
  string memory name_,
169
100
  string memory symbol_,
170
- bytes memory poolConfig_,
171
- address platformReferrer_
101
+ address platformReferrer_,
102
+ address currency_,
103
+ address poolAddress_,
104
+ PoolConfiguration memory poolConfiguration_,
105
+ LpPosition[] memory positions_
172
106
  ) public initializer {
173
- // Validate the creation parameters
174
- if (payoutRecipient_ == address(0)) {
175
- revert AddressZero();
176
- }
177
-
178
- // Set base contract state
179
- __ERC20_init(name_, symbol_);
180
- __ERC20Permit_init(name_);
181
- __MultiOwnable_init(owners_);
182
- __ReentrancyGuard_init();
183
-
184
- // Set mutable state
185
- _setPayoutRecipient(payoutRecipient_);
186
- _setContractURI(tokenURI_);
107
+ super._initialize(payoutRecipient_, owners_, tokenURI_, name_, symbol_, platformReferrer_);
187
108
 
188
- // Store the referrer if set
189
- platformReferrer = platformReferrer_ == address(0) ? protocolRewardRecipient : platformReferrer_;
109
+ currency = currency_;
110
+ poolAddress = poolAddress_;
111
+ poolConfiguration = poolConfiguration_;
112
+ positions = positions_;
190
113
 
191
- // Mint the total supply
192
- _mint(address(this), CoinConstants.MAX_TOTAL_SUPPLY);
193
-
194
- // Distribute the creator launch reward
195
- _transfer(address(this), payoutRecipient, CoinConstants.CREATOR_LAUNCH_REWARD);
196
-
197
- UniV3Config memory uniswapV3Config = UniV3Config({weth: WETH, v3Factory: v3Factory, swapRouter: swapRouter, airlock: airlock});
198
-
199
- // Deploy the pool
200
- (currency, poolAddress, poolConfiguration) = CoinSetupV3.setupPool(poolConfig_, uniswapV3Config, address(this));
201
-
202
- // Split out the deployment of liquidity to avoid stack too deep
203
- CoinSetupV3.deployLiquidity(address(this), currency, poolConfiguration, poolAddress);
114
+ CoinSetupV3.deployLiquidity(positions_, poolAddress);
204
115
  }
205
116
 
206
- function buildCoinConfig() internal view returns (CoinConfig memory coinConfig) {
117
+ function buildConfig() internal view returns (CoinConfig memory coinConfig) {
207
118
  coinConfig = CoinConfig({
208
119
  protocolRewardRecipient: protocolRewardRecipient,
209
120
  platformReferrer: platformReferrer,
210
- currency: currency,
211
121
  payoutRecipient: payoutRecipient,
212
- protocolRewards: protocolRewards,
213
- poolConfiguration: poolConfiguration,
214
- poolAddress: poolAddress,
215
- uniswapV3Config: UniV3Config({weth: WETH, v3Factory: v3Factory, swapRouter: swapRouter, airlock: airlock})
122
+ protocolRewards: protocolRewards
216
123
  });
217
124
  }
218
125
 
126
+ function getPoolConfiguration() public view returns (PoolConfiguration memory) {
127
+ return poolConfiguration;
128
+ }
129
+
219
130
  /// @notice Executes a buy order
220
131
  /// @param recipient The recipient address of the coins
221
132
  /// @param orderSize The amount of coins to buy
@@ -228,7 +139,24 @@ contract Coin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnabl
228
139
  uint160 sqrtPriceLimitX96,
229
140
  address tradeReferrer
230
141
  ) public payable nonReentrant returns (uint256, uint256) {
231
- return UniV3BuySell.buy(recipient, orderSize, minAmountOut, sqrtPriceLimitX96, tradeReferrer, address(this), buildCoinConfig());
142
+ CoinConfig memory coinConfig = buildConfig();
143
+ (uint256 amountOut, uint256 tradeReward, uint256 trueOrderSize) = UniV3BuySell.handleBuy(
144
+ recipient,
145
+ orderSize,
146
+ minAmountOut,
147
+ sqrtPriceLimitX96,
148
+ tradeReferrer,
149
+ coinConfig,
150
+ currency,
151
+ ISwapRouter(swapRouter),
152
+ IWETH(WETH)
153
+ );
154
+
155
+ UniV3BuySell.handleMarketRewards(coinConfig, currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
156
+
157
+ emit CoinBuy(msg.sender, recipient, tradeReferrer, amountOut, currency, tradeReward, trueOrderSize);
158
+
159
+ return (orderSize, amountOut);
232
160
  }
233
161
 
234
162
  /// @notice Executes a sell order
@@ -253,21 +181,33 @@ contract Coin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnabl
253
181
  // Approve the Uniswap V3 swap router
254
182
  this.approve(swapRouter, orderSize);
255
183
 
256
- return UniV3BuySell.sell(recipient, beforeCoinBalance, orderSize, minAmountOut, sqrtPriceLimitX96, tradeReferrer, buildCoinConfig());
257
- }
184
+ CoinConfig memory coinConfig = buildConfig();
185
+
186
+ SellResult memory result = UniV3BuySell.handleSell(
187
+ recipient,
188
+ beforeCoinBalance,
189
+ orderSize,
190
+ minAmountOut,
191
+ sqrtPriceLimitX96,
192
+ tradeReferrer,
193
+ coinConfig,
194
+ currency,
195
+ ISwapRouter(swapRouter),
196
+ IWETH(WETH)
197
+ );
198
+
199
+ UniV3BuySell.handleMarketRewards(coinConfig, currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
200
+
201
+ emit ICoin.CoinSell(msg.sender, recipient, tradeReferrer, result.trueOrderSize, currency, result.tradeReward, result.payoutSize);
258
202
 
259
- /// @notice Enables a user to burn their tokens
260
- /// @param amount The amount of tokens to burn
261
- function burn(uint256 amount) external {
262
- // This burn function sets the from as msg.sender, so having an unauthed call is safe.
263
- _burn(msg.sender, amount);
203
+ return (result.trueOrderSize, result.payoutSize);
264
204
  }
265
205
 
266
206
  /// @notice Force claim any accrued secondary rewards from the market's liquidity position.
267
207
  /// @dev This function is a fallback, secondary rewards will be claimed automatically on each buy and sell.
268
208
  /// @param pushEthRewards Whether to push the ETH directly to the recipients.
269
209
  function claimSecondaryRewards(bool pushEthRewards) external nonReentrant {
270
- MarketRewards memory rewards = UniV3BuySell.handleMarketRewards(address(this), buildCoinConfig());
210
+ MarketRewards memory rewards = UniV3BuySell.handleMarketRewards(buildConfig(), currency, poolAddress, positions, IWETH(WETH), dopplerFeeRecipient());
271
211
 
272
212
  if (pushEthRewards && rewards.totalAmountCurrency > 0 && currency == WETH) {
273
213
  IProtocolRewards(protocolRewards).withdrawFor(payoutRecipient, rewards.creatorPayoutAmountCurrency);
@@ -276,38 +216,6 @@ contract Coin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnabl
276
216
  }
277
217
  }
278
218
 
279
- /// @notice Set the creator's payout address
280
- /// @param newPayoutRecipient The new recipient address
281
- function setPayoutRecipient(address newPayoutRecipient) external onlyOwner {
282
- _setPayoutRecipient(newPayoutRecipient);
283
- }
284
-
285
- /// @notice Set the contract URI
286
- /// @param newURI The new URI
287
- function setContractURI(string memory newURI) external onlyOwner {
288
- _setContractURI(newURI);
289
- }
290
-
291
- /// @notice The contract metadata
292
- function contractURI() external view returns (string memory) {
293
- return tokenURI;
294
- }
295
-
296
- /// @notice ERC165 interface support
297
- /// @param interfaceId The interface ID to check
298
- function supportsInterface(bytes4 interfaceId) public pure virtual returns (bool) {
299
- return
300
- interfaceId == type(ICoin).interfaceId ||
301
- interfaceId == type(ICoinComments).interfaceId ||
302
- interfaceId == type(IERC7572).interfaceId ||
303
- interfaceId == type(IERC165).interfaceId;
304
- }
305
-
306
- /// @notice Receives ETH converted from WETH
307
- receive() external payable {
308
- require(msg.sender == WETH, OnlyWeth());
309
- }
310
-
311
219
  /// @dev Called by the pool after minting liquidity to transfer the associated coins
312
220
  function uniswapV3MintCallback(uint256 amount0Owed, uint256 amount1Owed, bytes calldata) external {
313
221
  if (msg.sender != poolAddress) revert OnlyPool(msg.sender, poolAddress);
@@ -315,31 +223,8 @@ contract Coin is ICoin, ContractVersionBase, ERC20PermitUpgradeable, MultiOwnabl
315
223
  IERC20(address(this)).safeTransfer(poolAddress, amount0Owed == 0 ? amount1Owed : amount0Owed);
316
224
  }
317
225
 
318
- /// @dev Overrides ERC20's _update function to emit a superset `CoinTransfer` event
319
- function _update(address from, address to, uint256 value) internal virtual override {
320
- super._update(from, to, value);
321
-
322
- emit CoinTransfer(from, to, value, balanceOf(from), balanceOf(to));
323
- }
324
-
325
- /// @dev Used to set the payout recipient on coin creation and updates
326
- /// @param newPayoutRecipient The new recipient address
327
- function _setPayoutRecipient(address newPayoutRecipient) internal {
328
- if (newPayoutRecipient == address(0)) {
329
- revert AddressZero();
330
- }
331
-
332
- emit CoinPayoutRecipientUpdated(msg.sender, payoutRecipient, newPayoutRecipient);
333
-
334
- payoutRecipient = newPayoutRecipient;
335
- }
336
-
337
- /// @dev Used to set the contract URI on coin creation and updates
338
- /// @param newURI The new URI
339
- function _setContractURI(string memory newURI) internal {
340
- emit ContractMetadataUpdated(msg.sender, newURI, name());
341
- emit ContractURIUpdated();
342
-
343
- tokenURI = newURI;
226
+ /// @notice Receives ETH converted from WETH
227
+ receive() external payable {
228
+ require(msg.sender == WETH, OnlyWeth());
344
229
  }
345
230
  }