@zoralabs/coins 1.1.0 → 1.1.2
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 +102 -97
- package/CHANGELOG.md +14 -0
- package/LICENSE +90 -21
- package/abis/BaseCoin.json +6 -1
- package/abis/BaseZoraV4CoinHook.json +119 -0
- package/abis/Coin.json +6 -1
- package/abis/CoinTest.json +14 -0
- package/abis/CoinV4.json +6 -1
- package/abis/ContentCoinHook.json +119 -0
- package/abis/CreatorCoin.json +6 -1
- package/abis/CreatorCoinHook.json +119 -0
- package/abis/ERC165.json +21 -0
- package/abis/ERC165Upgradeable.json +44 -0
- package/abis/FeeEstimatorHook.json +119 -0
- package/abis/ICoin.json +5 -0
- package/abis/ICoinV3.json +5 -0
- package/abis/ICoinV4.json +5 -0
- package/abis/ICreatorCoin.json +5 -0
- package/abis/LiquidityMigrationTest.json +7 -0
- package/abis/UpgradeHooks.json +35 -0
- package/abis/UpgradesTest.json +21 -0
- package/addresses/8453.json +11 -7
- package/dist/index.cjs +6 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/wagmiGenerated.d.ts +15 -3
- package/dist/wagmiGenerated.d.ts.map +1 -1
- package/package/wagmiGenerated.ts +6 -3
- package/package.json +1 -1
- package/script/DeployUpgradeGate.s.sol +1 -1
- package/script/PrintRegisterUpgradePath.s.sol +35 -0
- package/script/UpgradeCoinImpl.sol +1 -1
- package/script/UpgradeHooks.s.sol +23 -0
- package/src/BaseCoin.sol +32 -10
- package/src/Coin.sol +7 -1
- package/src/CoinV4.sol +9 -3
- package/src/CreatorCoin.sol +7 -1
- package/src/ZoraFactoryImpl.sol +7 -1
- package/src/deployment/CoinsDeployerBase.sol +29 -9
- package/src/hooks/BaseZoraV4CoinHook.sol +124 -4
- package/src/hooks/ContentCoinHook.sol +7 -1
- package/src/hooks/CreatorCoinHook.sol +7 -1
- package/src/hooks/HookUpgradeGate.sol +7 -1
- package/src/interfaces/ICoin.sol +3 -0
- package/src/libs/CoinCommon.sol +7 -1
- package/src/libs/CoinConfigurationVersions.sol +7 -1
- package/src/libs/CoinConstants.sol +7 -1
- package/src/libs/CoinDopplerMultiCurve.sol +7 -1
- package/src/libs/CoinRewards.sol +7 -1
- package/src/libs/CoinRewardsV4.sol +25 -5
- package/src/libs/CoinSetup.sol +7 -1
- package/src/libs/CreatorCoinConstants.sol +7 -1
- package/src/libs/CreatorCoinRewards.sol +7 -1
- package/src/libs/DopplerMath.sol +7 -1
- package/src/libs/HooksDeployment.sol +20 -1
- package/src/libs/PoolStateReader.sol +7 -1
- package/src/libs/UniV4SwapHelper.sol +7 -1
- package/src/libs/UniV4SwapToCurrency.sol +7 -1
- package/src/libs/V4Liquidity.sol +34 -1
- package/src/types/PoolConfiguration.sol +7 -1
- package/src/utils/AutoSwapper.sol +7 -1
- package/src/version/ContractVersionBase.sol +1 -1
- package/test/Coin.t.sol +23 -0
- package/test/LiquidityMigration.t.sol +27 -0
- package/test/Upgrades.t.sol +180 -1
- package/test/utils/BaseTest.sol +5 -1
- /package/script/{DeployHooks.s.sol → DeployPostDeploymentHooks.s.sol} +0 -0
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.28;
|
|
3
9
|
|
|
4
10
|
import {CreatorCoinConstants} from "../libs/CreatorCoinConstants.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {IHooksUpgradeGate} from "../interfaces/IHooksUpgradeGate.sol";
|
package/src/interfaces/ICoin.sol
CHANGED
|
@@ -23,6 +23,9 @@ struct PoolKeyStruct {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
interface ICoin is IERC165, IERC7572, IDopplerErrors, IHasRewardsRecipients {
|
|
26
|
+
/// @notice Thrown when the name is required for the coin
|
|
27
|
+
error NameIsRequired();
|
|
28
|
+
|
|
26
29
|
/// @notice Thrown when an operation is attempted with a zero address
|
|
27
30
|
error AddressZero();
|
|
28
31
|
|
package/src/libs/CoinCommon.sol
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {CoinConstants} from "./CoinConstants.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
library CoinConstants {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {PoolConfiguration} from "../interfaces/ICoin.sol";
|
package/src/libs/CoinRewards.sol
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.28;
|
|
3
9
|
|
|
4
10
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
@@ -79,6 +85,21 @@ library CoinRewardsV4 {
|
|
|
79
85
|
lpRewardAmount = uint128(calculateReward(uint256(totalBackingAmount), LP_REWARD_BPS));
|
|
80
86
|
}
|
|
81
87
|
|
|
88
|
+
function convertDeltaToPositiveUint128(int256 delta) internal pure returns (uint128) {
|
|
89
|
+
if (delta < 0) {
|
|
90
|
+
revert SafeCast.SafeCastOverflow();
|
|
91
|
+
}
|
|
92
|
+
return uint128(uint256(delta));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getCurrencyZeroBalance(IPoolManager poolManager, PoolKey calldata key) internal view returns (uint128) {
|
|
96
|
+
return convertDeltaToPositiveUint128(TransientStateLibrary.currencyDelta(poolManager, address(this), key.currency0));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getCurrencyOneBalance(IPoolManager poolManager, PoolKey calldata key) internal view returns (uint128) {
|
|
100
|
+
return convertDeltaToPositiveUint128(TransientStateLibrary.currencyDelta(poolManager, address(this), key.currency1));
|
|
101
|
+
}
|
|
102
|
+
|
|
82
103
|
/// @notice Mints LP rewards by creating new liquidity positions from collected fees
|
|
83
104
|
/// @dev Splits collected fees between LP rewards and market rewards, then mints new LP positions
|
|
84
105
|
/// with the LP reward portion. The remaining amount becomes market rewards for distribution.
|
|
@@ -99,8 +120,6 @@ library CoinRewardsV4 {
|
|
|
99
120
|
if (lpRewardAmount0 > 0) {
|
|
100
121
|
_modifyLiquidity(poolManager, key, lpRewardAmount0, true);
|
|
101
122
|
}
|
|
102
|
-
|
|
103
|
-
marketRewardsAmount0 = uint128(uint256(TransientStateLibrary.currencyDelta(poolManager, address(this), key.currency0)));
|
|
104
123
|
}
|
|
105
124
|
|
|
106
125
|
if (fees1 > 0) {
|
|
@@ -108,9 +127,10 @@ library CoinRewardsV4 {
|
|
|
108
127
|
if (lpRewardAmount1 > 0) {
|
|
109
128
|
_modifyLiquidity(poolManager, key, lpRewardAmount1, false);
|
|
110
129
|
}
|
|
111
|
-
|
|
112
|
-
marketRewardsAmount1 = uint128(uint256(TransientStateLibrary.currencyDelta(poolManager, address(this), key.currency1)));
|
|
113
130
|
}
|
|
131
|
+
|
|
132
|
+
marketRewardsAmount0 = getCurrencyZeroBalance(poolManager, key);
|
|
133
|
+
marketRewardsAmount1 = getCurrencyOneBalance(poolManager, key);
|
|
114
134
|
}
|
|
115
135
|
|
|
116
136
|
/// @notice Mints a single-sided LP position
|
package/src/libs/CoinSetup.sol
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {PoolConfigurationV4} from "../interfaces/ICoin.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
library CreatorCoinConstants {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.28;
|
|
3
9
|
|
|
4
10
|
import {ICreatorCoinHook} from "../interfaces/ICreatorCoinHook.sol";
|
package/src/libs/DopplerMath.sol
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.24;
|
|
3
9
|
|
|
4
10
|
import {IDopplerErrors} from "../interfaces/IDopplerErrors.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {Hooks} from "@uniswap/v4-core/src/libraries/Hooks.sol";
|
|
@@ -157,6 +163,19 @@ library HooksDeployment {
|
|
|
157
163
|
);
|
|
158
164
|
}
|
|
159
165
|
|
|
166
|
+
function creatorCoinCreationCode(
|
|
167
|
+
address poolManager,
|
|
168
|
+
address coinVersionLookup,
|
|
169
|
+
address[] memory trustedMessageSenders,
|
|
170
|
+
address upgradeGate
|
|
171
|
+
) internal pure returns (bytes memory) {
|
|
172
|
+
return
|
|
173
|
+
abi.encodePacked(
|
|
174
|
+
type(CreatorCoinHook).creationCode,
|
|
175
|
+
creatorCoinConstructorArgs(poolManager, coinVersionLookup, trustedMessageSenders, upgradeGate)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
160
179
|
/// @notice Deploys or returns existing ContentCoinHook using deterministic deployment. Ensures that if a hooks is already
|
|
161
180
|
/// deployed with the provided salt, it will be returned.
|
|
162
181
|
function deployContentCoinHook(
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
package/src/libs/V4Liquidity.sol
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
import {TickMath} from "@uniswap/v4-core/src/libraries/TickMath.sol";
|
|
@@ -48,6 +54,9 @@ library V4Liquidity {
|
|
|
48
54
|
error InvalidCallbackId(uint8 callbackId);
|
|
49
55
|
|
|
50
56
|
/// @notice Locks the pool, and mint initial positions to the hook
|
|
57
|
+
/// @param poolManager The pool manager.
|
|
58
|
+
/// @param poolKey The pool key.
|
|
59
|
+
/// @param positions The positions.
|
|
51
60
|
function lockAndMint(IPoolManager poolManager, PoolKey memory poolKey, LpPosition[] memory positions) internal {
|
|
52
61
|
bytes memory data = abi.encode(MINT_CALLBACK_ID, abi.encode(MintCallbackData({poolKey: poolKey, positions: positions})));
|
|
53
62
|
|
|
@@ -129,11 +138,35 @@ library V4Liquidity {
|
|
|
129
138
|
return abi.encode(result);
|
|
130
139
|
}
|
|
131
140
|
|
|
141
|
+
function generatePositionsFromMigratedLiquidity(
|
|
142
|
+
uint160 sqrtPriceX96,
|
|
143
|
+
BurnedPosition[] calldata migratedLiquidity
|
|
144
|
+
) internal pure returns (LpPosition[] memory positions) {
|
|
145
|
+
positions = new LpPosition[](migratedLiquidity.length);
|
|
146
|
+
|
|
147
|
+
for (uint256 i = 0; i < migratedLiquidity.length; i++) {
|
|
148
|
+
uint128 liquidity = LiquidityAmounts.getLiquidityForAmounts(
|
|
149
|
+
sqrtPriceX96,
|
|
150
|
+
TickMath.getSqrtPriceAtTick(migratedLiquidity[i].tickLower),
|
|
151
|
+
TickMath.getSqrtPriceAtTick(migratedLiquidity[i].tickUpper),
|
|
152
|
+
migratedLiquidity[i].amount0Received,
|
|
153
|
+
migratedLiquidity[i].amount1Received
|
|
154
|
+
);
|
|
155
|
+
positions[i] = LpPosition({liquidity: liquidity, tickLower: migratedLiquidity[i].tickLower, tickUpper: migratedLiquidity[i].tickUpper});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
132
159
|
function collectFees(IPoolManager poolManager, PoolKey memory poolKey, LpPosition[] storage positions) internal returns (int128 balance0, int128 balance1) {
|
|
133
160
|
ModifyLiquidityParams memory params;
|
|
134
161
|
uint256 numPositions = positions.length;
|
|
135
162
|
|
|
136
163
|
for (uint256 i; i < numPositions; i++) {
|
|
164
|
+
// if there is no liquidity, skip
|
|
165
|
+
uint128 liquidity = getLiquidity(poolManager, address(this), poolKey, positions[i].tickLower, positions[i].tickUpper);
|
|
166
|
+
if (liquidity == 0) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
137
170
|
params = ModifyLiquidityParams({
|
|
138
171
|
tickLower: positions[i].tickLower,
|
|
139
172
|
tickUpper: positions[i].tickUpper,
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.23;
|
|
3
9
|
|
|
4
10
|
/// @notice The configuration of the pool
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
// SPDX-License-Identifier:
|
|
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
|
|
2
8
|
pragma solidity ^0.8.28;
|
|
3
9
|
|
|
4
10
|
import {ISwapRouter} from "@zoralabs/shared-contracts/interfaces/uniswap/ISwapRouter.sol";
|
|
@@ -9,6 +9,6 @@ import {IVersionedContract} from "@zoralabs/shared-contracts/interfaces/IVersion
|
|
|
9
9
|
contract ContractVersionBase is IVersionedContract {
|
|
10
10
|
/// @notice The version of the contract
|
|
11
11
|
function contractVersion() external pure override returns (string memory) {
|
|
12
|
-
return "1.1.
|
|
12
|
+
return "1.1.2";
|
|
13
13
|
}
|
|
14
14
|
}
|
package/test/Coin.t.sol
CHANGED
|
@@ -8,6 +8,8 @@ import {CoinConstants} from "../src/libs/CoinConstants.sol";
|
|
|
8
8
|
import {IZoraFactory} from "../src/interfaces/IZoraFactory.sol";
|
|
9
9
|
import {IHasRewardsRecipients} from "../src/interfaces/IHasRewardsRecipients.sol";
|
|
10
10
|
import {PoolConfiguration} from "../src/interfaces/ICoin.sol";
|
|
11
|
+
import {IERC165, IERC7572, ICoin, ICoinComments, IERC20} from "../src/BaseCoin.sol";
|
|
12
|
+
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
|
|
11
13
|
|
|
12
14
|
contract CoinTest is BaseTest {
|
|
13
15
|
using stdJson for string;
|
|
@@ -16,6 +18,17 @@ contract CoinTest is BaseTest {
|
|
|
16
18
|
super.setUp();
|
|
17
19
|
}
|
|
18
20
|
|
|
21
|
+
function test_contract_ierc165_support() public {
|
|
22
|
+
_deployCoin();
|
|
23
|
+
assertEq(coin.supportsInterface(type(IZoraFactory).interfaceId), false);
|
|
24
|
+
assertEq(coin.supportsInterface(bytes4(0x00000000)), false);
|
|
25
|
+
assertEq(coin.supportsInterface(type(IERC165).interfaceId), true);
|
|
26
|
+
assertEq(coin.supportsInterface(type(IERC7572).interfaceId), true);
|
|
27
|
+
assertEq(coin.supportsInterface(type(ICoin).interfaceId), true);
|
|
28
|
+
assertEq(coin.supportsInterface(type(ICoinComments).interfaceId), true);
|
|
29
|
+
assertEq(coin.supportsInterface(type(IERC7572).interfaceId), true);
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
function test_contract_version() public {
|
|
20
33
|
_deployCoin();
|
|
21
34
|
string memory package = vm.readFile("./package.json");
|
|
@@ -658,4 +671,14 @@ contract CoinTest is BaseTest {
|
|
|
658
671
|
vm.expectRevert(abi.encodeWithSelector(MultiOwnable.OnlyOwner.selector));
|
|
659
672
|
coin.setNameAndSymbol(newName, newSymbol);
|
|
660
673
|
}
|
|
674
|
+
|
|
675
|
+
function test_update_metadata_reverts_if_name_is_blank() public {
|
|
676
|
+
_deployCoin();
|
|
677
|
+
string memory newName = "";
|
|
678
|
+
string memory newSymbol = "NEW";
|
|
679
|
+
|
|
680
|
+
vm.prank(users.creator);
|
|
681
|
+
vm.expectRevert(abi.encodeWithSelector(ICoin.NameIsRequired.selector));
|
|
682
|
+
coin.setNameAndSymbol(newName, newSymbol);
|
|
683
|
+
}
|
|
661
684
|
}
|
|
@@ -123,6 +123,33 @@ contract LiquidityMigrationTest is BaseTest {
|
|
|
123
123
|
assertEq(newPoolKey.tickSpacing, poolKey.tickSpacing, "poolkey tickSpacing");
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
function test_migrateLiquidity_enablesSwapsOnOldPoolKey() public {
|
|
127
|
+
address currency = address(mockERC20A);
|
|
128
|
+
mockERC20A.mint(address(poolManager), 1_000_000_000 ether);
|
|
129
|
+
_deployV4Coin(currency);
|
|
130
|
+
|
|
131
|
+
address trader = makeAddr("trader");
|
|
132
|
+
|
|
133
|
+
mockERC20A.mint(trader, 10 ether);
|
|
134
|
+
|
|
135
|
+
// do some swaps
|
|
136
|
+
_swapSomeCurrencyForCoin(coinV4, currency, 1 ether, trader);
|
|
137
|
+
_swapSomeCoinForCurrency(coinV4, currency, uint128(coinV4.balanceOf(trader)), trader);
|
|
138
|
+
|
|
139
|
+
address newHook = address(new LiquidityMigrationReceiver());
|
|
140
|
+
|
|
141
|
+
PoolKey memory poolKey = coinV4.getPoolKey();
|
|
142
|
+
|
|
143
|
+
registerUpgradePath(address(poolKey.hooks), address(newHook));
|
|
144
|
+
|
|
145
|
+
// migrate the liquidity
|
|
146
|
+
vm.prank(users.creator);
|
|
147
|
+
coinV4.migrateLiquidity(address(newHook), "");
|
|
148
|
+
|
|
149
|
+
// now swap using the existing pool key, it should succeed
|
|
150
|
+
_swapSomeCurrencyForCoin(poolKey, coinV4, currency, uint128(mockERC20A.balanceOf(trader)), trader);
|
|
151
|
+
}
|
|
152
|
+
|
|
126
153
|
function test_migrateLiquidity_emitsLiquidityMigrated() public {
|
|
127
154
|
address currency = address(mockERC20A);
|
|
128
155
|
_deployV4Coin(currency);
|
package/test/Upgrades.t.sol
CHANGED
|
@@ -13,8 +13,20 @@ import {IWETH} from "../src/interfaces/IWETH.sol";
|
|
|
13
13
|
import {PoolKey} from "@uniswap/v4-core/src/types/PoolKey.sol";
|
|
14
14
|
import {Currency} from "@uniswap/v4-core/src/types/Currency.sol";
|
|
15
15
|
import {BuySupplyWithSwapRouterHook} from "../src/hooks/deployment/BuySupplyWithSwapRouterHook.sol";
|
|
16
|
-
|
|
16
|
+
import {ContentCoinHook} from "../src/hooks/ContentCoinHook.sol";
|
|
17
17
|
import {console} from "forge-std/console.sol";
|
|
18
|
+
import {IDeployedCoinVersionLookup} from "../src/interfaces/IDeployedCoinVersionLookup.sol";
|
|
19
|
+
import {IHooksUpgradeGate} from "../src/interfaces/IHooksUpgradeGate.sol";
|
|
20
|
+
import {HooksDeployment} from "../src/libs/HooksDeployment.sol";
|
|
21
|
+
import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
|
|
22
|
+
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
23
|
+
import {MultiOwnable} from "../src/utils/MultiOwnable.sol";
|
|
24
|
+
import {CoinV4} from "../src/CoinV4.sol";
|
|
25
|
+
import {UniV4SwapHelper} from "../src/libs/UniV4SwapHelper.sol";
|
|
26
|
+
import {StateLibrary} from "@uniswap/v4-core/src/libraries/StateLibrary.sol";
|
|
27
|
+
import {IZoraV4CoinHook} from "../src/interfaces/IZoraV4CoinHook.sol";
|
|
28
|
+
import {PoolStateReader} from "../src/libs/PoolStateReader.sol";
|
|
29
|
+
import {LpPosition} from "../src/types/LpPosition.sol";
|
|
18
30
|
|
|
19
31
|
contract BadImpl {
|
|
20
32
|
function contractName() public pure returns (string memory) {
|
|
@@ -159,4 +171,171 @@ contract UpgradesTest is BaseTest, CoinsDeployerBase {
|
|
|
159
171
|
// do some swaps to test out
|
|
160
172
|
_swapSomeCoinForCurrency(ICoinV4(coinAddress), ZORA, uint128(IERC20(coinAddress).balanceOf(trader)), trader);
|
|
161
173
|
}
|
|
174
|
+
|
|
175
|
+
address coinVersionLookup = 0x777777751622c0d3258f214F9DF38E35BF45baF3;
|
|
176
|
+
address upgradeGate = 0xD88f6BdD765313CaFA5888C177c325E2C3AbF2D2;
|
|
177
|
+
|
|
178
|
+
function _swapSomeCurrencyForCoinAndExpectRevert(ICoinV4 _coin, address currency, uint128 amountIn, address trader) internal {
|
|
179
|
+
uint128 minAmountOut = uint128(0);
|
|
180
|
+
|
|
181
|
+
(bytes memory commands, bytes[] memory inputs) = UniV4SwapHelper.buildExactInputSingleSwapCommand(
|
|
182
|
+
currency,
|
|
183
|
+
amountIn,
|
|
184
|
+
address(_coin),
|
|
185
|
+
minAmountOut,
|
|
186
|
+
_coin.getPoolKey(),
|
|
187
|
+
bytes("")
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
vm.startPrank(trader);
|
|
191
|
+
UniV4SwapHelper.approveTokenWithPermit2(permit2, address(router), currency, amountIn, uint48(block.timestamp + 1 days));
|
|
192
|
+
|
|
193
|
+
// Execute the swap
|
|
194
|
+
uint256 deadline = block.timestamp + 20;
|
|
195
|
+
vm.expectRevert();
|
|
196
|
+
router.execute(commands, inputs, deadline);
|
|
197
|
+
|
|
198
|
+
vm.stopPrank();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function test_canCanFixBrokenContentCoinAndSwap() public {
|
|
202
|
+
vm.createSelectFork("base", 31835069);
|
|
203
|
+
|
|
204
|
+
address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
|
|
205
|
+
|
|
206
|
+
address contentCoin = 0x4E93A01c90f812284F71291a8d1415a904957156;
|
|
207
|
+
|
|
208
|
+
address creatorCoin = ICoinV4(contentCoin).currency();
|
|
209
|
+
|
|
210
|
+
uint256 amountIn = IERC20(creatorCoin).balanceOf(trader);
|
|
211
|
+
|
|
212
|
+
require(amountIn > 0, "no balance");
|
|
213
|
+
|
|
214
|
+
// this swap should revert because the content coin is broken
|
|
215
|
+
_swapSomeCurrencyForCoinAndExpectRevert(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
|
|
216
|
+
|
|
217
|
+
bytes memory creationCode = HooksDeployment.contentCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
|
|
218
|
+
|
|
219
|
+
(IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
|
|
220
|
+
|
|
221
|
+
// etch new hook into the content coin, it shouldn't revert anymore when swapping
|
|
222
|
+
vm.etch(address(ICoinV4(contentCoin).hooks()), address(newHook).code);
|
|
223
|
+
|
|
224
|
+
_swapSomeCurrencyForCoin(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function test_canUpgradeBrokenContentCoinAndSwap() public {
|
|
228
|
+
vm.createSelectFork("base", 31835069);
|
|
229
|
+
|
|
230
|
+
address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
|
|
231
|
+
|
|
232
|
+
address contentCoin = 0x4E93A01c90f812284F71291a8d1415a904957156;
|
|
233
|
+
|
|
234
|
+
address creatorCoin = ICoinV4(contentCoin).currency();
|
|
235
|
+
|
|
236
|
+
address existingHook = 0xd3D133469ADC85e01A4887404D8AC12d630e9040;
|
|
237
|
+
|
|
238
|
+
uint256 amountIn = IERC20(creatorCoin).balanceOf(trader);
|
|
239
|
+
|
|
240
|
+
bytes memory creationCode = HooksDeployment.contentCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
|
|
241
|
+
|
|
242
|
+
(IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
|
|
243
|
+
|
|
244
|
+
address[] memory baseImpls = new address[](1);
|
|
245
|
+
baseImpls[0] = existingHook;
|
|
246
|
+
|
|
247
|
+
vm.prank(Ownable(upgradeGate).owner());
|
|
248
|
+
IHooksUpgradeGate(upgradeGate).registerUpgradePath(baseImpls, address(newHook));
|
|
249
|
+
|
|
250
|
+
vm.prank(MultiOwnable(contentCoin).owners()[0]);
|
|
251
|
+
CoinV4(contentCoin).migrateLiquidity(address(newHook), "");
|
|
252
|
+
|
|
253
|
+
// do some swaps to test out
|
|
254
|
+
_swapSomeCurrencyForCoin(ICoinV4(contentCoin), creatorCoin, uint128(amountIn), trader);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function getPositionInfo(
|
|
258
|
+
PoolKey memory key,
|
|
259
|
+
address owner,
|
|
260
|
+
int24 tickLower,
|
|
261
|
+
int24 tickUpper
|
|
262
|
+
) internal view returns (uint128 liquidity, uint256 feeGrowthInside0LastX128, uint256 feeGrowthInside1LastX128) {
|
|
263
|
+
return StateLibrary.getPositionInfo(poolManager, key.toId(), owner, tickLower, tickUpper, bytes32(0));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function getLiquidityForPositions(PoolKey memory key, LpPosition[] memory positions) internal view returns (uint128[] memory liquidityForPositions) {
|
|
267
|
+
liquidityForPositions = new uint128[](positions.length);
|
|
268
|
+
|
|
269
|
+
for (uint256 i = 0; i < positions.length; i++) {
|
|
270
|
+
(uint128 liquidity, , ) = getPositionInfo(key, address(key.hooks), positions[i].tickLower, positions[i].tickUpper);
|
|
271
|
+
liquidityForPositions[i] = liquidity;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function getLiquidityForPoolCoin(ICoinV4 coin) internal view returns (uint128[] memory liquidityForPositions) {
|
|
276
|
+
return getLiquidityForPositions(coin.getPoolKey(), IZoraV4CoinHook(address(coin.hooks())).getPoolCoin(coin.getPoolKey()).positions);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function test_canUpgradeBrokenCreatorCoinAndSwap() public {
|
|
280
|
+
vm.createSelectFork("base", 31872861);
|
|
281
|
+
|
|
282
|
+
address trader = 0xf69fEc6d858c77e969509843852178bd24CAd2B6;
|
|
283
|
+
|
|
284
|
+
ICoinV4 creatorCoin = ICoinV4(0x2F03aB8fD97F5874bc3274C296Bb954Ae92EdA34);
|
|
285
|
+
|
|
286
|
+
address zora = creatorCoin.currency();
|
|
287
|
+
|
|
288
|
+
address existingHook = address(creatorCoin.hooks());
|
|
289
|
+
|
|
290
|
+
bytes memory creationCode = HooksDeployment.creatorCoinCreationCode(address(poolManager), coinVersionLookup, new address[](0), upgradeGate);
|
|
291
|
+
|
|
292
|
+
(IHooks newHook, ) = HooksDeployment.deployHookWithExistingOrNewSalt(address(this), creationCode, bytes32(0));
|
|
293
|
+
|
|
294
|
+
address[] memory baseImpls = new address[](1);
|
|
295
|
+
baseImpls[0] = existingHook;
|
|
296
|
+
|
|
297
|
+
vm.prank(Ownable(upgradeGate).owner());
|
|
298
|
+
IHooksUpgradeGate(upgradeGate).registerUpgradePath(baseImpls, address(newHook));
|
|
299
|
+
|
|
300
|
+
LpPosition[] memory beforePositions = IZoraV4CoinHook(address(creatorCoin.hooks())).getPoolCoin(creatorCoin.getPoolKey()).positions;
|
|
301
|
+
PoolKey memory beforeKey = creatorCoin.getPoolKey();
|
|
302
|
+
|
|
303
|
+
uint128[] memory beforeLiquidity = getLiquidityForPositions(beforeKey, beforePositions);
|
|
304
|
+
// get before price
|
|
305
|
+
uint160 beforePrice = PoolStateReader.getSqrtPriceX96(creatorCoin.getPoolKey(), poolManager);
|
|
306
|
+
|
|
307
|
+
vm.prank(MultiOwnable(address(creatorCoin)).owners()[0]);
|
|
308
|
+
CoinV4(address(creatorCoin)).migrateLiquidity(address(newHook), "");
|
|
309
|
+
|
|
310
|
+
// get liquidity of original positions after migration
|
|
311
|
+
uint128[] memory liquidityOfPositionsAfterMigration = getLiquidityForPositions(beforeKey, beforePositions);
|
|
312
|
+
|
|
313
|
+
// there should be no liquidity left in the original positions after migration
|
|
314
|
+
for (uint256 i = 0; i < liquidityOfPositionsAfterMigration.length; i++) {
|
|
315
|
+
assertEq(liquidityOfPositionsAfterMigration[i], 0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// get liquidity of new positions after migration
|
|
319
|
+
PoolKey memory afterKey = creatorCoin.getPoolKey();
|
|
320
|
+
LpPosition[] memory afterPositions = IZoraV4CoinHook(address(afterKey.hooks)).getPoolCoin(afterKey).positions;
|
|
321
|
+
uint128[] memory afterLiquidity = getLiquidityForPositions(afterKey, afterPositions);
|
|
322
|
+
|
|
323
|
+
for (uint256 i = 0; i < beforeLiquidity.length; i++) {
|
|
324
|
+
// we added any extra liquidity to the last position, so we don't expect it to be the same
|
|
325
|
+
if (i != beforeLiquidity.length - 1) {
|
|
326
|
+
assertApproxEqAbs(beforeLiquidity[i], afterLiquidity[i], 200);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
uint160 afterPrice = PoolStateReader.getSqrtPriceX96(creatorCoin.getPoolKey(), poolManager);
|
|
331
|
+
|
|
332
|
+
assertEq(beforePrice, afterPrice);
|
|
333
|
+
|
|
334
|
+
// make sure that the new hook has no balance of 0 or 1
|
|
335
|
+
assertApproxEqAbs(creatorCoin.getPoolKey().currency0.balanceOf(address(newHook)), 0, 10);
|
|
336
|
+
assertApproxEqAbs(creatorCoin.getPoolKey().currency1.balanceOf(address(newHook)), 0, 10);
|
|
337
|
+
|
|
338
|
+
// now try to swap some currency for the creator coin - it should succeed
|
|
339
|
+
_swapSomeCurrencyForCoin(creatorCoin, zora, uint128(IERC20(zora).balanceOf(trader) / 2), trader);
|
|
340
|
+
}
|
|
162
341
|
}
|