From 36bdf20cb1d59532f55707ba19e59b9956191fb9 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 18:07:35 +0400 Subject: [PATCH 01/29] First pass at Uniswap V3 + allocated allowlist DTL --- .../UniswapV3DTLWithAllocatedAllowlist.sol | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol new file mode 100644 index 00000000..8018beb7 --- /dev/null +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {MerkleProof} from "@openzeppelin-contracts-4.9.2/utils/cryptography/MerkleProof.sol"; +import {Owned} from "@solmate-6.7.0/auth/Owned.sol"; + +import {UniswapV3DirectToLiquidity} from "./UniswapV3DTL.sol"; +import {BaseDirectToLiquidity} from "./BaseDTL.sol"; + +/// @notice Allocated allowlist version of the Uniswap V3 Direct To Liquidity callback. +/// @notice This version allows for each address in the Merkle tree to have a per-address amount of quote tokens they can spend. +/// @dev The merkle tree is expected to have both an address and an amount of quote tokens they can spend in each leaf. +contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned { + // ========== ERRORS ========== // + + /// @notice Error message when the bid amount exceeds the limit assigned to a buyer + error Callback_ExceedsLimit(); + + /// @notice Error message when the callback state does not support the action + error Callback_InvalidState(); + + // ========== EVENTS ========== // + + /// @notice Emitted when the merkle root is set + event MerkleRootSet(uint96 lotId, bytes32 merkleRoot); + + // ========== STATE VARIABLES ========== // + + /// @notice The root of the merkle tree that represents the allowlist + /// @dev The merkle tree should adhere to the format specified in the OpenZeppelin MerkleProof library at https://github.com/OpenZeppelin/merkle-tree + /// In particular, leaf values (such as `(address)` or `(address,uint256)`) should be double-hashed. + mapping(uint96 => bytes32) public lotMerkleRoot; + + /// @notice Tracks the cumulative amount spent by a buyer + mapping(uint96 => mapping(address => uint256)) public lotBuyerSpent; + + // ========== CONSTRUCTOR ========== // + + // PERMISSIONS + // onCreate: true + // onCancel: true + // onCurate: true + // onPurchase: false + // onBid: true + // onSettle: true + // receiveQuoteTokens: true + // sendBaseTokens: true + // Contract prefix should be: 11101111 = 0xEF + + constructor( + address auctionHouse_, + address uniV3Factory_, + address gUniFactory_, + address owner_ + ) UniswapV3DirectToLiquidity(auctionHouse_, uniV3Factory_, gUniFactory_) Owned(owner_) {} + + // ========== CALLBACKS ========== // + + /// @inheritdoc BaseDirectToLiquidity + function __onCreate( + uint96 lotId_, + address seller_, + address baseToken_, + address quoteToken_, + uint256 capacity_, + bool prefund_, + bytes calldata callbackData_ + ) internal virtual override { + // Validate the UniswapV3 parameters + super.__onCreate( + lotId_, seller_, baseToken_, quoteToken_, capacity_, prefund_, callbackData_ + ); + + // Check that the parameters are of the correct length + if (callbackData_.length != 32) { + revert Callback_InvalidParams(); + } + + // Decode the merkle root from the callback data + bytes32 merkleRootParams = abi.decode(callbackData_, (bytes32)); + + // Set the merkle root and buyer limit + lotMerkleRoot[lotId_] = merkleRootParams; + emit MerkleRootSet(lotId_, merkleRootParams); + } + + /// @inheritdoc BaseDirectToLiquidity + /// + /// @param callbackData_ abi-encoded data: (bytes32[], uint256) representing the merkle proof and allocated amount + function _onBid( + uint96 lotId_, + uint64 bidId_, + address buyer_, + uint256 amount_, + bytes calldata callbackData_ + ) internal pure override { + // Validate that the buyer is allowed to participate + uint256 allocatedAmount = _canParticipate(lotId_, buyer_, callbackData_); + + // Validate that the buyer can buy the amount + _canBuy(lotId_, buyer_, amount_, allocatedAmount); + } + + // ========== INTERNAL FUNCTIONS ========== // + + /// @dev The buyer must provide the proof and their total allocated amount in the callback data for this to succeed. + function _canParticipate( + uint96 lotId_, + address buyer_, + bytes calldata callbackData_ + ) internal view returns (uint256) { + // Decode the merkle proof from the callback data + (bytes32[] memory proof, uint256 allocatedAmount) = + abi.decode(callbackData_, (bytes32[], uint256)); + + // Get the leaf for the buyer + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(buyer_, allocatedAmount)))); + + // Validate the merkle proof + if (!MerkleProof.verify(proof, lotMerkleRoot[lotId_], leaf)) { + revert Callback_NotAuthorized(); + } + + // Return the allocated amount for the buyer + return allocatedAmount; + } + + function _canBuy( + uint96 lotId_, + address buyer_, + uint256 amount_, + uint256 allocatedAmount_ + ) internal { + // Check if the buyer has already spent their limit + if (lotBuyerSpent[lotId_][buyer_] + amount_ > allocatedAmount_) { + revert Callback_ExceedsLimit(); + } + + // Update the buyer spent amount + lotBuyerSpent[lotId_][buyer_] += amount_; + } + + // ========== ADMIN FUNCTIONS ========== // + + /// @notice Sets the merkle root for the allowlist + /// This function can be called by the owner to update the merkle root after `onCreate()`. + /// @dev This function performs the following: + /// - Performs validation + /// - Sets the merkle root + /// - Emits a MerkleRootSet event + /// + /// This function reverts if: + /// - The caller is not the owner + /// - The auction has not been registered + /// - The auction has been completed + /// + /// @param merkleRoot_ The new merkle root + function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external onlyOwner { + // Revert if onCreate has not been called + if (lotId_ == type(uint96).max) { + revert Callback_InvalidState(); + } + + // Revert if the auction has been completed already + if (!lotConfiguration[lotId_].active) { + revert Callback_AlreadyComplete(); + } + + lotMerkleRoot[lotId_] = merkleRoot_; + + emit MerkleRootSet(lotId_, merkleRoot_); + } +} From 100e14bb1cb92fc6dd7fad3d80040e869719d34d Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 18:15:33 +0400 Subject: [PATCH 02/29] chore: Update soldeer.lock --- soldeer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/soldeer.lock b/soldeer.lock index 6def550e..fcf7f737 100644 --- a/soldeer.lock +++ b/soldeer.lock @@ -1,78 +1,78 @@ [[dependencies]] name = "@openzeppelin-contracts" version = "4.9.2" -source = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts/4_9_2_22-01-2024_13:13:52_contracts.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts/4_9_2_22-01-2024_13:13:52_contracts.zip" checksum = "0f4450671798ea5659e6391876a3cf443ca50a696d9b556ac622ec7660bce306" integrity = "f69bd90f264280204b2a1172a02a2d20f3611f5993a61e5215647bec696a8420" [[dependencies]] name = "@openzeppelin-contracts-upgradeable" version = "4.9.2" -source = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts-upgradeable/4_9_2_22-01-2024_13:15:04_contracts-upgradeable.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts-upgradeable/4_9_2_22-01-2024_13:15:04_contracts-upgradeable.zip" checksum = "33a161bf7799dcac1475d2470615b56a8f9a9387cb8eef921b49816dbbc61c2b" integrity = "93ffee03edd3f6b0cad1830d6cb1937c5c870fab9eccaaeabbf1b752c6d4e8f1" [[dependencies]] name = "@uniswap-v2-core" version = "1.0.1" -source = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v2-core/1_0_1_22-01-2024_13:18:30_v2-core.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v2-core/1_0_1_22-01-2024_13:18:30_v2-core.zip" checksum = "efebb89237048771c19f52d3ce87ec4d0c591279bf1977c49f9e70e5fff530f0" integrity = "fda4e18a2a0c21eeddd8b6af36439f394e4ff74eb75705409a87b8952c9e2972" [[dependencies]] name = "@uniswap-v2-periphery" version = "1.0.1" -source = "git@github.com:Axis-Fi/uniswap-v2-periphery.git" -checksum = "19be650786731dfe43cac3aac7a2d1f0731d18e2" +git = "git@github.com:Axis-Fi/uniswap-v2-periphery.git" +rev = "19be650786731dfe43cac3aac7a2d1f0731d18e2" [[dependencies]] name = "@uniswap-v3-core" version = "1.0.1-solc-0.8-simulate" -source = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v3-core/1_0_1-solc-0_8-simulate_22-01-2024_13:19:52_v3-core.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/@uniswap-v3-core/1_0_1-solc-0_8-simulate_22-01-2024_13:19:52_v3-core.zip" checksum = "566fc479fe846f41b211a0ddd66f875cd37e2ccb86b3fc4f7fa18bd55266ec7d" integrity = "75f26f8cb2cd8179eace9cdc4b248fa75faae799fc19c3e5a1f8f1b9d58d3188" [[dependencies]] name = "@uniswap-v3-periphery" version = "1.4.2-solc-0.8" -source = "git@github.com:Uniswap/v3-periphery.git" -checksum = "b325bb0905d922ae61fcc7df85ee802e8df5e96c" +git = "git@github.com:Uniswap/v3-periphery.git" +rev = "b325bb0905d922ae61fcc7df85ee802e8df5e96c" [[dependencies]] name = "axis-core" version = "1.0.1" -source = "https://soldeer-revisions.s3.amazonaws.com/axis-core/1_0_1_22-08-2024_01:53:20_axis-core.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/axis-core/1_0_1_22-08-2024_01:53:20_axis-core.zip" checksum = "90ee8eca451f4454ad911c52d014bebbbacc3e0ba2260ad19e56e32598ea9d21" integrity = "381ce84e3d947c891a53aa651a59328bdcba27534116bf5c55f57833a5603962" [[dependencies]] name = "clones-with-immutable-args" version = "1.1.1" -source = "git@github.com:wighawag/clones-with-immutable-args.git" -checksum = "f5ca191afea933d50a36d101009b5644dc28bc99" +git = "git@github.com:wighawag/clones-with-immutable-args.git" +rev = "f5ca191afea933d50a36d101009b5644dc28bc99" [[dependencies]] name = "forge-std" version = "1.9.1" -source = "https://soldeer-revisions.s3.amazonaws.com/forge-std/v1_9_1_03-07-2024_14:44:59_forge-std-v1.9.1.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/forge-std/v1_9_1_03-07-2024_14:44:59_forge-std-v1.9.1.zip" checksum = "110b35ad3604d91a919c521c71206c18cd07b29c750bd90b5cbbaf37288c9636" -integrity = "229fada41d3af5734ba5e8b2715734b99c7d70335f3dd5a103d2a2e1cae831ba" +integrity = "389f8bfe6b6aad01915b1e38e6d4839f8189e8d4792b42be4e10d0a96a358e3f" [[dependencies]] name = "g-uni-v1-core" version = "0.9.9" -source = "git@github.com:Axis-Fi/g-uni-v1-core.git" -checksum = "d6bcb6e811e86d36bc836c002eb2e9a2c73d29ca" +git = "git@github.com:Axis-Fi/g-uni-v1-core.git" +rev = "d6bcb6e811e86d36bc836c002eb2e9a2c73d29ca" [[dependencies]] name = "solady" version = "0.0.124" -source = "https://soldeer-revisions.s3.amazonaws.com/solady/0_0_124_22-01-2024_13:28:04_solady.zip" +url = "https://soldeer-revisions.s3.amazonaws.com/solady/0_0_124_22-01-2024_13:28:04_solady.zip" checksum = "9342385eaad08f9bb5408be0b41b241dd2b974c001f7da8c3b1ac552b52ce16b" integrity = "29d93e52694d8e858cf5a737257f4a6f21aefccaf803174fd00b9d686172ab27" [[dependencies]] name = "solmate" version = "6.7.0" -source = "git@github.com:transmissions11/solmate.git" -checksum = "c892309933b25c03d32b1b0d674df7ae292ba925" +git = "git@github.com:transmissions11/solmate.git" +rev = "c892309933b25c03d32b1b0d674df7ae292ba925" From 520a45f36df75fb369c5a4e7b243a365f97ea1d3 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 18:15:59 +0400 Subject: [PATCH 03/29] Mark BaseDTL functions as virtual --- src/callbacks/liquidity/BaseDTL.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/callbacks/liquidity/BaseDTL.sol b/src/callbacks/liquidity/BaseDTL.sol index 5cb638b2..4bb94d1e 100644 --- a/src/callbacks/liquidity/BaseDTL.sol +++ b/src/callbacks/liquidity/BaseDTL.sol @@ -232,7 +232,7 @@ abstract contract BaseDirectToLiquidity is BaseCallback { /// - The lot has already been completed /// /// @param lotId_ The lot ID - function _onCancel(uint96 lotId_, uint256, bool, bytes calldata) internal override { + function _onCancel(uint96 lotId_, uint256, bool, bytes calldata) internal virtual override { // Check that the lot is active if (!lotConfiguration[lotId_].active) { revert Callback_AlreadyComplete(); @@ -258,7 +258,7 @@ abstract contract BaseDirectToLiquidity is BaseCallback { uint256 curatorPayout_, bool, bytes calldata - ) internal override { + ) internal virtual override { // Check that the lot is active if (!lotConfiguration[lotId_].active) { revert Callback_AlreadyComplete(); @@ -278,14 +278,14 @@ abstract contract BaseDirectToLiquidity is BaseCallback { uint256, bool, bytes calldata - ) internal pure override { + ) internal virtual override { // Not implemented revert Callback_NotImplemented(); } /// @notice Callback for a bid /// @dev Not implemented - function _onBid(uint96, uint64, address, uint256, bytes calldata) internal pure override { + function _onBid(uint96, uint64, address, uint256, bytes calldata) internal virtual override { // Not implemented revert Callback_NotImplemented(); } From aea470741f7fec8be216277f7df17ab6c2899d0a Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 18:16:05 +0400 Subject: [PATCH 04/29] Fix compiler error --- src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 8018beb7..9687c7c7 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -93,7 +93,7 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned address buyer_, uint256 amount_, bytes calldata callbackData_ - ) internal pure override { + ) internal override { // Validate that the buyer is allowed to participate uint256 allocatedAmount = _canParticipate(lotId_, buyer_, callbackData_); From f04bbc869576bf52ceaf711f84ac2479dd3dd4b8 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 21:26:57 +0400 Subject: [PATCH 05/29] Workaround for setting merkle root --- .../UniswapV3DTLWithAllocatedAllowlist.sol | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 9687c7c7..7fecba72 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -26,6 +26,9 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned // ========== STATE VARIABLES ========== // + /// @notice The seller address for each lot + mapping(uint96 => address) public lotSeller; + /// @notice The root of the merkle tree that represents the allowlist /// @dev The merkle tree should adhere to the format specified in the OpenZeppelin MerkleProof library at https://github.com/OpenZeppelin/merkle-tree /// In particular, leaf values (such as `(address)` or `(address,uint256)`) should be double-hashed. @@ -57,6 +60,11 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned // ========== CALLBACKS ========== // /// @inheritdoc BaseDirectToLiquidity + /// @dev This function performs the following: + /// - Stores the seller address + /// - Passes the remaining parameters to the UniswapV3DTL implementation + /// + /// Due to the way that the callback data is structured, the merkle root cannot be passed in as part of the callback data. Instead, the seller must call `setMerkleRoot()` after `onCreate()` to set the merkle root. function __onCreate( uint96 lotId_, address seller_, @@ -66,34 +74,29 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned bool prefund_, bytes calldata callbackData_ ) internal virtual override { - // Validate the UniswapV3 parameters - super.__onCreate( - lotId_, seller_, baseToken_, quoteToken_, capacity_, prefund_, callbackData_ - ); + // Store the seller address + lotSeller[lotId_] = seller_; - // Check that the parameters are of the correct length - if (callbackData_.length != 32) { - revert Callback_InvalidParams(); - } - - // Decode the merkle root from the callback data - bytes32 merkleRootParams = abi.decode(callbackData_, (bytes32)); - - // Set the merkle root and buyer limit - lotMerkleRoot[lotId_] = merkleRootParams; - emit MerkleRootSet(lotId_, merkleRootParams); + // Pass to the UniswapV3DTL implementation + super.__onCreate(lotId_, seller_, baseToken_, quoteToken_, capacity_, prefund_, callbackData_); } /// @inheritdoc BaseDirectToLiquidity + /// @dev This function will revert if: + /// - The callback data is invalid + /// - The bid amount exceeds the allocated amount for the buyer + /// - The merkle root for the auction has not been set by the seller /// /// @param callbackData_ abi-encoded data: (bytes32[], uint256) representing the merkle proof and allocated amount function _onBid( uint96 lotId_, - uint64 bidId_, + uint64, address buyer_, uint256 amount_, bytes calldata callbackData_ ) internal override { + // Validate that the merkle root has been set + // Validate that the buyer is allowed to participate uint256 allocatedAmount = _canParticipate(lotId_, buyer_, callbackData_); @@ -156,16 +159,28 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned /// /// @param merkleRoot_ The new merkle root function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external onlyOwner { - // Revert if onCreate has not been called - if (lotId_ == type(uint96).max) { + DTLConfiguration memory lotConfig = lotConfiguration[lotId_]; + + // Validate that onCreate has been called for this lot + if (lotConfig.recipient == address(0)) { revert Callback_InvalidState(); } - // Revert if the auction has been completed already - if (!lotConfiguration[lotId_].active) { + // Validate that the auction is active + if (lotConfig.active == false) { revert Callback_AlreadyComplete(); } + // Validate that the caller is the seller + if (msg.sender != lotSeller[lotId_]) { + revert Callback_NotAuthorized(); + } + + // Validate that the merkle root is of the correct length + if (merkleRoot_.length != 32) { + revert Callback_InvalidParams(); + } + lotMerkleRoot[lotId_] = merkleRoot_; emit MerkleRootSet(lotId_, merkleRoot_); From 3b46f126b9ec7a6dc409cdadcd07da87aa0e6fc0 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:01:23 +0400 Subject: [PATCH 06/29] Modify BaseDTL and derivatives to support passing in the permissions --- script/deploy/Deploy.s.sol | 60 ++++++++++++++++--- script/salts/salts.json | 4 +- script/salts/test/TestSalts.s.sol | 32 +++++++++- src/callbacks/liquidity/BaseDTL.sol | 19 +----- src/callbacks/liquidity/UniswapV2DTL.sol | 6 +- src/callbacks/liquidity/UniswapV3DTL.sol | 16 ++++- .../UniswapV2DTL/UniswapV2DTLTest.sol | 14 ++++- .../UniswapV3DTL/UniswapV3DTLTest.sol | 14 ++++- test/invariant/Setup.sol | 23 +++++-- 9 files changed, 150 insertions(+), 38 deletions(-) diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index a4dc43b1..20c8fde4 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -286,11 +286,22 @@ contract Deploy is Script, WithDeploySequence, WithSalts { "UniswapV2Router.factory() does not match given Uniswap V2 factory address" ); + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt bytes32 salt_ = _getSalt( sequenceName_, type(UniswapV2DirectToLiquidity).creationCode, - abi.encode(atomicAuctionHouse, uniswapV2Factory, uniswapV2Router) + abi.encode(atomicAuctionHouse, uniswapV2Factory, uniswapV2Router, permissions) ); // Revert if the salt is not set @@ -302,7 +313,7 @@ contract Deploy is Script, WithDeploySequence, WithSalts { vm.broadcast(); UniswapV2DirectToLiquidity cbAtomicUniswapV2Dtl = new UniswapV2DirectToLiquidity{ salt: salt_ - }(atomicAuctionHouse, uniswapV2Factory, uniswapV2Router); + }(atomicAuctionHouse, uniswapV2Factory, uniswapV2Router, permissions); console2.log(""); console2.log(" deployed at:", address(cbAtomicUniswapV2Dtl)); @@ -330,11 +341,22 @@ contract Deploy is Script, WithDeploySequence, WithSalts { "UniswapV2Router.factory() does not match given Uniswap V2 factory address" ); + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt bytes32 salt_ = _getSalt( deploymentKey, type(UniswapV2DirectToLiquidity).creationCode, - abi.encode(batchAuctionHouse, uniswapV2Factory, uniswapV2Router) + abi.encode(batchAuctionHouse, uniswapV2Factory, uniswapV2Router, permissions) ); // Revert if the salt is not set @@ -345,7 +367,7 @@ contract Deploy is Script, WithDeploySequence, WithSalts { vm.broadcast(); UniswapV2DirectToLiquidity cbBatchUniswapV2Dtl = new UniswapV2DirectToLiquidity{salt: salt_}( - batchAuctionHouse, uniswapV2Factory, uniswapV2Router + batchAuctionHouse, uniswapV2Factory, uniswapV2Router, permissions ); console2.log(""); console2.log(" deployed at:", address(cbBatchUniswapV2Dtl)); @@ -375,11 +397,22 @@ contract Deploy is Script, WithDeploySequence, WithSalts { "GUniFactory.factory() does not match given Uniswap V3 factory address" ); + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt bytes32 salt_ = _getSalt( deploymentKey, type(UniswapV3DirectToLiquidity).creationCode, - abi.encode(atomicAuctionHouse, uniswapV3Factory, gUniFactory) + abi.encode(atomicAuctionHouse, uniswapV3Factory, gUniFactory, permissions) ); // Revert if the salt is not set @@ -391,7 +424,7 @@ contract Deploy is Script, WithDeploySequence, WithSalts { vm.broadcast(); UniswapV3DirectToLiquidity cbAtomicUniswapV3Dtl = new UniswapV3DirectToLiquidity{ salt: salt_ - }(atomicAuctionHouse, uniswapV3Factory, gUniFactory); + }(atomicAuctionHouse, uniswapV3Factory, gUniFactory, permissions); console2.log(""); console2.log(" deployed at:", address(cbAtomicUniswapV3Dtl)); @@ -420,11 +453,22 @@ contract Deploy is Script, WithDeploySequence, WithSalts { "GUniFactory.factory() does not match given Uniswap V3 factory address" ); + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt bytes32 salt_ = _getSalt( deploymentKey, type(UniswapV3DirectToLiquidity).creationCode, - abi.encode(batchAuctionHouse, uniswapV3Factory, gUniFactory) + abi.encode(batchAuctionHouse, uniswapV3Factory, gUniFactory, permissions) ); // Revert if the salt is not set @@ -435,7 +479,7 @@ contract Deploy is Script, WithDeploySequence, WithSalts { vm.broadcast(); UniswapV3DirectToLiquidity cbBatchUniswapV3Dtl = new UniswapV3DirectToLiquidity{salt: salt_}( - batchAuctionHouse, uniswapV3Factory, gUniFactory + batchAuctionHouse, uniswapV3Factory, gUniFactory, permissions ); console2.log(""); console2.log(" deployed at:", address(cbBatchUniswapV3Dtl)); diff --git a/script/salts/salts.json b/script/salts/salts.json index 0a351ed6..1ebe2675 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -96,13 +96,13 @@ "0xb789c4afd1a886c5cfeb88fbd8b09ae8ec1b3869e50a0b8527289817f2e25218": "0xe33f41bdf6be9ac2a67f006ff3fa86cf5974fba590d3b14514751adf8d1f63ac" }, "Test_UniswapV2DirectToLiquidity": { - "0x73e92c9fa7edbd64b00a40b781f6c757025945f0a761bc0b75764a6e401c91db": "0x82cef4b767766ea17c0232cad10798847f9c23fd04774b19b72ccd443321d6cb" + "0x4e58c10856f2239319fe5013e7d340d3e1f33133faa1edc26441a414a4513394": "0x1f74ed93eb7f112f63a39f8aaf7a6c03a90f71021066567f1f53b5ab50586f07" }, "Test_UniswapV2Router": { "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, "Test_UniswapV3DirectToLiquidity": { - "0x8b8a67c1a77b2a6e6498afcc953996805627b791b07b022b75e61e93977bea7b": "0xb3bb1bc05e789ba09ea8b4273381d883a2377423cb399c907700ddda448864dd" + "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0x30a263ee7e40137d3022c6283eec6d799a26e584f55de45be9a5b48823633c4d" }, "Test_UniswapV3Factory": { "0x862fde1cd9de35dc112d759742b17a659781dfe0dddb8136e0b63fa9c2e00dab": "0x5fbe68e6c093ea70e56909c84fe99890a237a4af7f7599ace8471a48c78a8aae" diff --git a/script/salts/test/TestSalts.s.sol b/script/salts/test/TestSalts.s.sol index 309c547e..b619ca53 100644 --- a/script/salts/test/TestSalts.s.sol +++ b/script/salts/test/TestSalts.s.sol @@ -193,7 +193,21 @@ contract TestSalts is Script, WithEnvironment, Permit2User, WithSalts, TestConst } function generateUniswapV2DirectToLiquidity() public { - bytes memory args = abi.encode(_AUCTION_HOUSE, _UNISWAP_V2_FACTORY, _UNISWAP_V2_ROUTER); + bytes memory args = abi.encode( + _AUCTION_HOUSE, + _UNISWAP_V2_FACTORY, + _UNISWAP_V2_ROUTER, + Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }) + ); bytes memory contractCode = type(UniswapV2DirectToLiquidity).creationCode; (string memory bytecodePath, bytes32 bytecodeHash) = _writeBytecode("UniswapV2DirectToLiquidity", contractCode, args); @@ -201,7 +215,21 @@ contract TestSalts is Script, WithEnvironment, Permit2User, WithSalts, TestConst } function generateUniswapV3DirectToLiquidity() public { - bytes memory args = abi.encode(_AUCTION_HOUSE, _UNISWAP_V3_FACTORY, _GUNI_FACTORY); + bytes memory args = abi.encode( + _AUCTION_HOUSE, + _UNISWAP_V3_FACTORY, + _GUNI_FACTORY, + Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }) + ); bytes memory contractCode = type(UniswapV3DirectToLiquidity).creationCode; (string memory bytecodePath, bytes32 bytecodeHash) = _writeBytecode("UniswapV3DirectToLiquidity", contractCode, args); diff --git a/src/callbacks/liquidity/BaseDTL.sol b/src/callbacks/liquidity/BaseDTL.sol index 4bb94d1e..4e0545d6 100644 --- a/src/callbacks/liquidity/BaseDTL.sol +++ b/src/callbacks/liquidity/BaseDTL.sol @@ -94,22 +94,9 @@ abstract contract BaseDirectToLiquidity is BaseCallback { // ========== CONSTRUCTOR ========== // constructor( - address auctionHouse_ - ) - BaseCallback( - auctionHouse_, - Callbacks.Permissions({ - onCreate: true, - onCancel: true, - onCurate: true, - onPurchase: false, - onBid: false, - onSettle: true, - receiveQuoteTokens: true, - sendBaseTokens: false - }) - ) - {} + address auctionHouse_, + Callbacks.Permissions memory permissions_ + ) BaseCallback(auctionHouse_, permissions_) {} // ========== CALLBACK FUNCTIONS ========== // diff --git a/src/callbacks/liquidity/UniswapV2DTL.sol b/src/callbacks/liquidity/UniswapV2DTL.sol index 0fde44cc..ffc292a3 100644 --- a/src/callbacks/liquidity/UniswapV2DTL.sol +++ b/src/callbacks/liquidity/UniswapV2DTL.sol @@ -13,6 +13,7 @@ import {IUniswapV2Router02} from "@uniswap-v2-periphery-1.0.1/interfaces/IUniswa // Callbacks import {BaseDirectToLiquidity} from "./BaseDTL.sol"; +import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; /// @title UniswapV2DirectToLiquidity /// @notice This Callback contract deposits the proceeds from a batch auction into a Uniswap V2 pool @@ -54,8 +55,9 @@ contract UniswapV2DirectToLiquidity is BaseDirectToLiquidity { constructor( address auctionHouse_, address uniswapV2Factory_, - address uniswapV2Router_ - ) BaseDirectToLiquidity(auctionHouse_) { + address uniswapV2Router_, + Callbacks.Permissions memory permissions_ + ) BaseDirectToLiquidity(auctionHouse_, permissions_) { if (uniswapV2Factory_ == address(0)) { revert Callback_Params_InvalidAddress(); } diff --git a/src/callbacks/liquidity/UniswapV3DTL.sol b/src/callbacks/liquidity/UniswapV3DTL.sol index 7455d27f..c87460d9 100644 --- a/src/callbacks/liquidity/UniswapV3DTL.sol +++ b/src/callbacks/liquidity/UniswapV3DTL.sol @@ -19,6 +19,7 @@ import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; // Callbacks import {BaseDirectToLiquidity} from "./BaseDTL.sol"; +import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; /// @title UniswapV3DirectToLiquidity /// @notice This Callback contract deposits the proceeds from a batch auction into a Uniswap V3 pool @@ -69,11 +70,22 @@ contract UniswapV3DirectToLiquidity is BaseDirectToLiquidity { // ========== CONSTRUCTOR ========== // + // Default permissions: + // onCreate: true + // onCancel: true + // onCurate: true + // onPurchase: false + // onBid: false + // onSettle: true + // receiveQuoteTokens: true + // sendBaseTokens: false + constructor( address auctionHouse_, address uniV3Factory_, - address gUniFactory_ - ) BaseDirectToLiquidity(auctionHouse_) { + address gUniFactory_, + Callbacks.Permissions memory permissions_ + ) BaseDirectToLiquidity(auctionHouse_, permissions_) { if (uniV3Factory_ == address(0)) { revert Callback_Params_InvalidAddress(); } diff --git a/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol b/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol index 7f40c784..04e99ae4 100644 --- a/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol +++ b/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol @@ -139,7 +139,19 @@ abstract contract UniswapV2DirectToLiquidityTest is Test, Permit2User, WithSalts // Source: https://github.com/foundry-rs/foundry/issues/6402 vm.startBroadcast(); _dtl = new UniswapV2DirectToLiquidity{salt: salt}( - address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router) + address(_auctionHouse), + address(_uniV2Factory), + address(_uniV2Router), + Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }) ); vm.stopBroadcast(); diff --git a/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol b/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol index 0a8944b6..94b923cf 100644 --- a/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol +++ b/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol @@ -150,7 +150,19 @@ abstract contract UniswapV3DirectToLiquidityTest is Test, Permit2User, WithSalts // Source: https://github.com/foundry-rs/foundry/issues/6402 vm.startBroadcast(); _dtl = new UniswapV3DirectToLiquidity{salt: salt}( - address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory) + address(_auctionHouse), + address(_uniV3Factory), + address(_gUniFactory), + Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }) ); vm.stopBroadcast(); diff --git a/test/invariant/Setup.sol b/test/invariant/Setup.sol index 2ab4dbe6..b54cfaa4 100644 --- a/test/invariant/Setup.sol +++ b/test/invariant/Setup.sol @@ -195,9 +195,22 @@ abstract contract Setup is Test, Permit2User, WithSalts, TestConstants { _quoteToken = new MockERC20("Quote Token", "QT", 18); _baseToken = new MockERC20("Base Token", "BT", 18); + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + bytes memory constructorArgs = abi.encodePacked( type(UniswapV2DirectToLiquidity).creationCode, - abi.encode(address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router)) + abi.encode( + address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router), permissions + ) ); string[] memory uniswapV2Inputs = new string[](7); @@ -213,7 +226,7 @@ abstract contract Setup is Test, Permit2User, WithSalts, TestConstants { bytes32 uniswapV2Salt = abi.decode(uniswapV2Res, (bytes32)); _dtlV2 = new UniswapV2DirectToLiquidity{salt: uniswapV2Salt}( - address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router) + address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router), permissions ); _dtlV2Address = address(_dtlV2); @@ -232,7 +245,9 @@ abstract contract Setup is Test, Permit2User, WithSalts, TestConstants { bytes memory v3SaltArgs = abi.encodePacked( type(UniswapV3DirectToLiquidity).creationCode, - abi.encode(address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory)) + abi.encode( + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), permissions + ) ); string[] memory uniswapV3Inputs = new string[](7); @@ -248,7 +263,7 @@ abstract contract Setup is Test, Permit2User, WithSalts, TestConstants { bytes32 uniswapV3Salt = abi.decode(uniswapV3Res, (bytes32)); _dtlV3 = new UniswapV3DirectToLiquidity{salt: uniswapV3Salt}( - address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory) + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), permissions ); _dtlV3Address = address(_dtlV3); From 49c15ccf8f59cf7f70c48896462bd62697ba28c7 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:01:48 +0400 Subject: [PATCH 07/29] Correct permissions for allocated allowlist DTL. Misc fixes. --- .../UniswapV3DTLWithAllocatedAllowlist.sol | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 7fecba72..87eb62c7 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -6,6 +6,7 @@ import {Owned} from "@solmate-6.7.0/auth/Owned.sol"; import {UniswapV3DirectToLiquidity} from "./UniswapV3DTL.sol"; import {BaseDirectToLiquidity} from "./BaseDTL.sol"; +import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; /// @notice Allocated allowlist version of the Uniswap V3 Direct To Liquidity callback. /// @notice This version allows for each address in the Merkle tree to have a per-address amount of quote tokens they can spend. @@ -47,15 +48,32 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned // onBid: true // onSettle: true // receiveQuoteTokens: true - // sendBaseTokens: true - // Contract prefix should be: 11101111 = 0xEF + // sendBaseTokens: false + // Contract prefix should be: 11101110 = 0xEE constructor( address auctionHouse_, address uniV3Factory_, address gUniFactory_, address owner_ - ) UniswapV3DirectToLiquidity(auctionHouse_, uniV3Factory_, gUniFactory_) Owned(owner_) {} + ) + UniswapV3DirectToLiquidity( + auctionHouse_, + uniV3Factory_, + gUniFactory_, + Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: true, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }) + ) + Owned(owner_) + {} // ========== CALLBACKS ========== // @@ -78,7 +96,9 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned lotSeller[lotId_] = seller_; // Pass to the UniswapV3DTL implementation - super.__onCreate(lotId_, seller_, baseToken_, quoteToken_, capacity_, prefund_, callbackData_); + super.__onCreate( + lotId_, seller_, baseToken_, quoteToken_, capacity_, prefund_, callbackData_ + ); } /// @inheritdoc BaseDirectToLiquidity @@ -158,7 +178,7 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned /// - The auction has been completed /// /// @param merkleRoot_ The new merkle root - function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external onlyOwner { + function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external { DTLConfiguration memory lotConfig = lotConfiguration[lotId_]; // Validate that onCreate has been called for this lot @@ -176,11 +196,6 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned revert Callback_NotAuthorized(); } - // Validate that the merkle root is of the correct length - if (merkleRoot_.length != 32) { - revert Callback_InvalidParams(); - } - lotMerkleRoot[lotId_] = merkleRoot_; emit MerkleRootSet(lotId_, merkleRoot_); From c7f86fd781e506592a6edc778b8a33539ab3e730 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:01:56 +0400 Subject: [PATCH 08/29] Tests for new DTL --- script/salts/salts.json | 3 + script/salts/test/TestSalts.s.sol | 10 + ...UniswapV3DTLWithAllocatedAllowlistTest.sol | 399 +++++++ .../onBid.t.sol | 255 +++++ .../onCancel.t.sol | 129 +++ .../onCreate.t.sol | 473 ++++++++ .../onCurate.t.sol | 88 ++ .../onSettle.t.sol | 1013 +++++++++++++++++ .../setMerkleRoot.t.sol | 17 + 9 files changed, 2387 insertions(+) create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol create mode 100644 test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol diff --git a/script/salts/salts.json b/script/salts/salts.json index 1ebe2675..9e1e05ea 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -101,6 +101,9 @@ "Test_UniswapV2Router": { "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, + "Test_UniswapV3DTLWithAllocatedAllowlist": { + "0x2bdf3a604a31018a9d9c078b0ca102d8e010e76bd778ef15be00a064d92e8311": "0x2705df88bd7528b526bc650a636a81c4fb61999c46817355118c3bfd51b72f6b" + }, "Test_UniswapV3DirectToLiquidity": { "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0x30a263ee7e40137d3022c6283eec6d799a26e584f55de45be9a5b48823633c4d" }, diff --git a/script/salts/test/TestSalts.s.sol b/script/salts/test/TestSalts.s.sol index b619ca53..888dfffb 100644 --- a/script/salts/test/TestSalts.s.sol +++ b/script/salts/test/TestSalts.s.sol @@ -34,6 +34,8 @@ import {BALwithCappedAllowlist} from "../../../src/callbacks/liquidity/BaselineV2/BALwithCappedAllowlist.sol"; import {BALwithTokenAllowlist} from "../../../src/callbacks/liquidity/BaselineV2/BALwithTokenAllowlist.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; contract TestSalts is Script, WithEnvironment, Permit2User, WithSalts, TestConstants { string internal constant _CAPPED_MERKLE_ALLOWLIST = "CappedMerkleAllowlist"; @@ -236,6 +238,14 @@ contract TestSalts is Script, WithEnvironment, Permit2User, WithSalts, TestConst _setTestSalt(bytecodePath, "E6", "UniswapV3DirectToLiquidity", bytecodeHash); } + function generateUniswapV3DTLWithAllocatedAllowlist() public { + bytes memory args = abi.encode(_AUCTION_HOUSE, _UNISWAP_V3_FACTORY, _GUNI_FACTORY, _OWNER); + bytes memory contractCode = type(UniswapV3DTLWithAllocatedAllowlist).creationCode; + (string memory bytecodePath, bytes32 bytecodeHash) = + _writeBytecode("UniswapV3DTLWithAllocatedAllowlist", contractCode, args); + _setTestSalt(bytecodePath, "EE", "UniswapV3DTLWithAllocatedAllowlist", bytecodeHash); + } + function generateGUniFactory() public { // Generate a salt for a GUniFactory bytes memory args = abi.encode(_UNISWAP_V3_FACTORY); diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol new file mode 100644 index 00000000..08ed00c8 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Test} from "@forge-std-1.9.1/Test.sol"; +import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; +import {Permit2User} from "@axis-core-1.0.1-test/lib/permit2/Permit2User.sol"; + +import {IAuction} from "@axis-core-1.0.1/interfaces/modules/IAuction.sol"; +import {IAuctionHouse} from "@axis-core-1.0.1/interfaces/IAuctionHouse.sol"; +import {BatchAuctionHouse} from "@axis-core-1.0.1/BatchAuctionHouse.sol"; + +import {GUniFactory} from "@g-uni-v1-core-0.9.9/GUniFactory.sol"; +import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; +import {IUniswapV3Factory} from + "@uniswap-v3-core-1.0.1-solc-0.8-simulate/interfaces/IUniswapV3Factory.sol"; + +import {UniswapV3Factory} from "../../../lib/uniswap-v3/UniswapV3Factory.sol"; + +import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; +import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "../../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; +import {LinearVesting} from "@axis-core-1.0.1/modules/derivatives/LinearVesting.sol"; +import {MockBatchAuctionModule} from + "@axis-core-1.0.1-test/modules/Auction/MockBatchAuctionModule.sol"; + +import {keycodeFromVeecode, toKeycode} from "@axis-core-1.0.1/modules/Keycode.sol"; + +import {MockERC20} from "@solmate-6.7.0/test/utils/mocks/MockERC20.sol"; + +import {WithSalts} from "../../../lib/WithSalts.sol"; +import {console2} from "@forge-std-1.9.1/console2.sol"; +import {TestConstants} from "../../../Constants.sol"; + +// solhint-disable max-states-count + +abstract contract UniswapV3DirectToLiquidityWithAllocatedAllowlistTest is + Test, + Permit2User, + WithSalts, + TestConstants +{ + using Callbacks for UniswapV3DirectToLiquidity; + + address internal constant _PROTOCOL = address(0x3); + address internal constant _BUYER = address(0x4); + address internal constant _NOT_SELLER = address(0x20); + + uint96 internal constant _LOT_CAPACITY = 10e18; + + uint48 internal constant _START = 1_000_000; + uint48 internal constant _DURATION = 1 days; + uint48 internal constant _AUCTION_START = _START + 1; + uint48 internal constant _AUCTION_CONCLUSION = _AUCTION_START + _DURATION; + + // Values: + // 0x0000000000000000000000000000000000000004, 5e18 + // 0x0000000000000000000000000000000000000020, 0 + bytes32 internal constant _MERKLE_ROOT = + 0x0fdc3942d9af344db31ff2e80c06bc4e558dc967ca5b4d421d741870f5ea40df; + bytes32[] internal _merkleProof; + uint256 internal constant _BUYER_ALLOCATED_AMOUNT = 5e18; + + uint96 internal _lotId = 1; + + BatchAuctionHouse internal _auctionHouse; + UniswapV3DTLWithAllocatedAllowlist internal _dtl; + address internal _dtlAddress; + IUniswapV3Factory internal _uniV3Factory; + GUniFactory internal _gUniFactory; + LinearVesting internal _linearVesting; + MockBatchAuctionModule internal _batchAuctionModule; + + MockERC20 internal _quoteToken; + MockERC20 internal _baseToken; + + uint96 internal _proceeds; + uint96 internal _refund; + uint24 internal _maxSlippage = 1; // 0.01% + + // Inputs + uint24 internal _poolFee = 500; + UniswapV3DirectToLiquidity.UniswapV3OnCreateParams internal _uniswapV3CreateParams = + UniswapV3DirectToLiquidity.UniswapV3OnCreateParams({ + poolFee: _poolFee, + maxSlippage: 1 // 0.01%, to handle rounding errors + }); + BaseDirectToLiquidity.OnCreateParams internal _dtlCreateParams = BaseDirectToLiquidity + .OnCreateParams({ + poolPercent: 100e2, + vestingStart: 0, + vestingExpiry: 0, + recipient: _SELLER, + implParams: abi.encode(_uniswapV3CreateParams) + }); + + function setUp() public { + // Set reasonable timestamp + vm.warp(_START); + + // Create an AuctionHouse at a deterministic address, since it is used as input to callbacks + BatchAuctionHouse auctionHouse = new BatchAuctionHouse(_OWNER, _PROTOCOL, _permit2Address); + _auctionHouse = BatchAuctionHouse(_AUCTION_HOUSE); + vm.etch(address(_auctionHouse), address(auctionHouse).code); + vm.store(address(_auctionHouse), bytes32(uint256(0)), bytes32(abi.encode(_OWNER))); // Owner + vm.store(address(_auctionHouse), bytes32(uint256(6)), bytes32(abi.encode(1))); // Reentrancy + vm.store(address(_auctionHouse), bytes32(uint256(10)), bytes32(abi.encode(_PROTOCOL))); // Protocol + + // Create a UniswapV3Factory at a deterministic address + vm.startBroadcast(_CREATE2_DEPLOYER); + bytes32 uniswapV3Salt = + _getTestSalt("UniswapV3Factory", type(UniswapV3Factory).creationCode, abi.encode()); + _uniV3Factory = new UniswapV3Factory{salt: uniswapV3Salt}(); + vm.stopBroadcast(); + if (address(_uniV3Factory) != _UNISWAP_V3_FACTORY) { + console2.log("UniswapV3Factory address: ", address(_uniV3Factory)); + revert("UniswapV3Factory address mismatch"); + } + + // Create a GUniFactory at a deterministic address + vm.startBroadcast(_CREATE2_DEPLOYER); + bytes32 gUniFactorySalt = _getTestSalt( + "GUniFactory", type(GUniFactory).creationCode, abi.encode(address(_uniV3Factory)) + ); + _gUniFactory = new GUniFactory{salt: gUniFactorySalt}(address(_uniV3Factory)); + vm.stopBroadcast(); + if (address(_gUniFactory) != _GUNI_FACTORY) { + console2.log("GUniFactory address: ", address(_gUniFactory)); + revert("GUniFactory address mismatch"); + } + + // Initialize the GUniFactory + address payable gelatoAddress = payable(address(0x10)); + GUniPool poolImplementation = new GUniPool(gelatoAddress); + _gUniFactory.initialize(address(poolImplementation), address(0), address(this)); + + _linearVesting = new LinearVesting(address(_auctionHouse)); + _batchAuctionModule = new MockBatchAuctionModule(address(_auctionHouse)); + + // Install a mock batch auction module + vm.prank(_OWNER); + _auctionHouse.installModule(_batchAuctionModule); + + _quoteToken = new MockERC20("Quote Token", "QT", 18); + _baseToken = new MockERC20("Base Token", "BT", 18); + + _merkleProof.push( + bytes32(0x2eac7b0cadd960cd4457012a5e232aa3532d9365ba6df63c1b5a9c7846f77760) + ); // Corresponds to _BUYER + } + + // ========== MODIFIERS ========== // + + modifier givenLinearVestingModuleIsInstalled() { + vm.prank(_OWNER); + _auctionHouse.installModule(_linearVesting); + _; + } + + modifier givenCallbackIsCreated() { + // Get the salt + bytes memory args = abi.encode( + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), _OWNER + ); + bytes32 salt = _getTestSalt( + "UniswapV3DTLWithAllocatedAllowlist", + type(UniswapV3DTLWithAllocatedAllowlist).creationCode, + args + ); + + // Required for CREATE2 address to work correctly. doesn't do anything in a test + // Source: https://github.com/foundry-rs/foundry/issues/6402 + vm.startBroadcast(); + _dtl = new UniswapV3DTLWithAllocatedAllowlist{salt: salt}( + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), _OWNER + ); + vm.stopBroadcast(); + + _dtlAddress = address(_dtl); + _; + } + + modifier givenAddressHasQuoteTokenBalance(address address_, uint256 amount_) { + _quoteToken.mint(address_, amount_); + _; + } + + modifier givenAddressHasBaseTokenBalance(address address_, uint256 amount_) { + _baseToken.mint(address_, amount_); + _; + } + + modifier givenAddressHasQuoteTokenAllowance(address owner_, address spender_, uint256 amount_) { + vm.prank(owner_); + _quoteToken.approve(spender_, amount_); + _; + } + + modifier givenAddressHasBaseTokenAllowance(address owner_, address spender_, uint256 amount_) { + vm.prank(owner_); + _baseToken.approve(spender_, amount_); + _; + } + + function _createLot(address seller_, bytes memory err_) internal returns (uint96 lotId) { + // Mint and approve the capacity to the owner + _baseToken.mint(seller_, _LOT_CAPACITY); + vm.prank(seller_); + _baseToken.approve(address(_auctionHouse), _LOT_CAPACITY); + + // Prep the lot arguments + IAuctionHouse.RoutingParams memory routingParams = IAuctionHouse.RoutingParams({ + auctionType: keycodeFromVeecode(_batchAuctionModule.VEECODE()), + baseToken: address(_baseToken), + quoteToken: address(_quoteToken), + referrerFee: 0, // No referrer fee + curator: address(0), + callbacks: _dtl, + callbackData: abi.encode(_dtlCreateParams), + derivativeType: toKeycode(""), + derivativeParams: abi.encode(""), + wrapDerivative: false + }); + + IAuction.AuctionParams memory auctionParams = IAuction.AuctionParams({ + start: _AUCTION_START, + duration: _DURATION, + capacityInQuote: false, + capacity: _LOT_CAPACITY, + implParams: abi.encode("") + }); + + if (err_.length > 0) { + vm.expectRevert(err_); + } + + // Create a new lot + vm.prank(seller_); + return _auctionHouse.auction(routingParams, auctionParams, ""); + } + + function _createLot( + address seller_ + ) internal returns (uint96 lotId) { + return _createLot(seller_, ""); + } + + modifier givenOnCreate() { + _lotId = _createLot(_SELLER); + _; + } + + function _performOnCreate( + address seller_ + ) internal { + vm.prank(address(_auctionHouse)); + _dtl.onCreate( + _lotId, + seller_, + address(_baseToken), + address(_quoteToken), + _LOT_CAPACITY, + false, + abi.encode(_dtlCreateParams) + ); + } + + function _performOnCreate() internal { + _performOnCreate(_SELLER); + } + + function _performOnCurate( + uint96 curatorPayout_ + ) internal { + vm.prank(address(_auctionHouse)); + _dtl.onCurate(_lotId, curatorPayout_, false, abi.encode("")); + } + + modifier givenOnCurate( + uint96 curatorPayout_ + ) { + _performOnCurate(curatorPayout_); + _; + } + + function _performOnCancel(uint96 lotId_, uint256 refundAmount_) internal { + vm.prank(address(_auctionHouse)); + _dtl.onCancel(lotId_, refundAmount_, false, abi.encode("")); + } + + function _performOnCancel() internal { + _performOnCancel(_lotId, 0); + } + + function _performOnSettle( + uint96 lotId_ + ) internal { + vm.prank(address(_auctionHouse)); + _dtl.onSettle(lotId_, _proceeds, _refund, abi.encode("")); + } + + function _performOnSettle() internal { + _performOnSettle(_lotId); + } + + function _setPoolPercent( + uint24 percent_ + ) internal { + _dtlCreateParams.poolPercent = percent_; + } + + modifier givenPoolPercent( + uint24 percent_ + ) { + _setPoolPercent(percent_); + _; + } + + modifier givenPoolFee( + uint24 fee_ + ) { + _uniswapV3CreateParams.poolFee = fee_; + + // Update the callback data + _dtlCreateParams.implParams = abi.encode(_uniswapV3CreateParams); + _; + } + + function _setMaxSlippage( + uint24 maxSlippage_ + ) internal { + _uniswapV3CreateParams.maxSlippage = maxSlippage_; + + // Update the callback data + _dtlCreateParams.implParams = abi.encode(_uniswapV3CreateParams); + } + + modifier givenMaxSlippage( + uint24 maxSlippage_ + ) { + _setMaxSlippage(maxSlippage_); + _; + } + + modifier givenVestingStart( + uint48 start_ + ) { + _dtlCreateParams.vestingStart = start_; + _; + } + + modifier givenVestingExpiry( + uint48 end_ + ) { + _dtlCreateParams.vestingExpiry = end_; + _; + } + + modifier whenRecipientIsNotSeller() { + _dtlCreateParams.recipient = _NOT_SELLER; + _; + } + + modifier givenMerkleRootIsSet() { + vm.prank(_SELLER); + _dtl.setMerkleRoot(_lotId, _MERKLE_ROOT); + _; + } + + // ========== FUNCTIONS ========== // + + function _getDTLConfiguration( + uint96 lotId_ + ) internal view returns (BaseDirectToLiquidity.DTLConfiguration memory) { + ( + address recipient_, + uint256 lotCapacity_, + uint256 lotCuratorPayout_, + uint24 poolPercent_, + uint48 vestingStart_, + uint48 vestingExpiry_, + LinearVesting linearVestingModule_, + bool active_, + bytes memory implParams_ + ) = _dtl.lotConfiguration(lotId_); + + return BaseDirectToLiquidity.DTLConfiguration({ + recipient: recipient_, + lotCapacity: lotCapacity_, + lotCuratorPayout: lotCuratorPayout_, + poolPercent: poolPercent_, + vestingStart: vestingStart_, + vestingExpiry: vestingExpiry_, + linearVestingModule: linearVestingModule_, + active: active_, + implParams: implParams_ + }); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol new file mode 100644 index 00000000..1afc0987 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "../../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ + // Use the @openzeppelin/merkle-tree package or the scripts in axis-utils to generate the merkle tree + + // Values: + // 0x0000000000000000000000000000000000000004, 5e18 + // 0x0000000000000000000000000000000000000020, 0 + bytes32 internal constant _BUYER_MERKLE_PROOF = + 0x2eac7b0cadd960cd4457012a5e232aa3532d9365ba6df63c1b5a9c7846f77760; + bytes32 internal constant _NOT_SELLER_MERKLE_PROOF = + 0xe0a73973cd60d8cbabb978d1f3c983065148b388619b9176d3d30e47c16d4fd5; + + bytes32[] internal _proof; + uint256 internal _allocatedAmount; + + uint64 internal constant _BID_ID = 1; + + // ========== MODIFIER ========== // + + modifier givenMerkleProof( + bytes32 merkleProof_ + ) { + bytes32[] memory proof = new bytes32[](1); + proof[0] = merkleProof_; + + _proof = proof; + _; + } + + modifier givenMerkleAllocatedAmount( + uint256 allocatedAmount_ + ) { + _allocatedAmount = allocatedAmount_; + _; + } + + function _onBid( + uint256 bidAmount_ + ) internal { + // Call the callback + vm.prank(address(_auctionHouse)); + _dtl.onBid(_lotId, _BID_ID, _BUYER, bidAmount_, abi.encode(_proof, _allocatedAmount)); + } + + // ========== TESTS ========== // + + // when the merkle root is not set + // [X] it reverts + // when the allowlist parameters are in an incorrect format + // [X] it reverts + // when the merkle proof is invalid + // [X] it reverts + // when the buyer is not in the merkle tree + // [X] it reverts + // when the buyer has already spent their limit + // [X] it reverts + // when the buyer has a 0 limit + // [X] it reverts + // when the buyer has not made a bid + // when the bid amount is over the buyer's limit + // [X] it reverts + // [X] it updates the spent amount with the bid amount + // when the bid amount is over the remaining limit + // [X] it reverts + // [X] it updates the spent amount with the bid amount + + function test_merkleRootNotSet_reverts() public givenCallbackIsCreated givenOnCreate { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector + ); + vm.expectRevert(err); + + // Call the callback + _onBid(5e18); + } + + function test_parametersInvalid_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + { + // Expect revert + vm.expectRevert(); + + // Call the callback with an invalid parameter format + vm.prank(address(_auctionHouse)); + _dtl.onBid(_lotId, _BID_ID, _BUYER, 5e18, abi.encode(uint256(20), bytes("something"))); + } + + function test_merkleProofInvalid_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_NOT_SELLER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) // Amount is different to what is in the merkle tree + { + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + + // Call the callback with an invalid merkle proof + _onBid(5e18); + } + + function test_buyerNotInMerkleTree_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + + // Call the callback + vm.prank(address(_auctionHouse)); + _dtl.onBid(_lotId, _BID_ID, address(0x55), 5e18, abi.encode(_proof, _allocatedAmount)); + } + + function test_buyerLimitSpent_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Spend the allocation + _onBid(5e18); + + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + ); + vm.expectRevert(err); + + // Call the callback again + _onBid(1e18); + } + + function test_buyerZeroLimit_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_NOT_SELLER_MERKLE_PROOF) + givenMerkleAllocatedAmount(0) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + ); + vm.expectRevert(err); + + // Call the callback + vm.prank(address(_auctionHouse)); + _dtl.onBid(_lotId, _BID_ID, _NOT_SELLER, 5e18, abi.encode(_proof, _allocatedAmount)); + } + + function test_noBids_aboveLimit_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + ); + vm.expectRevert(err); + + // Call the callback + _onBid(6e18); + } + + function test_noBids_belowLimit() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Call the callback + _onBid(4e18); + + // Check the buyer spent amount + assertEq( + UniswapV3DTLWithAllocatedAllowlist(address(_dtl)).lotBuyerSpent(_lotId, _BUYER), + 4e18, + "buyer spent" + ); + } + + function test_remainingLimit_aboveLimit_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Spend the allocation + _onBid(4e18); + + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + ); + vm.expectRevert(err); + + // Call the callback again + _onBid(2e18); + } + + function test_remainingLimit_belowLimit() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleRootIsSet + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { + // Spend the allocation + _onBid(4e18); + + // Call the callback + _onBid(1e18); + + // Check the buyer spent amount + assertEq( + UniswapV3DTLWithAllocatedAllowlist(address(_dtl)).lotBuyerSpent(_lotId, _BUYER), + 5e18, + "buyer spent" + ); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol new file mode 100644 index 00000000..4d426cd4 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistOnCancelTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ + uint96 internal constant _REFUND_AMOUNT = 2e18; + + // ============ Modifiers ============ // + + // ============ Tests ============ // + + // [X] given the onCancel callback has already been called + // [X] when onSettle is called + // [X] it reverts + // [X] when onCancel is called + // [X] it reverts + // [X] when onCurate is called + // [X] it reverts + // [X] when onCreate is called + // [X] it reverts + // [X] when the lot has not been registered + // [X] it reverts + // [X] when multiple lots are created + // [X] it marks the correct lot as inactive + // [X] it marks the lot as inactive + + function test_whenLotNotRegistered_reverts() public givenCallbackIsCreated { + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + + // Call the function + _performOnCancel(); + } + + function test_success() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performOnCancel(); + + // Check the values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.active, false, "active"); + + // Check the balances + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "base token balance"); + assertEq(_baseToken.balanceOf(_SELLER), 0, "seller base token balance"); + assertEq(_baseToken.balanceOf(_NOT_SELLER), 0, "not seller base token balance"); + } + + function test_success_multiple() public givenCallbackIsCreated givenOnCreate { + uint96 lotIdOne = _lotId; + + // Create a second lot and cancel it + uint96 lotIdTwo = _createLot(_NOT_SELLER); + _performOnCancel(lotIdTwo, _REFUND_AMOUNT); + + // Check the values + BaseDirectToLiquidity.DTLConfiguration memory configurationOne = + _getDTLConfiguration(lotIdOne); + assertEq(configurationOne.active, true, "lot one: active"); + + BaseDirectToLiquidity.DTLConfiguration memory configurationTwo = + _getDTLConfiguration(lotIdTwo); + assertEq(configurationTwo.active, false, "lot two: active"); + + // Check the balances + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "base token balance"); + assertEq(_baseToken.balanceOf(_SELLER), 0, "seller base token balance"); + assertEq(_baseToken.balanceOf(_NOT_SELLER), 0, "not seller base token balance"); + } + + function test_auctionCancelled_onCreate_reverts() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performOnCancel(); + + // Expect revert + // BaseCallback determines if the lot has already been registered + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_InvalidParams.selector); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_auctionCancelled_onCurate_reverts() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performOnCancel(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + _performOnCurate(0); + } + + function test_auctionCancelled_onCancel_reverts() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performOnCancel(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + _performOnCancel(); + } + + function test_auctionCancelled_onSettle_reverts() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performOnCancel(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + _performOnSettle(); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol new file mode 100644 index 00000000..98d382f4 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; +import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistOnCreateTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ + // ============ Modifiers ============ // + + // ============ Assertions ============ // + + function _expectTransferFrom() internal { + vm.expectRevert("TRANSFER_FROM_FAILED"); + } + + function _expectInvalidParams() internal { + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_InvalidParams.selector); + vm.expectRevert(err); + } + + function _expectNotAuthorized() internal { + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + } + + function _assertBaseTokenBalances() internal view { + assertEq(_baseToken.balanceOf(_SELLER), 0, "seller balance"); + assertEq(_baseToken.balanceOf(_NOT_SELLER), 0, "not seller balance"); + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "dtl balance"); + } + + // ============ Tests ============ // + + // [X] when the callback data is incorrect + // [X] it reverts + // [X] when the callback is not called by the auction house + // [X] it reverts + // [X] when the lot has already been registered + // [X] it reverts + // [X] when the proceeds utilisation is 0 + // [X] it reverts + // [X] when the proceeds utilisation is greater than 100% + // [X] it reverts + // [X] when the implParams is not the correct length + // [X] it reverts + // [X] when the max slippage is between 0 and 100% + // [X] it succeeds + // [X] when the max slippage is greater than 100% + // [X] it reverts + // [X] given the pool fee is not enabled + // [X] it reverts + // [X] given uniswap v3 pool already exists + // [X] it succeeds + // [X] when the start and expiry timestamps are the same + // [X] it reverts + // [X] when the start timestamp is after the expiry timestamp + // [X] it reverts + // [X] when the start timestamp is before the current timestamp + // [X] it succeeds + // [X] when the expiry timestamp is before the current timestamp + // [X] it reverts + // [X] when the start timestamp and expiry timestamp are specified + // [X] given the linear vesting module is not installed + // [X] it reverts + // [X] given the vesting start timestamp is before the auction conclusion + // [X] it reverts + // [X] it records the address of the linear vesting module + // [X] when the recipient is the zero address + // [X] it reverts + // [X] when the recipient is not the seller + // [X] it records the recipient + // [X] when multiple lots are created + // [X] it registers each lot + // [ ] it registers the seller of the lot + // [X] it registers the lot + // [ ] it registers the seller of the lot + + function test_whenCallbackDataIsIncorrect_reverts() public givenCallbackIsCreated { + // Expect revert + vm.expectRevert(); + + vm.prank(address(_auctionHouse)); + _dtl.onCreate( + _lotId, + _SELLER, + address(_baseToken), + address(_quoteToken), + _LOT_CAPACITY, + false, + abi.encode(uint256(10)) + ); + } + + function test_whenCallbackIsNotCalledByAuctionHouse_reverts() public givenCallbackIsCreated { + _expectNotAuthorized(); + + _dtl.onCreate( + _lotId, + _SELLER, + address(_baseToken), + address(_quoteToken), + _LOT_CAPACITY, + false, + abi.encode(_dtlCreateParams) + ); + } + + function test_whenLotHasAlreadyBeenRegistered_reverts() public givenCallbackIsCreated { + _performOnCreate(); + + _expectInvalidParams(); + + _performOnCreate(); + } + + function test_poolPercent_whenBelowBounds_reverts( + uint24 poolPercent_ + ) public givenCallbackIsCreated { + uint24 poolPercent = uint24(bound(poolPercent_, 0, 10e2 - 1)); + + // Set pool percent + _setPoolPercent(poolPercent); + + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_PercentOutOfBounds.selector, + poolPercent, + 10e2, + 100e2 + ); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_poolPercent_whenAboveBounds_reverts( + uint24 poolPercent_ + ) public givenCallbackIsCreated { + uint24 poolPercent = uint24(bound(poolPercent_, 100e2 + 1, type(uint24).max)); + + // Set pool percent + _setPoolPercent(poolPercent); + + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_PercentOutOfBounds.selector, + poolPercent, + 10e2, + 100e2 + ); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_poolPercent_fuzz( + uint24 poolPercent_ + ) public givenCallbackIsCreated { + uint24 poolPercent = uint24(bound(poolPercent_, 10e2, 100e2)); + + _setPoolPercent(poolPercent); + + _performOnCreate(); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.poolPercent, poolPercent, "poolPercent"); + } + + function test_paramsIncorrectLength_reverts() public givenCallbackIsCreated { + // Set the implParams to an incorrect length + _dtlCreateParams.implParams = abi.encode(uint256(10)); + + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_InvalidParams.selector); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_maxSlippageGreaterThan100Percent_reverts( + uint24 maxSlippage_ + ) public givenCallbackIsCreated { + uint24 maxSlippage = uint24(bound(maxSlippage_, 100e2 + 1, type(uint24).max)); + _setMaxSlippage(maxSlippage); + + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_PercentOutOfBounds.selector, maxSlippage, 0, 100e2 + ); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_givenPoolFeeIsNotEnabled_reverts() + public + givenCallbackIsCreated + givenPoolFee(0) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DirectToLiquidity.Callback_Params_PoolFeeNotEnabled.selector + ); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_givenUniswapV3PoolAlreadyExists() + public + givenCallbackIsCreated + givenPoolFee(500) + { + // Create the pool + _uniV3Factory.createPool(address(_baseToken), address(_quoteToken), 500); + + // Perform the callback + _performOnCreate(); + + // Assert that the callback was successful + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.active, true, "active"); + } + + function test_whenStartAndExpiryTimestampsAreTheSame_reverts() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 1) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_InvalidVestingParams.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenStartTimestampIsAfterExpiryTimestamp_reverts() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION + 2) + givenVestingExpiry(_AUCTION_CONCLUSION + 1) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_InvalidVestingParams.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenStartTimestampIsBeforeCurrentTimestamp_reverts() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_START - 1) + givenVestingExpiry(_START + 1) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_InvalidVestingParams.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenExpiryTimestampIsBeforeCurrentTimestamp_reverts() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION - 1) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_InvalidVestingParams.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenVestingSpecified_givenLinearVestingModuleNotInstalled_reverts() + public + givenCallbackIsCreated + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_LinearVestingModuleNotFound.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenVestingSpecified_whenStartTimestampIsBeforeAuctionConclusion_reverts() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION - 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_Params_InvalidVestingParams.selector + ); + + _createLot(address(_SELLER), err); + } + + function test_whenVestingSpecified_whenVestingStartTimestampIsOnAuctionConclusion() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + { + _lotId = _createLot(address(_SELLER)); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.vestingStart, _AUCTION_CONCLUSION, "vestingStart"); + assertEq(configuration.vestingExpiry, _AUCTION_CONCLUSION + 2, "vestingExpiry"); + assertEq( + address(configuration.linearVestingModule), + address(_linearVesting), + "linearVestingModule" + ); + + // Assert balances + _assertBaseTokenBalances(); + } + + function test_whenVestingSpecified() + public + givenCallbackIsCreated + givenLinearVestingModuleIsInstalled + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + { + _lotId = _createLot(address(_SELLER)); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.vestingStart, _AUCTION_CONCLUSION + 1, "vestingStart"); + assertEq(configuration.vestingExpiry, _AUCTION_CONCLUSION + 2, "vestingExpiry"); + assertEq( + address(configuration.linearVestingModule), + address(_linearVesting), + "linearVestingModule" + ); + + // Assert balances + _assertBaseTokenBalances(); + } + + function test_whenRecipientIsZeroAddress_reverts() public givenCallbackIsCreated { + _dtlCreateParams.recipient = address(0); + + // Expect revert + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_Params_InvalidAddress.selector); + vm.expectRevert(err); + + _performOnCreate(); + } + + function test_whenRecipientIsNotSeller_succeeds() + public + givenCallbackIsCreated + whenRecipientIsNotSeller + { + _performOnCreate(); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.recipient, _NOT_SELLER, "recipient"); + + // Assert balances + _assertBaseTokenBalances(); + } + + function test_succeeds() public givenCallbackIsCreated { + _performOnCreate(); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.recipient, _SELLER, "recipient"); + assertEq(configuration.lotCapacity, _LOT_CAPACITY, "lotCapacity"); + assertEq(configuration.lotCuratorPayout, 0, "lotCuratorPayout"); + assertEq(configuration.poolPercent, _dtlCreateParams.poolPercent, "poolPercent"); + assertEq(configuration.vestingStart, 0, "vestingStart"); + assertEq(configuration.vestingExpiry, 0, "vestingExpiry"); + assertEq(address(configuration.linearVestingModule), address(0), "linearVestingModule"); + assertEq(configuration.active, true, "active"); + + (uint24 configurationPoolFee) = abi.decode(configuration.implParams, (uint24)); + assertEq(configurationPoolFee, _poolFee, "poolFee"); + assertEq(configuration.implParams, _dtlCreateParams.implParams, "implParams"); + + UniswapV3DirectToLiquidity.UniswapV3OnCreateParams memory uniswapV3CreateParams = abi.decode( + configuration.implParams, (UniswapV3DirectToLiquidity.UniswapV3OnCreateParams) + ); + assertEq(uniswapV3CreateParams.poolFee, _uniswapV3CreateParams.poolFee, "poolFee"); + assertEq( + uniswapV3CreateParams.maxSlippage, _uniswapV3CreateParams.maxSlippage, "maxSlippage" + ); + + // Assert balances + _assertBaseTokenBalances(); + } + + function test_succeeds_multiple() public givenCallbackIsCreated { + // Lot one + _performOnCreate(); + + // Lot two + _dtlCreateParams.recipient = _NOT_SELLER; + _lotId = 2; + _performOnCreate(_NOT_SELLER); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.recipient, _NOT_SELLER, "recipient"); + assertEq(configuration.lotCapacity, _LOT_CAPACITY, "lotCapacity"); + assertEq(configuration.lotCuratorPayout, 0, "lotCuratorPayout"); + assertEq(configuration.poolPercent, _dtlCreateParams.poolPercent, "poolPercent"); + assertEq(configuration.vestingStart, 0, "vestingStart"); + assertEq(configuration.vestingExpiry, 0, "vestingExpiry"); + assertEq(address(configuration.linearVestingModule), address(0), "linearVestingModule"); + assertEq(configuration.active, true, "active"); + assertEq(configuration.implParams, _dtlCreateParams.implParams, "implParams"); + + UniswapV3DirectToLiquidity.UniswapV3OnCreateParams memory uniswapV3CreateParams = abi.decode( + configuration.implParams, (UniswapV3DirectToLiquidity.UniswapV3OnCreateParams) + ); + assertEq(uniswapV3CreateParams.poolFee, _uniswapV3CreateParams.poolFee, "poolFee"); + assertEq( + uniswapV3CreateParams.maxSlippage, _uniswapV3CreateParams.maxSlippage, "maxSlippage" + ); + + // Assert balances + _assertBaseTokenBalances(); + } + + function test_maxSlippage_fuzz( + uint24 maxSlippage_ + ) public givenCallbackIsCreated { + uint24 maxSlippage = uint24(bound(maxSlippage_, 0, 100e2)); + _setMaxSlippage(maxSlippage); + + _performOnCreate(); + + // Assert values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.implParams, _dtlCreateParams.implParams, "implParams"); + + UniswapV3DirectToLiquidity.UniswapV3OnCreateParams memory uniswapV3CreateParams = abi.decode( + configuration.implParams, (UniswapV3DirectToLiquidity.UniswapV3OnCreateParams) + ); + assertEq(uniswapV3CreateParams.maxSlippage, maxSlippage, "maxSlippage"); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol new file mode 100644 index 00000000..e7d44569 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistOnCurateTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ + uint96 internal constant _PAYOUT_AMOUNT = 1e18; + + // ============ Modifiers ============ // + + function _performCallback( + uint96 lotId_ + ) internal { + vm.prank(address(_auctionHouse)); + _dtl.onCurate(lotId_, _PAYOUT_AMOUNT, false, abi.encode("")); + } + + // ============ Tests ============ // + + // [X] when the lot has not been registered + // [X] it reverts + // [X] when multiple lots are created + // [X] it marks the correct lot as inactive + // [X] it registers the curator payout + + function test_whenLotNotRegistered_reverts() public givenCallbackIsCreated { + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + + // Call the function + _performCallback(_lotId); + } + + function test_success() public givenCallbackIsCreated givenOnCreate { + // Call the function + _performCallback(_lotId); + + // Check the values + BaseDirectToLiquidity.DTLConfiguration memory configuration = _getDTLConfiguration(_lotId); + assertEq(configuration.lotCuratorPayout, _PAYOUT_AMOUNT, "lotCuratorPayout"); + + // Check the balances + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "base token balance"); + assertEq(_baseToken.balanceOf(_SELLER), 0, "seller base token balance"); + assertEq(_baseToken.balanceOf(_NOT_SELLER), 0, "not seller base token balance"); + assertEq( + _baseToken.balanceOf(address(_auctionHouse)), + _LOT_CAPACITY, + "auction house base token balance" + ); + } + + function test_success_multiple() public givenCallbackIsCreated givenOnCreate { + uint96 lotIdOne = _lotId; + + // Create a second lot + uint96 lotIdTwo = _createLot(_NOT_SELLER); + + // Call the function + _performCallback(lotIdTwo); + + // Check the values + BaseDirectToLiquidity.DTLConfiguration memory configurationOne = + _getDTLConfiguration(lotIdOne); + assertEq(configurationOne.lotCuratorPayout, 0, "lot one: lotCuratorPayout"); + + BaseDirectToLiquidity.DTLConfiguration memory configurationTwo = + _getDTLConfiguration(lotIdTwo); + assertEq(configurationTwo.lotCuratorPayout, _PAYOUT_AMOUNT, "lot two: lotCuratorPayout"); + + // Check the balances + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "base token balance"); + assertEq(_baseToken.balanceOf(_SELLER), 0, "seller base token balance"); + assertEq(_baseToken.balanceOf(_NOT_SELLER), 0, "not seller base token balance"); + assertEq( + _baseToken.balanceOf(address(_auctionHouse)), + _LOT_CAPACITY * 2, + "auction house base token balance" + ); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol new file mode 100644 index 00000000..2c7594e2 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol @@ -0,0 +1,1013 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +// Libraries +import {FixedPointMathLib} from "@solmate-6.7.0/utils/FixedPointMathLib.sol"; +import {ERC20} from "@solmate-6.7.0/tokens/ERC20.sol"; + +// Uniswap +import {IUniswapV3Pool} from + "@uniswap-v3-core-1.0.1-solc-0.8-simulate/interfaces/IUniswapV3Pool.sol"; +import {SqrtPriceMath} from "../../../../src/lib/uniswap-v3/SqrtPriceMath.sol"; +import {TickMath} from "@uniswap-v3-core-1.0.1-solc-0.8-simulate/libraries/TickMath.sol"; + +// G-UNI +import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; + +// AuctionHouse +import {ILinearVesting} from "@axis-core-1.0.1/interfaces/modules/derivatives/ILinearVesting.sol"; +import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; +import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; + +import {console2} from "@forge-std-1.9.1/console2.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistOnSettleTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ + uint96 internal constant _PROCEEDS = 20e18; + uint96 internal constant _REFUND = 0; + + uint96 internal _capacityUtilised; + uint96 internal _quoteTokensToDeposit; + uint96 internal _baseTokensToDeposit; + uint96 internal _curatorPayout; + uint256 internal _additionalQuoteTokensMinted; + + uint160 internal constant _SQRT_PRICE_X96_OVERRIDE = 125_270_724_187_523_965_593_206_000_000; // Different to what is normally calculated + + /// @dev Set via `setCallbackParameters` modifier + uint160 internal _sqrtPriceX96; + + // ========== Internal functions ========== // + + function _getGUniPool() internal view returns (GUniPool) { + // Get the pools deployed by the DTL callback + address[] memory pools = _gUniFactory.getPools(_dtlAddress); + + return GUniPool(pools[0]); + } + + function _getVestingTokenId() internal view returns (uint256) { + // Get the pools deployed by the DTL callback + address pool = address(_getGUniPool()); + + return _linearVesting.computeId( + pool, + abi.encode( + ILinearVesting.VestingParams({ + start: _dtlCreateParams.vestingStart, + expiry: _dtlCreateParams.vestingExpiry + }) + ) + ); + } + + // ========== Assertions ========== // + + function _assertPoolState( + uint160 sqrtPriceX96_ + ) internal view { + // Get the pool + IUniswapV3Pool pool = _getPool(); + + (uint160 sqrtPriceX96,,,,,,) = pool.slot0(); + assertEq(sqrtPriceX96, sqrtPriceX96_, "pool sqrt price"); + } + + function _assertLpTokenBalance() internal view { + // Get the pools deployed by the DTL callback + GUniPool pool = _getGUniPool(); + + uint256 sellerExpectedBalance; + uint256 linearVestingExpectedBalance; + // Only has a balance if not vesting + if (_dtlCreateParams.vestingStart == 0) { + sellerExpectedBalance = pool.totalSupply(); + } else { + linearVestingExpectedBalance = pool.totalSupply(); + } + + assertEq( + pool.balanceOf(_SELLER), + _dtlCreateParams.recipient == _SELLER ? sellerExpectedBalance : 0, + "seller: LP token balance" + ); + assertEq( + pool.balanceOf(_NOT_SELLER), + _dtlCreateParams.recipient == _NOT_SELLER ? sellerExpectedBalance : 0, + "not seller: LP token balance" + ); + assertEq( + pool.balanceOf(address(_linearVesting)), + linearVestingExpectedBalance, + "linear vesting: LP token balance" + ); + } + + function _assertVestingTokenBalance() internal { + // Exit if not vesting + if (_dtlCreateParams.vestingStart == 0) { + return; + } + + // Get the pools deployed by the DTL callback + address pool = address(_getGUniPool()); + + // Get the wrapped address + (, address wrappedVestingTokenAddress) = _linearVesting.deploy( + pool, + abi.encode( + ILinearVesting.VestingParams({ + start: _dtlCreateParams.vestingStart, + expiry: _dtlCreateParams.vestingExpiry + }) + ), + true + ); + ERC20 wrappedVestingToken = ERC20(wrappedVestingTokenAddress); + uint256 sellerExpectedBalance = wrappedVestingToken.totalSupply(); + + assertEq( + wrappedVestingToken.balanceOf(_SELLER), + _dtlCreateParams.recipient == _SELLER ? sellerExpectedBalance : 0, + "seller: vesting token balance" + ); + assertEq( + wrappedVestingToken.balanceOf(_NOT_SELLER), + _dtlCreateParams.recipient == _NOT_SELLER ? sellerExpectedBalance : 0, + "not seller: vesting token balance" + ); + } + + function _assertQuoteTokenBalance() internal view { + assertEq(_quoteToken.balanceOf(_dtlAddress), 0, "DTL: quote token balance"); + + uint256 nonPoolProceeds = _proceeds - _quoteTokensToDeposit; + assertApproxEqAbs( + _quoteToken.balanceOf(_NOT_SELLER), + _dtlCreateParams.recipient == _NOT_SELLER ? nonPoolProceeds : 0, + ( + _dtlCreateParams.recipient == _NOT_SELLER + ? _uniswapV3CreateParams.maxSlippage * _quoteTokensToDeposit / 100e2 + : 0 + ) + 2, // Rounding errors + "not seller: quote token balance" + ); + assertApproxEqAbs( + _quoteToken.balanceOf(_SELLER), + _dtlCreateParams.recipient == _SELLER ? nonPoolProceeds : 0, + ( + _dtlCreateParams.recipient == _NOT_SELLER + ? _uniswapV3CreateParams.maxSlippage * _quoteTokensToDeposit / 100e2 + : 0 + ) + 2, // Rounding errors + "seller: quote token balance" + ); + } + + function _assertBaseTokenBalance() internal view { + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "DTL: base token balance"); + } + + function _assertApprovals() internal view { + // Ensure there are no dangling approvals + assertEq( + _quoteToken.allowance(_dtlAddress, address(_getGUniPool())), + 0, + "DTL: quote token allowance" + ); + assertEq( + _baseToken.allowance(_dtlAddress, address(_getGUniPool())), + 0, + "DTL: base token allowance" + ); + } + + // ========== Modifiers ========== // + + function _createPool() internal returns (address) { + (address token0, address token1) = address(_baseToken) < address(_quoteToken) + ? (address(_baseToken), address(_quoteToken)) + : (address(_quoteToken), address(_baseToken)); + + return _uniV3Factory.createPool(token0, token1, _poolFee); + } + + function _initializePool(address pool_, uint160 sqrtPriceX96_) internal { + IUniswapV3Pool(pool_).initialize(sqrtPriceX96_); + } + + modifier givenPoolIsCreated() { + _createPool(); + _; + } + + modifier givenPoolIsCreatedAndInitialized( + uint160 sqrtPriceX96_ + ) { + address pool = _createPool(); + _initializePool(pool, sqrtPriceX96_); + _; + } + + function _calculateSqrtPriceX96( + uint256 quoteTokenAmount_, + uint256 baseTokenAmount_ + ) internal view returns (uint160) { + return SqrtPriceMath.getSqrtPriceX96( + address(_quoteToken), address(_baseToken), quoteTokenAmount_, baseTokenAmount_ + ); + } + + modifier setCallbackParameters(uint96 proceeds_, uint96 refund_) { + _proceeds = proceeds_; + _refund = refund_; + + // Calculate the capacity utilised + // Any unspent curator payout is included in the refund + // However, curator payouts are linear to the capacity utilised + // Calculate the percent utilisation + uint96 capacityUtilisationPercent = 100e2 + - uint96(FixedPointMathLib.mulDivDown(_refund, 100e2, _LOT_CAPACITY + _curatorPayout)); + _capacityUtilised = _LOT_CAPACITY * capacityUtilisationPercent / 100e2; + + // The proceeds utilisation percent scales the quote tokens and base tokens linearly + _quoteTokensToDeposit = _proceeds * _dtlCreateParams.poolPercent / 100e2; + _baseTokensToDeposit = _capacityUtilised * _dtlCreateParams.poolPercent / 100e2; + + _sqrtPriceX96 = _calculateSqrtPriceX96(_quoteTokensToDeposit, _baseTokensToDeposit); + _; + } + + modifier givenUnboundedPoolPercent( + uint24 percent_ + ) { + // Bound the percent + uint24 percent = uint24(bound(percent_, 10e2, 100e2)); + + // Set the value on the DTL + _dtlCreateParams.poolPercent = percent; + _; + } + + modifier givenUnboundedOnCurate( + uint96 curationPayout_ + ) { + // Bound the value + _curatorPayout = uint96(bound(curationPayout_, 1e17, _LOT_CAPACITY)); + + // Call the onCurate callback + _performOnCurate(_curatorPayout); + _; + } + + modifier whenRefundIsBounded( + uint96 refund_ + ) { + // Bound the refund + _refund = uint96(bound(refund_, 1e17, 5e18)); + _; + } + + modifier givenPoolHasDepositLowerPrice() { + _sqrtPriceX96 = _calculateSqrtPriceX96(_PROCEEDS / 2, _LOT_CAPACITY); + _; + } + + modifier givenPoolHasDepositHigherPrice() { + _sqrtPriceX96 = _calculateSqrtPriceX96(_PROCEEDS * 2, _LOT_CAPACITY); + _; + } + + modifier givenPoolHasDepositMuchHigherPrice() { + _sqrtPriceX96 = _calculateSqrtPriceX96(_PROCEEDS * 10, _LOT_CAPACITY); + _; + } + + function _getPool() internal view returns (IUniswapV3Pool) { + (address token0, address token1) = address(_baseToken) < address(_quoteToken) + ? (address(_baseToken), address(_quoteToken)) + : (address(_quoteToken), address(_baseToken)); + return IUniswapV3Pool(_uniV3Factory.getPool(token0, token1, _poolFee)); + } + + // ========== Tests ========== // + + // [X] given the onSettle callback has already been called + // [X] when onSettle is called + // [X] it reverts + // [X] when onCancel is called + // [X] it reverts + // [X] when onCreate is called + // [X] it reverts + // [X] when onCurate is called + // [X] it reverts + // [X] given the pool is created + // [X] it initializes the pool + // [X] given the pool is created and initialized + // [X] it succeeds + // [X] given there is liquidity in the pool at a higher tick + // [X] it adjusts the pool price + // [X] given there is liquidity in the pool at a lower tick + // [X] it adjusts the pool price + // [X] given the proceeds utilisation percent is set + // [X] it calculates the deposit amount correctly + // [X] given curation is enabled + // [X] the utilisation percent considers this + // [X] when the refund amount changes + // [X] the utilisation percent considers this + // [X] given minting pool tokens utilises less than the available amount of base tokens + // [X] the excess base tokens are returned + // [X] given minting pool tokens utilises less than the available amount of quote tokens + // [X] the excess quote tokens are returned + // [X] given the send base tokens flag is false + // [X] it transfers the base tokens from the seller + // [X] given vesting is enabled + // [X] given the recipient is not the seller + // [X] it mints the vesting tokens to the seller + // [X] it mints the vesting tokens to the seller + // [X] given the recipient is not the seller + // [X] it mints the LP token to the recipient + // [X] when multiple lots are created + // [X] it performs actions on the correct pool + // [X] it creates and initializes the pool, creates a pool token, deposits into the pool token, transfers the LP token to the seller and transfers any excess back to the seller + + function test_givenPoolIsCreated() + public + givenCallbackIsCreated + givenOnCreate + givenPoolIsCreated + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenPoolPercent_fuzz( + uint24 percent_ + ) + public + givenCallbackIsCreated + givenUnboundedPoolPercent(percent_) + whenRecipientIsNotSeller + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenCurationPayout_fuzz( + uint96 curationPayout_ + ) + public + givenCallbackIsCreated + givenOnCreate + givenUnboundedOnCurate(curationPayout_) + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenPoolPercent_givenCurationPayout_fuzz( + uint24 percent_, + uint96 curationPayout_ + ) + public + givenCallbackIsCreated + givenUnboundedPoolPercent(percent_) + givenOnCreate + givenUnboundedOnCurate(curationPayout_) + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_whenRefund_fuzz( + uint96 refund_ + ) + public + givenCallbackIsCreated + givenOnCreate + whenRefundIsBounded(refund_) + setCallbackParameters(_PROCEEDS, _refund) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenPoolHasDepositWithLowerPrice() + public + givenCallbackIsCreated + givenMaxSlippage(200) // 2% + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenPoolHasDepositLowerPrice + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_calculateSqrtPriceX96(_PROCEEDS, _LOT_CAPACITY)); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + // TODO need to add a case where the price is more than 2x the target price and there is too much liquidity to sell through + // the result should be the pool is initialized at a higher price than the target price, but with balanced liquidity + function test_givenPoolHasDepositWithHigherPrice() + public + givenCallbackIsCreated + givenMaxSlippage(200) // 2% + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenPoolHasDepositHigherPrice + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_calculateSqrtPriceX96(_PROCEEDS, _LOT_CAPACITY)); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_lessThanMaxSlippage() + public + givenCallbackIsCreated + givenMaxSlippage(1) // 0.01% + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_greaterThanMaxSlippage_reverts() + public + givenCallbackIsCreated + givenMaxSlippage(0) // 0% + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DirectToLiquidity.Callback_Slippage.selector, + address(_quoteToken), + 19_999_999_999_999_999_999, // Hardcoded + _quoteTokensToDeposit + ); + vm.expectRevert(err); + + _performOnSettle(); + } + + function test_givenVesting() + public + givenLinearVestingModuleIsInstalled + givenCallbackIsCreated + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenVesting_whenRecipientIsNotSeller() + public + givenLinearVestingModuleIsInstalled + givenCallbackIsCreated + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + whenRecipientIsNotSeller + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_givenVesting_redemption() + public + givenLinearVestingModuleIsInstalled + givenCallbackIsCreated + givenVestingStart(_AUCTION_CONCLUSION + 1) + givenVestingExpiry(_AUCTION_CONCLUSION + 2) + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _baseTokensToDeposit) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _baseTokensToDeposit) + { + _performOnSettle(); + + // Warp to the end of the vesting period + vm.warp(_AUCTION_CONCLUSION + 3); + + // Check that there is a vested token balance + uint256 tokenId = _getVestingTokenId(); + uint256 redeemable = _linearVesting.redeemable(_SELLER, tokenId); + assertGt(redeemable, 0, "redeemable"); + + // Redeem the vesting tokens + vm.prank(_SELLER); + _linearVesting.redeemMax(tokenId); + + // Assert that the LP token has been transferred to the seller + GUniPool pool = _getGUniPool(); + assertEq(pool.balanceOf(_SELLER), pool.totalSupply(), "seller: LP token balance"); + } + + function test_withdrawLpToken() + public + givenCallbackIsCreated + givenOnCreate + givenPoolIsCreated + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + // Get the pools deployed by the DTL callback + address[] memory pools = _gUniFactory.getPools(_dtlAddress); + assertEq(pools.length, 1, "pools length"); + GUniPool pool = GUniPool(pools[0]); + + IUniswapV3Pool uniPool = _getPool(); + + // Withdraw the LP token + uint256 sellerBalance = pool.balanceOf(_SELLER); + vm.prank(_SELLER); + pool.burn(sellerBalance, _SELLER); + + // Check the balances + assertEq(pool.balanceOf(_SELLER), 0, "seller: LP token balance"); + assertEq(_quoteToken.balanceOf(_SELLER), _proceeds - 1, "seller: quote token balance"); + assertEq(_baseToken.balanceOf(_SELLER), _capacityUtilised - 1, "seller: base token balance"); + assertEq(_quoteToken.balanceOf(pools[0]), 0, "pool: quote token balance"); + assertEq(_baseToken.balanceOf(pools[0]), 0, "pool: base token balance"); + assertEq(_quoteToken.balanceOf(_dtlAddress), 0, "DTL: quote token balance"); + assertEq(_baseToken.balanceOf(_dtlAddress), 0, "DTL: base token balance"); + // There is a rounding error when burning the LP token, which leaves dust in the pool + assertEq(_quoteToken.balanceOf(address(uniPool)), 1, "uni pool: quote token balance"); + assertEq(_baseToken.balanceOf(address(uniPool)), 1, "uni pool: base token balance"); + } + + function test_givenInsufficientBaseTokenBalance_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised - 1) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + // Expect revert + bytes memory err = abi.encodeWithSelector( + BaseDirectToLiquidity.Callback_InsufficientBalance.selector, + address(_baseToken), + _SELLER, + _baseTokensToDeposit, + _baseTokensToDeposit - 1 + ); + vm.expectRevert(err); + + _performOnSettle(); + } + + function test_givenInsufficientBaseTokenAllowance_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised - 1) + { + // Expect revert + vm.expectRevert("TRANSFER_FROM_FAILED"); + + _performOnSettle(); + } + + function test_success() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_success_multiple() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_NOT_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_NOT_SELLER, _dtlAddress, _capacityUtilised) + { + // Create second lot + uint96 lotIdTwo = _createLot(_NOT_SELLER); + + _performOnSettle(lotIdTwo); + + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_whenRecipientIsNotSeller() + public + givenCallbackIsCreated + whenRecipientIsNotSeller + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + _assertPoolState(_sqrtPriceX96); + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_auctionCompleted_onCreate_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + // Expect revert + // BaseCallback determines if the lot has already been registered + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_InvalidParams.selector); + vm.expectRevert(err); + + // Try to call onCreate again + _performOnCreate(); + } + + function test_auctionCompleted_onCurate_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + // Try to call onCurate + _performOnCurate(_curatorPayout); + } + + function test_auctionCompleted_onCancel_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + // Try to call onCancel + _performOnCancel(); + } + + function test_auctionCompleted_onSettle_reverts() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + { + _performOnSettle(); + + // Expect revert + // BaseDirectToLiquidity determines if the lot has already been completed + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + // Try to call onSettle + _performOnSettle(); + } + + function uniswapV3MintCallback(uint256, uint256 amount1Owed, bytes calldata) external { + console2.log("Minting additional quote tokens", amount1Owed); + _additionalQuoteTokensMinted += amount1Owed; + + // Transfer the quote tokens + _quoteToken.mint(msg.sender, amount1Owed); + } + + function _mintPosition(int24 tickLower_, int24 tickUpper_) internal { + // Using PoC: https://github.com/GuardianAudits/axis-1/pull/4/files + IUniswapV3Pool pool = _getPool(); + + pool.mint(address(this), tickLower_, tickUpper_, 1e18, ""); + } + + function uniswapV3SwapCallback(int256, int256, bytes memory) external pure { + return; + } + + function _swap( + uint160 sqrtPrice_ + ) internal { + IUniswapV3Pool pool = _getPool(); + + pool.swap(address(this), true, 1, sqrtPrice_, ""); + } + + function test_existingReservesAtHigherPoolTick() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + { + // Assert the pool price + int24 poolTick; + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after mint"); // Original active tick + + // Swap at a tick higher than the anchor range + IUniswapV3Pool pool = _getPool(); + pool.swap(address(this), false, 1, TickMath.getSqrtRatioAtTick(60_000), ""); + + // Assert that the pool tick has moved higher + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 60_000, "pool tick after swap"); + + // Provide reserve tokens to the pool at a tick higher than the original active tick and lower than the new active tick + _mintPosition(7200, 7200 + _getPool().tickSpacing()); + + // Perform callback + _performOnSettle(); + + // Assert that the pool tick has corrected + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after settlement"); // Ends up rounded to the tick spacing + + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); // Difficult to calculate the exact balance, given the swaps + // _assertBaseTokenBalance(); // Difficult to calculate the exact balance, given the swaps + _assertApprovals(); + } + + function test_existingReservesAtHigherPoolTick_noLiquidity() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + { + // Assert the pool price + int24 poolTick; + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after mint"); // Original active tick + + // Swap at a tick higher than the active tick + IUniswapV3Pool pool = _getPool(); + pool.swap(address(this), false, 1, TickMath.getSqrtRatioAtTick(60_000), ""); + + // Assert that the pool tick has moved higher + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 60_000, "pool tick after swap"); + + // Do not mint any liquidity above the previous active tick + + // Perform callback + _performOnSettle(); + + // Assert that the pool tick has corrected + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after settlement"); // Ends up rounded to the tick spacing + + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_existingReservesAtLowerPoolTick() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + { + // Provide reserve tokens to the pool at a lower tick + _mintPosition(-60_000 - _getPool().tickSpacing(), -60_000); + + // Assert the pool price + int24 poolTick; + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after mint"); // Original active tick + + // Swap at a tick lower than the active tick + _swap(TickMath.getSqrtRatioAtTick(-60_000)); + + // Assert that the pool price has moved lower + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, -60_001, "pool tick after swap"); + + // Perform callback + _performOnSettle(); + + // Assert that the pool tick has corrected + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after settlement"); // Ends up rounded to the tick spacing + + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } + + function test_existingReservesAtLowerPoolTick_noLiquidity() + public + givenCallbackIsCreated + givenOnCreate + setCallbackParameters(_PROCEEDS, _REFUND) + givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + givenPoolIsCreatedAndInitialized(_sqrtPriceX96) + { + // Don't mint any liquidity + + // Assert the pool price + int24 poolTick; + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after mint"); // Original active tick + + // Swap at a tick lower than the active tick + _swap(TickMath.getSqrtRatioAtTick(-60_000)); + + // Assert that the pool price has moved lower + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, -60_000, "pool tick after swap"); + + // Perform callback + _performOnSettle(); + + // Assert that the pool tick has corrected + (, poolTick,,,,,) = _getPool().slot0(); + assertEq(poolTick, 6931, "pool tick after settlement"); // Ends up rounded to the tick spacing + + _assertLpTokenBalance(); + _assertVestingTokenBalance(); + _assertQuoteTokenBalance(); + _assertBaseTokenBalance(); + _assertApprovals(); + } +} diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol new file mode 100644 index 00000000..e7e38798 --- /dev/null +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from + "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; + +contract UniswapV3DTLWithAllocatedAllowlistSetMerkleRootTest is + UniswapV3DirectToLiquidityWithAllocatedAllowlistTest +{ +// when the auction has not been registered +// [ ] it reverts +// when the caller is not the seller +// [ ] it reverts +// [ ] when the auction has been completed +// [ ] it reverts +// [ ] the merkle root is updated and an event is emitted +} From 632c4090fec3a017f66ef16997a4fb6247cd9292 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:13:15 +0400 Subject: [PATCH 09/29] Add missing check in allowlist --- script/salts/salts.json | 2 +- src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index 9e1e05ea..b5f63693 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -102,7 +102,7 @@ "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, "Test_UniswapV3DTLWithAllocatedAllowlist": { - "0x2bdf3a604a31018a9d9c078b0ca102d8e010e76bd778ef15be00a064d92e8311": "0x2705df88bd7528b526bc650a636a81c4fb61999c46817355118c3bfd51b72f6b" + "0x93a2bf5f0936e4efa8afa79292f0a57a0f5c4756da91dd16dac9710fcc852df0": "0xecbcbe0f8041e91528b7b55fb890dc891cc6f13c902804fae79ffe3d1f122d7d" }, "Test_UniswapV3DirectToLiquidity": { "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0x30a263ee7e40137d3022c6283eec6d799a26e584f55de45be9a5b48823633c4d" diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 87eb62c7..7fe17481 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -116,6 +116,9 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned bytes calldata callbackData_ ) internal override { // Validate that the merkle root has been set + if (lotMerkleRoot[lotId_] == bytes32(0)) { + revert Callback_InvalidState(); + } // Validate that the buyer is allowed to participate uint256 allocatedAmount = _canParticipate(lotId_, buyer_, callbackData_); From a39e44b0643faa98884cf245ccdd109efb99aded Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:13:23 +0400 Subject: [PATCH 10/29] Add tests for setMerkleRoot --- .../onBid.t.sol | 8 ++- .../setMerkleRoot.t.sol | 68 +++++++++++++++++-- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol index 1afc0987..1fc4530a 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol @@ -75,7 +75,13 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is // [X] it reverts // [X] it updates the spent amount with the bid amount - function test_merkleRootNotSet_reverts() public givenCallbackIsCreated givenOnCreate { + function test_merkleRootNotSet_reverts() + public + givenCallbackIsCreated + givenOnCreate + givenMerkleProof(_BUYER_MERKLE_PROOF) + givenMerkleAllocatedAmount(5e18) + { // Expect revert bytes memory err = abi.encodeWithSelector( UniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol index e7e38798..03ff1fe1 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol @@ -3,15 +3,69 @@ pragma solidity 0.8.19; import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; +import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseDirectToLiquidity} from "src/callbacks/liquidity/BaseDTL.sol"; contract UniswapV3DTLWithAllocatedAllowlistSetMerkleRootTest is UniswapV3DirectToLiquidityWithAllocatedAllowlistTest { -// when the auction has not been registered -// [ ] it reverts -// when the caller is not the seller -// [ ] it reverts -// [ ] when the auction has been completed -// [ ] it reverts -// [ ] the merkle root is updated and an event is emitted + event MerkleRootSet(uint96 lotId, bytes32 merkleRoot); + + // when the auction has not been registered + // [X] it reverts + // when the caller is not the seller + // [X] it reverts + // when the auction has been completed + // [ X] it reverts + // [X] the merkle root is updated and an event is emitted + + function test_auctionNotRegistered_reverts() public givenCallbackIsCreated { + // Expect revert + bytes memory err = abi.encodeWithSelector( + UniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector + ); + vm.expectRevert(err); + + // Call the callback + vm.prank(_SELLER); + _dtl.setMerkleRoot(_lotId, _MERKLE_ROOT); + } + + function test_callerIsNotSeller_reverts() public givenCallbackIsCreated givenOnCreate { + // Expect revert + bytes memory err = abi.encodeWithSelector(BaseCallback.Callback_NotAuthorized.selector); + vm.expectRevert(err); + + // Call the callback + vm.prank(address(_auctionHouse)); + _dtl.setMerkleRoot(_lotId, _MERKLE_ROOT); + } + + function test_auctionCompleted_reverts() public givenCallbackIsCreated givenOnCreate { + _performOnCancel(); + + // Expect revert + bytes memory err = + abi.encodeWithSelector(BaseDirectToLiquidity.Callback_AlreadyComplete.selector); + vm.expectRevert(err); + + // Call the callback + vm.prank(_SELLER); + _dtl.setMerkleRoot(_lotId, _MERKLE_ROOT); + } + + function test_success() public givenCallbackIsCreated givenOnCreate { + // Expect event + vm.expectEmit(true, true, true, true); + emit MerkleRootSet(_lotId, _MERKLE_ROOT); + + // Call the callback + vm.prank(_SELLER); + _dtl.setMerkleRoot(_lotId, _MERKLE_ROOT); + + // Assert the merkle root is updated + assertEq(_dtl.lotMerkleRoot(_lotId), _MERKLE_ROOT); + } } From 5fea07fca76f9c8ca15dacdbdaa0d94eb2b6849f Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:14:17 +0400 Subject: [PATCH 11/29] Correct docs --- script/salts/salts.json | 2 +- .../liquidity/UniswapV3DTLWithAllocatedAllowlist.sol | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index b5f63693..cc83fc1a 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -102,7 +102,7 @@ "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, "Test_UniswapV3DTLWithAllocatedAllowlist": { - "0x93a2bf5f0936e4efa8afa79292f0a57a0f5c4756da91dd16dac9710fcc852df0": "0xecbcbe0f8041e91528b7b55fb890dc891cc6f13c902804fae79ffe3d1f122d7d" + "0x9057c598b934f57af272c3aeade144dde3143701670ced4dc6a2ef62452b3ae7": "0x6d71bb3650d38e49c3303f196b3ce244e04f59e9542c756437a621401894de60" }, "Test_UniswapV3DirectToLiquidity": { "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0x30a263ee7e40137d3022c6283eec6d799a26e584f55de45be9a5b48823633c4d" diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 7fe17481..e65c3be7 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -169,16 +169,16 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned // ========== ADMIN FUNCTIONS ========== // /// @notice Sets the merkle root for the allowlist - /// This function can be called by the owner to update the merkle root after `onCreate()`. + /// This function can be called by the seller to update the merkle root after `onCreate()`. /// @dev This function performs the following: /// - Performs validation /// - Sets the merkle root /// - Emits a MerkleRootSet event /// /// This function reverts if: - /// - The caller is not the owner /// - The auction has not been registered /// - The auction has been completed + /// - The caller is not the seller /// /// @param merkleRoot_ The new merkle root function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external { From 2ecad81e07719967e9c9ef5458fc1c18b554462c Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:27:52 +0400 Subject: [PATCH 12/29] Fix issue with test salts --- script/salts/salts.json | 4 +-- .../UniswapV2DTL/UniswapV2DTLTest.sol | 30 +++++++++---------- .../UniswapV3DTL/UniswapV3DTLTest.sol | 30 +++++++++---------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index cc83fc1a..cf29b3de 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -96,7 +96,7 @@ "0xb789c4afd1a886c5cfeb88fbd8b09ae8ec1b3869e50a0b8527289817f2e25218": "0xe33f41bdf6be9ac2a67f006ff3fa86cf5974fba590d3b14514751adf8d1f63ac" }, "Test_UniswapV2DirectToLiquidity": { - "0x4e58c10856f2239319fe5013e7d340d3e1f33133faa1edc26441a414a4513394": "0x1f74ed93eb7f112f63a39f8aaf7a6c03a90f71021066567f1f53b5ab50586f07" + "0x4e58c10856f2239319fe5013e7d340d3e1f33133faa1edc26441a414a4513394": "0x1b2d8986785dda37b20ac0ad8942a762ed170a7cf45e5fc63683ba670b389143" }, "Test_UniswapV2Router": { "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" @@ -105,7 +105,7 @@ "0x9057c598b934f57af272c3aeade144dde3143701670ced4dc6a2ef62452b3ae7": "0x6d71bb3650d38e49c3303f196b3ce244e04f59e9542c756437a621401894de60" }, "Test_UniswapV3DirectToLiquidity": { - "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0x30a263ee7e40137d3022c6283eec6d799a26e584f55de45be9a5b48823633c4d" + "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0xc8be4d10dcb98ffec22b85b9da34f5253e7f2d4575ba1af8df919d86235dc0cf" }, "Test_UniswapV3Factory": { "0x862fde1cd9de35dc112d759742b17a659781dfe0dddb8136e0b63fa9c2e00dab": "0x5fbe68e6c093ea70e56909c84fe99890a237a4af7f7599ace8471a48c78a8aae" diff --git a/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol b/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol index 04e99ae4..ba1f5e26 100644 --- a/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol +++ b/test/callbacks/liquidity/UniswapV2DTL/UniswapV2DTLTest.sol @@ -128,9 +128,21 @@ abstract contract UniswapV2DirectToLiquidityTest is Test, Permit2User, WithSalts } modifier givenCallbackIsCreated() { + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt - bytes memory args = - abi.encode(address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router)); + bytes memory args = abi.encode( + address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router), permissions + ); bytes32 salt = _getTestSalt( "UniswapV2DirectToLiquidity", type(UniswapV2DirectToLiquidity).creationCode, args ); @@ -139,19 +151,7 @@ abstract contract UniswapV2DirectToLiquidityTest is Test, Permit2User, WithSalts // Source: https://github.com/foundry-rs/foundry/issues/6402 vm.startBroadcast(); _dtl = new UniswapV2DirectToLiquidity{salt: salt}( - address(_auctionHouse), - address(_uniV2Factory), - address(_uniV2Router), - Callbacks.Permissions({ - onCreate: true, - onCancel: true, - onCurate: true, - onPurchase: false, - onBid: false, - onSettle: true, - receiveQuoteTokens: true, - sendBaseTokens: false - }) + address(_auctionHouse), address(_uniV2Factory), address(_uniV2Router), permissions ); vm.stopBroadcast(); diff --git a/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol b/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol index 94b923cf..78f45131 100644 --- a/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol +++ b/test/callbacks/liquidity/UniswapV3DTL/UniswapV3DTLTest.sol @@ -139,9 +139,21 @@ abstract contract UniswapV3DirectToLiquidityTest is Test, Permit2User, WithSalts } modifier givenCallbackIsCreated() { + Callbacks.Permissions memory permissions = Callbacks.Permissions({ + onCreate: true, + onCancel: true, + onCurate: true, + onPurchase: false, + onBid: false, + onSettle: true, + receiveQuoteTokens: true, + sendBaseTokens: false + }); + // Get the salt - bytes memory args = - abi.encode(address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory)); + bytes memory args = abi.encode( + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), permissions + ); bytes32 salt = _getTestSalt( "UniswapV3DirectToLiquidity", type(UniswapV3DirectToLiquidity).creationCode, args ); @@ -150,19 +162,7 @@ abstract contract UniswapV3DirectToLiquidityTest is Test, Permit2User, WithSalts // Source: https://github.com/foundry-rs/foundry/issues/6402 vm.startBroadcast(); _dtl = new UniswapV3DirectToLiquidity{salt: salt}( - address(_auctionHouse), - address(_uniV3Factory), - address(_gUniFactory), - Callbacks.Permissions({ - onCreate: true, - onCancel: true, - onCurate: true, - onPurchase: false, - onBid: false, - onSettle: true, - receiveQuoteTokens: true, - sendBaseTokens: false - }) + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), permissions ); vm.stopBroadcast(); From 47bcd1357b49f86af30dbe7226c9771681a35e29 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 28 Jan 2025 23:28:05 +0400 Subject: [PATCH 13/29] Disable tests that were giving a stack too deep error --- .../liquidity/UniswapV2DTL/onSettle.t.sol | 1278 ++++++++--------- 1 file changed, 639 insertions(+), 639 deletions(-) diff --git a/test/callbacks/liquidity/UniswapV2DTL/onSettle.t.sol b/test/callbacks/liquidity/UniswapV2DTL/onSettle.t.sol index 0c914b46..3d1cbb4a 100644 --- a/test/callbacks/liquidity/UniswapV2DTL/onSettle.t.sol +++ b/test/callbacks/liquidity/UniswapV2DTL/onSettle.t.sol @@ -343,645 +343,645 @@ contract UniswapV2DirectToLiquidityOnSettleTest is UniswapV2DirectToLiquidityTes _assertApprovals(); } - function test_givenDonation_givenAuctionPriceGreaterThanOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDifferentQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenLowQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(6) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 1e24); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenAuctionPriceGreaterThanOne_givenDifferentBaseTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenBaseTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDifferentBaseTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenBaseTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(15e18, _REFUND) // 1.5e18 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenDifferentQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(15e18, _REFUND) // 1.5e17 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenLowQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(6) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(15e18, _REFUND) // 1.5e6 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 1e24); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenDifferentBaseTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenBaseTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(15e18, _REFUND) // 1.5e18 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenAuctionPriceOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_LOT_CAPACITY, 0) // Price = 1 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_LOT_CAPACITY, 0) // Price = 1 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceOne_givenDifferentQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_LOT_CAPACITY, 0) - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceOne_givenLowQuoteTokenDecimals_reverts() - public - givenCallbackIsCreated - givenQuoteTokenDecimals(6) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_LOT_CAPACITY, 0) - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // This is a demonstration that a ridiculous quantity of quote tokens will cause - // the donation mitigation functionality to revert - uint256 donatedQuoteTokens = 1e24; - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Expect revert - vm.expectRevert("UniswapV2: K"); - - // Callback - _performOnSettle(); - } - - function test_givenDonation_givenSync_givenAuctionPriceOne_givenDifferentBaseTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenBaseTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_LOT_CAPACITY, 0) - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenAuctionPriceLessThanOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_givenDifferentQuoteTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenQuoteTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } - - function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_givenDifferentBaseTokenDecimals_fuzz( - uint256 donatedQuoteTokens_ - ) - public - givenCallbackIsCreated - givenBaseTokenDecimals(17) - givenOnCreate - givenPoolIsCreated - setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 - givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) - givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) - givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) - { - // Donation amount could be more or less than the auction price - uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); - _quoteTokensDonated += donatedQuoteTokens; - - // Donate to the pool - _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); - - // Sync - _syncPool(); - - // Callback - _performOnSettle(); - - // Assertions - _assertLpTokenBalance(); - _assertLpUnderlyingBalances(); - _assertVestingTokenBalance(); - _assertQuoteTokenBalance(); - _assertBaseTokenBalance(); - _assertApprovals(); - } + // function test_givenDonation_givenAuctionPriceGreaterThanOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDifferentQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenLowQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(6) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 1e24); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenAuctionPriceGreaterThanOne_givenDifferentBaseTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenBaseTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDifferentBaseTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenBaseTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS, _REFUND) // Price is 2 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(15e18, _REFUND) // 1.5e18 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenDifferentQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(15e18, _REFUND) // 1.5e17 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenLowQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(6) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(15e18, _REFUND) // 1.5e6 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 1e24); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceGreaterThanOne_givenDecimalPrice_givenDifferentBaseTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenBaseTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(15e18, _REFUND) // 1.5e18 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenAuctionPriceOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_LOT_CAPACITY, 0) // Price = 1 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_LOT_CAPACITY, 0) // Price = 1 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceOne_givenDifferentQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_LOT_CAPACITY, 0) + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceOne_givenLowQuoteTokenDecimals_reverts() + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(6) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_LOT_CAPACITY, 0) + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // This is a demonstration that a ridiculous quantity of quote tokens will cause + // // the donation mitigation functionality to revert + // uint256 donatedQuoteTokens = 1e24; + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Expect revert + // vm.expectRevert("UniswapV2: K"); + + // // Callback + // _performOnSettle(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceOne_givenDifferentBaseTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenBaseTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_LOT_CAPACITY, 0) + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenAuctionPriceLessThanOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_givenDifferentQuoteTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenQuoteTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e17); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } + + // function test_givenDonation_givenSync_givenAuctionPriceLessThanOne_givenDifferentBaseTokenDecimals_fuzz( + // uint256 donatedQuoteTokens_ + // ) + // public + // givenCallbackIsCreated + // givenBaseTokenDecimals(17) + // givenOnCreate + // givenPoolIsCreated + // setCallbackParameters(_PROCEEDS_PRICE_LESS_THAN_ONE, 0) // Price = 0.5 + // givenAddressHasQuoteTokenBalance(_dtlAddress, _proceeds) + // givenAddressHasBaseTokenBalance(_SELLER, _capacityUtilised) + // givenAddressHasBaseTokenAllowance(_SELLER, _dtlAddress, _capacityUtilised) + // { + // // Donation amount could be more or less than the auction price + // uint256 donatedQuoteTokens = bound(donatedQuoteTokens_, 1, 3e18); + // _quoteTokensDonated += donatedQuoteTokens; + + // // Donate to the pool + // _quoteToken.mint(address(_getUniswapV2Pool()), donatedQuoteTokens); + + // // Sync + // _syncPool(); + + // // Callback + // _performOnSettle(); + + // // Assertions + // _assertLpTokenBalance(); + // _assertLpUnderlyingBalances(); + // _assertVestingTokenBalance(); + // _assertQuoteTokenBalance(); + // _assertBaseTokenBalance(); + // _assertApprovals(); + // } function test_givenPoolPercent_fuzz( uint24 percent_ From e30a907c1ab5110873f309dc8002d73219842c1e Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 15:57:49 +0400 Subject: [PATCH 14/29] Use stable version of foundry --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 125dd02c..db5c1adc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -33,8 +33,6 @@ jobs: - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly # Providing the SSH key to the checkout action does not work with our config. # It likely is because of the install script wiping the lib/ directory. From 4c9f69e77fc59f1ba84fd620a3cfbb9ee42f650a Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 16:53:05 +0400 Subject: [PATCH 15/29] Extract interface --- script/salts/salts.json | 2 +- .../IUniswapV3DTLWithAllocatedAllowlist.sol | 27 +++++++++++++++++++ .../UniswapV3DTLWithAllocatedAllowlist.sol | 27 ++++++------------- .../onBid.t.sol | 12 +++++---- .../setMerkleRoot.t.sol | 4 ++- 5 files changed, 46 insertions(+), 26 deletions(-) create mode 100644 src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol diff --git a/script/salts/salts.json b/script/salts/salts.json index cf29b3de..fbf63ed7 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -102,7 +102,7 @@ "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, "Test_UniswapV3DTLWithAllocatedAllowlist": { - "0x9057c598b934f57af272c3aeade144dde3143701670ced4dc6a2ef62452b3ae7": "0x6d71bb3650d38e49c3303f196b3ce244e04f59e9542c756437a621401894de60" + "0x00e2a2827930678950c09245de129ca3e6bb37c30ce3bb0fcb2accf347fe5644": "0x835105acc4e4750a718ff60ed12163a2c1b37e8938df2350145ddd67e3fb5e98" }, "Test_UniswapV3DirectToLiquidity": { "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0xc8be4d10dcb98ffec22b85b9da34f5253e7f2d4575ba1af8df919d86235dc0cf" diff --git a/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol new file mode 100644 index 00000000..027e27e2 --- /dev/null +++ b/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +interface IUniswapV3DTLWithAllocatedAllowlist { + // ========== ERRORS ========== // + + /// @notice Error message when the bid amount exceeds the limit assigned to a buyer + error Callback_ExceedsLimit(); + + /// @notice Error message when the callback state does not support the action + error Callback_InvalidState(); + + // ========== EVENTS ========== // + + /// @notice Emitted when the merkle root is set + event MerkleRootSet(uint96 lotId, bytes32 merkleRoot); + + // ========== ADMIN ========== // + + /// @notice Sets the merkle root for the allowlist + /// This function can be called by the seller to update the merkle root after `onCreate()`. + /// @dev This function can only be called by the seller + /// + /// @param lotId_ The lot ID + /// @param merkleRoot_ The merkle root + function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external; +} diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index e65c3be7..37170313 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -7,24 +7,16 @@ import {Owned} from "@solmate-6.7.0/auth/Owned.sol"; import {UniswapV3DirectToLiquidity} from "./UniswapV3DTL.sol"; import {BaseDirectToLiquidity} from "./BaseDTL.sol"; import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; +import {IUniswapV3DTLWithAllocatedAllowlist} from "./IUniswapV3DTLWithAllocatedAllowlist.sol"; /// @notice Allocated allowlist version of the Uniswap V3 Direct To Liquidity callback. /// @notice This version allows for each address in the Merkle tree to have a per-address amount of quote tokens they can spend. /// @dev The merkle tree is expected to have both an address and an amount of quote tokens they can spend in each leaf. -contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned { - // ========== ERRORS ========== // - - /// @notice Error message when the bid amount exceeds the limit assigned to a buyer - error Callback_ExceedsLimit(); - - /// @notice Error message when the callback state does not support the action - error Callback_InvalidState(); - - // ========== EVENTS ========== // - - /// @notice Emitted when the merkle root is set - event MerkleRootSet(uint96 lotId, bytes32 merkleRoot); - +contract UniswapV3DTLWithAllocatedAllowlist is + IUniswapV3DTLWithAllocatedAllowlist, + UniswapV3DirectToLiquidity, + Owned +{ // ========== STATE VARIABLES ========== // /// @notice The seller address for each lot @@ -168,8 +160,7 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned // ========== ADMIN FUNCTIONS ========== // - /// @notice Sets the merkle root for the allowlist - /// This function can be called by the seller to update the merkle root after `onCreate()`. + /// @inheritdoc IUniswapV3DTLWithAllocatedAllowlist /// @dev This function performs the following: /// - Performs validation /// - Sets the merkle root @@ -179,9 +170,7 @@ contract UniswapV3DTLWithAllocatedAllowlist is UniswapV3DirectToLiquidity, Owned /// - The auction has not been registered /// - The auction has been completed /// - The caller is not the seller - /// - /// @param merkleRoot_ The new merkle root - function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external { + function setMerkleRoot(uint96 lotId_, bytes32 merkleRoot_) external override { DTLConfiguration memory lotConfig = lotConfiguration[lotId_]; // Validate that onCreate has been called for this lot diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol index 1fc4530a..ab2e9556 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol @@ -7,6 +7,8 @@ import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; import {UniswapV3DTLWithAllocatedAllowlist} from "../../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; +import {IUniswapV3DTLWithAllocatedAllowlist} from + "../../../../src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol"; contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is UniswapV3DirectToLiquidityWithAllocatedAllowlistTest @@ -84,7 +86,7 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is { // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector ); vm.expectRevert(err); @@ -152,7 +154,7 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector ); vm.expectRevert(err); @@ -170,7 +172,7 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is { // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector ); vm.expectRevert(err); @@ -189,7 +191,7 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is { // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector ); vm.expectRevert(err); @@ -229,7 +231,7 @@ contract UniswapV3DTLWithAllocatedAllowlistOnBidTest is // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_ExceedsLimit.selector ); vm.expectRevert(err); diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol index 03ff1fe1..ff36eb69 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol @@ -7,6 +7,8 @@ import {UniswapV3DTLWithAllocatedAllowlist} from "src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; import {BaseDirectToLiquidity} from "src/callbacks/liquidity/BaseDTL.sol"; +import {IUniswapV3DTLWithAllocatedAllowlist} from + "src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol"; contract UniswapV3DTLWithAllocatedAllowlistSetMerkleRootTest is UniswapV3DirectToLiquidityWithAllocatedAllowlistTest @@ -24,7 +26,7 @@ contract UniswapV3DTLWithAllocatedAllowlistSetMerkleRootTest is function test_auctionNotRegistered_reverts() public givenCallbackIsCreated { // Expect revert bytes memory err = abi.encodeWithSelector( - UniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector + IUniswapV3DTLWithAllocatedAllowlist.Callback_InvalidState.selector ); vm.expectRevert(err); From 803df6e055f990c2d2019958c8687897e9f2829e Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 18:19:18 +0400 Subject: [PATCH 16/29] Remove redundant owner from DTL --- script/salts/salts.json | 2 +- script/salts/test/TestSalts.s.sol | 2 +- .../liquidity/UniswapV3DTLWithAllocatedAllowlist.sol | 8 ++------ .../UniswapV3DTLWithAllocatedAllowlistTest.sol | 7 +++---- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index fbf63ed7..206c3733 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -102,7 +102,7 @@ "0x874532e739feebacbbe36f8c61fa97ab6ab1e6f7316e48763abf915e4af90c02": "0x5e9f7ca3ee281335c8a4fe4a4f33b950a5359d6a95fdc81892d9103ffd689659" }, "Test_UniswapV3DTLWithAllocatedAllowlist": { - "0x00e2a2827930678950c09245de129ca3e6bb37c30ce3bb0fcb2accf347fe5644": "0x835105acc4e4750a718ff60ed12163a2c1b37e8938df2350145ddd67e3fb5e98" + "0xd1693ad5a79e28f239ed97bcba831c44f94fdda24442c765182a676e3b6d48e1": "0x85a9a2e58352cc66d24640fbea18bf194ba67a6b85c4c8f81818089177f6ed65" }, "Test_UniswapV3DirectToLiquidity": { "0x7e6b454bebf4f4d7a29947c79da35cca0128dca192e222a53cd430d9d377c65d": "0xc8be4d10dcb98ffec22b85b9da34f5253e7f2d4575ba1af8df919d86235dc0cf" diff --git a/script/salts/test/TestSalts.s.sol b/script/salts/test/TestSalts.s.sol index 888dfffb..2139a018 100644 --- a/script/salts/test/TestSalts.s.sol +++ b/script/salts/test/TestSalts.s.sol @@ -239,7 +239,7 @@ contract TestSalts is Script, WithEnvironment, Permit2User, WithSalts, TestConst } function generateUniswapV3DTLWithAllocatedAllowlist() public { - bytes memory args = abi.encode(_AUCTION_HOUSE, _UNISWAP_V3_FACTORY, _GUNI_FACTORY, _OWNER); + bytes memory args = abi.encode(_AUCTION_HOUSE, _UNISWAP_V3_FACTORY, _GUNI_FACTORY); bytes memory contractCode = type(UniswapV3DTLWithAllocatedAllowlist).creationCode; (string memory bytecodePath, bytes32 bytecodeHash) = _writeBytecode("UniswapV3DTLWithAllocatedAllowlist", contractCode, args); diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index 37170313..af51e3c1 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.19; import {MerkleProof} from "@openzeppelin-contracts-4.9.2/utils/cryptography/MerkleProof.sol"; -import {Owned} from "@solmate-6.7.0/auth/Owned.sol"; import {UniswapV3DirectToLiquidity} from "./UniswapV3DTL.sol"; import {BaseDirectToLiquidity} from "./BaseDTL.sol"; @@ -14,8 +13,7 @@ import {IUniswapV3DTLWithAllocatedAllowlist} from "./IUniswapV3DTLWithAllocatedA /// @dev The merkle tree is expected to have both an address and an amount of quote tokens they can spend in each leaf. contract UniswapV3DTLWithAllocatedAllowlist is IUniswapV3DTLWithAllocatedAllowlist, - UniswapV3DirectToLiquidity, - Owned + UniswapV3DirectToLiquidity { // ========== STATE VARIABLES ========== // @@ -46,8 +44,7 @@ contract UniswapV3DTLWithAllocatedAllowlist is constructor( address auctionHouse_, address uniV3Factory_, - address gUniFactory_, - address owner_ + address gUniFactory_ ) UniswapV3DirectToLiquidity( auctionHouse_, @@ -64,7 +61,6 @@ contract UniswapV3DTLWithAllocatedAllowlist is sendBaseTokens: false }) ) - Owned(owner_) {} // ========== CALLBACKS ========== // diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol index 08ed00c8..3832b1d4 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol @@ -159,9 +159,8 @@ abstract contract UniswapV3DirectToLiquidityWithAllocatedAllowlistTest is modifier givenCallbackIsCreated() { // Get the salt - bytes memory args = abi.encode( - address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), _OWNER - ); + bytes memory args = + abi.encode(address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory)); bytes32 salt = _getTestSalt( "UniswapV3DTLWithAllocatedAllowlist", type(UniswapV3DTLWithAllocatedAllowlist).creationCode, @@ -172,7 +171,7 @@ abstract contract UniswapV3DirectToLiquidityWithAllocatedAllowlistTest is // Source: https://github.com/foundry-rs/foundry/issues/6402 vm.startBroadcast(); _dtl = new UniswapV3DTLWithAllocatedAllowlist{salt: salt}( - address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory), _OWNER + address(_auctionHouse), address(_uniV3Factory), address(_gUniFactory) ); vm.stopBroadcast(); From 79da311497ed77c1f06db6954f172e88761401a0 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 18:19:29 +0400 Subject: [PATCH 17/29] Add deployment script --- script/deploy/Deploy.s.sol | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/script/deploy/Deploy.s.sol b/script/deploy/Deploy.s.sol index 20c8fde4..ea20e466 100644 --- a/script/deploy/Deploy.s.sol +++ b/script/deploy/Deploy.s.sol @@ -22,6 +22,8 @@ import {GUniFactory} from "@g-uni-v1-core-0.9.9/GUniFactory.sol"; // Callbacks import {UniswapV2DirectToLiquidity} from "../../src/callbacks/liquidity/UniswapV2DTL.sol"; import {UniswapV3DirectToLiquidity} from "../../src/callbacks/liquidity/UniswapV3DTL.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; import {CappedMerkleAllowlist} from "../../src/callbacks/allowlists/CappedMerkleAllowlist.sol"; import {MerkleAllowlist} from "../../src/callbacks/allowlists/MerkleAllowlist.sol"; import {TokenAllowlist} from "../../src/callbacks/allowlists/TokenAllowlist.sol"; @@ -487,6 +489,51 @@ contract Deploy is Script, WithDeploySequence, WithSalts { return (address(cbBatchUniswapV3Dtl), _PREFIX_CALLBACKS, deploymentKey); } + function deployBatchUniswapV3DirectToLiquidityWithAllocatedAllowlist( + string memory sequenceName_ + ) public returns (address, string memory, string memory) { + console2.log(""); + console2.log("Deploying UniswapV3DirectToLiquidityWithAllocatedAllowlist (Batch)"); + + // Get configuration variables + address batchAuctionHouse = _getAddressNotZero("deployments.BatchAuctionHouse"); + address uniswapV3Factory = _getEnvAddressOrOverride( + "constants.uniswapV3.factory", sequenceName_, "args.uniswapV3Factory" + ); + address gUniFactory = + _getEnvAddressOrOverride("constants.gUni.factory", sequenceName_, "args.gUniFactory"); + string memory deploymentKey = _getDeploymentKey(sequenceName_); + console2.log(" deploymentKey:", deploymentKey); + + // Check that the GUni factory and Uniswap V3 factory are consistent + require( + GUniFactory(gUniFactory).factory() == uniswapV3Factory, + "GUniFactory.factory() does not match given Uniswap V3 factory address" + ); + + // Get the salt + bytes32 salt_ = _getSalt( + deploymentKey, + type(UniswapV3DTLWithAllocatedAllowlist).creationCode, + abi.encode(batchAuctionHouse, uniswapV3Factory, gUniFactory) + ); + + // Revert if the salt is not set + require(salt_ != bytes32(0), "Salt not set"); + + // Deploy the module + console2.log(" salt:", vm.toString(salt_)); + + vm.broadcast(); + UniswapV3DTLWithAllocatedAllowlist cbBatchUniswapV3Dtl = new UniswapV3DTLWithAllocatedAllowlist{ + salt: salt_ + }(batchAuctionHouse, uniswapV3Factory, gUniFactory); + console2.log(""); + console2.log(" deployed at:", address(cbBatchUniswapV3Dtl)); + + return (address(cbBatchUniswapV3Dtl), _PREFIX_CALLBACKS, deploymentKey); + } + function deployAtomicCappedMerkleAllowlist( string memory sequenceName_ ) public returns (address, string memory, string memory) { From 5bc93cc1e9b7aedc92e8f47c1f06d761956868c1 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 18:26:31 +0400 Subject: [PATCH 18/29] Add salt generation --- .../salts/dtl-uniswap/UniswapDTLSalts.s.sol | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol index a2452eb9..3ae4b5a2 100644 --- a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol +++ b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol @@ -9,6 +9,8 @@ import {WithDeploySequence} from "../../deploy/WithDeploySequence.s.sol"; // Uniswap import {UniswapV2DirectToLiquidity} from "../../../src/callbacks/liquidity/UniswapV2DTL.sol"; import {UniswapV3DirectToLiquidity} from "../../../src/callbacks/liquidity/UniswapV3DTL.sol"; +import {UniswapV3DTLWithAllocatedAllowlist} from + "../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; contract UniswapDTLSalts is Script, WithDeploySequence, WithSalts { string internal constant _ADDRESS_PREFIX = "E6"; @@ -67,6 +69,17 @@ contract UniswapDTLSalts is Script, WithDeploySequence, WithSalts { _generateV3(sequenceName, auctionHouse, deploymentKey); } + // Batch Uniswap V3 with Allocated Allowlist + else if ( + keccak256(abi.encodePacked(sequenceName)) + == keccak256( + abi.encodePacked("BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist") + ) + ) { + address auctionHouse = _envAddressNotZero("deployments.BatchAuctionHouse"); + + _generateV3(sequenceName, auctionHouse, deploymentKey); + } // Something else else { console2.log(" Skipping unknown sequence: %s", sequenceName); @@ -116,4 +129,26 @@ contract UniswapDTLSalts is Script, WithDeploySequence, WithSalts { ); _setSalt(bytecodePath, _ADDRESS_PREFIX, deploymentKey_, bytecodeHash); } + + function _generateV3WithAllocatedAllowlist( + string memory sequenceName_, + address auctionHouse_, + string memory deploymentKey_ + ) internal { + // Get input variables or overrides + address envUniswapV3Factory = _getEnvAddressOrOverride( + "constants.uniswapV3.factory", sequenceName_, "args.uniswapV3Factory" + ); + address envGUniFactory = + _getEnvAddressOrOverride("constants.gUni.factory", sequenceName_, "args.gUniFactory"); + + // Calculate salt for the UniswapV2DirectToLiquidity + bytes memory contractCode = type(UniswapV3DTLWithAllocatedAllowlist).creationCode; + (string memory bytecodePath, bytes32 bytecodeHash) = _writeBytecode( + deploymentKey_, + contractCode, + abi.encode(auctionHouse_, envUniswapV3Factory, envGUniFactory) + ); + _setSalt(bytecodePath, _ADDRESS_PREFIX, deploymentKey_, bytecodeHash); + } } From b296fa93584a2e7f636073726066189e540e3838 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 18:28:19 +0400 Subject: [PATCH 19/29] Correct function --- script/salts/dtl-uniswap/UniswapDTLSalts.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol index 3ae4b5a2..e2f52baf 100644 --- a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol +++ b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol @@ -78,7 +78,7 @@ contract UniswapDTLSalts is Script, WithDeploySequence, WithSalts { ) { address auctionHouse = _envAddressNotZero("deployments.BatchAuctionHouse"); - _generateV3(sequenceName, auctionHouse, deploymentKey); + _generateV3WithAllocatedAllowlist(sequenceName, auctionHouse, deploymentKey); } // Something else else { From 3af891cad4e30a360271a9a46d61123c61bb0e77 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 18:30:59 +0400 Subject: [PATCH 20/29] Correct address prefix --- script/salts/dtl-uniswap/UniswapDTLSalts.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol index e2f52baf..a33e0a6e 100644 --- a/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol +++ b/script/salts/dtl-uniswap/UniswapDTLSalts.s.sol @@ -149,6 +149,6 @@ contract UniswapDTLSalts is Script, WithDeploySequence, WithSalts { contractCode, abi.encode(auctionHouse_, envUniswapV3Factory, envGUniFactory) ); - _setSalt(bytecodePath, _ADDRESS_PREFIX, deploymentKey_, bytecodeHash); + _setSalt(bytecodePath, "EE", deploymentKey_, bytecodeHash); } } From 3e87913053d2df4234a365d844c0d98dd65293fd Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Wed, 29 Jan 2025 20:01:12 +0400 Subject: [PATCH 21/29] Base sepolia deployment --- deployments/.base-sepolia-1738161094.json | 3 +++ script/env.json | 3 ++- script/salts/salts.json | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 deployments/.base-sepolia-1738161094.json diff --git a/deployments/.base-sepolia-1738161094.json b/deployments/.base-sepolia-1738161094.json new file mode 100644 index 00000000..c5eba581 --- /dev/null +++ b/deployments/.base-sepolia-1738161094.json @@ -0,0 +1,3 @@ +{ + "deployments.callbacks.BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE4d06C1c96Ae19D1D77ac279881a639307E97E2" +} diff --git a/script/env.json b/script/env.json index e5c2c97b..bcf77e26 100644 --- a/script/env.json +++ b/script/env.json @@ -92,7 +92,8 @@ "BatchMerkleAllowlist": "0x98d64E00D9d6550913E73C940Ff476Cf1723d834", "BatchTokenAllowlist": "0x9801e45362a2bb7C9F22486CC3F5cA9224e9CC55", "BatchUniswapV2DirectToLiquidity": "0xE6546c03B1b9DFC4238f0A2923FdefD5E4af7659", - "BatchUniswapV3DirectToLiquidity": "0xE68b21C071534781BC4c40E6BF1bCFC23638fF4B" + "BatchUniswapV3DirectToLiquidity": "0xE68b21C071534781BC4c40E6BF1bCFC23638fF4B", + "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE4d06C1c96Ae19D1D77ac279881a639307E97E2" } } }, diff --git a/script/salts/salts.json b/script/salts/salts.json index 206c3733..8fe240c3 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -17,6 +17,9 @@ "0xc329d36cea27b1f8e044c99a5eda27503fd6087f50b6d27b7bb12ac4493507e1": "0xb724ad108002e85a8144c2b305013b4d302fb1ef4a39d477f6d18e96bc219a3d", "0xf4d7d42633353828c29211c77c068516380a9c75c942fba88b1c01215c1001a6": "0xb07de304d67101f3cef70ee4e023a361d50b19eb13b59729724ad64e1f6aa88b" }, + "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": { + "0x6e336f95ca94d3a841a4bfccfa526767ddd3461f1c8f157b86427612f760f227": "0xda0a9ac9527532a9e8c0bf0e7c25a87dbbbb903092036db0c685faeb8dd4ffbe" + }, "CappedMerkleAllowlist": { "0x0249dded8310d17581f166a526ea9ded65b81112ccac0ee8a144e9770d2b8432": "0xf5746fa34aeff9866dc5ec58712f7f47045aea15db39a0aabf4dadc9d35c8854", "0x0ae7777d88dd21a8b9ca3dd9212307295a83aed438fef9dad0b62d57fbaf1025": "0x1de5ae5b126bd2cee8eb4f083080f5c30baa692580cf823fa5f382a7bfc70ac5", From 19252df4fc9c864a2bbb4bafba3203339cb4aaf9 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 18 Feb 2025 18:05:49 +0400 Subject: [PATCH 22/29] Add deployment sequence --- script/deploy/sequences/uniswap-v3-allocated-dtl.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 script/deploy/sequences/uniswap-v3-allocated-dtl.json diff --git a/script/deploy/sequences/uniswap-v3-allocated-dtl.json b/script/deploy/sequences/uniswap-v3-allocated-dtl.json new file mode 100644 index 00000000..c0258363 --- /dev/null +++ b/script/deploy/sequences/uniswap-v3-allocated-dtl.json @@ -0,0 +1,7 @@ +{ + "sequence": [ + { + "name": "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist" + } + ] +} From dd999a1ccc4382cfab7543624ea04c93aa8bebd5 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 18 Feb 2025 18:06:09 +0400 Subject: [PATCH 23/29] Adjust compiler version for interface --- src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol index 027e27e2..2fafaa82 100644 --- a/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity >=0.8.0; interface IUniswapV3DTLWithAllocatedAllowlist { // ========== ERRORS ========== // From 93903572e0c01bffd04f3f800f94a50d68ad3011 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 18 Feb 2025 18:09:17 +0400 Subject: [PATCH 24/29] Add optimizer flags --- foundry.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/foundry.toml b/foundry.toml index c2e02bd0..334d6f5c 100644 --- a/foundry.toml +++ b/foundry.toml @@ -11,6 +11,8 @@ fs_permissions = [ ffi = true solc_version = "0.8.19" evm_version = "paris" +optimizer = true +optimizer_runs = 200 [fuzz] runs = 1024 From 4316b2019cf7d63b7009b49cd8381e6b082a21e7 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 18 Feb 2025 18:10:18 +0400 Subject: [PATCH 25/29] chore: salt for DTL --- script/salts/salts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index 8fe240c3..3326964a 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -18,7 +18,7 @@ "0xf4d7d42633353828c29211c77c068516380a9c75c942fba88b1c01215c1001a6": "0xb07de304d67101f3cef70ee4e023a361d50b19eb13b59729724ad64e1f6aa88b" }, "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": { - "0x6e336f95ca94d3a841a4bfccfa526767ddd3461f1c8f157b86427612f760f227": "0xda0a9ac9527532a9e8c0bf0e7c25a87dbbbb903092036db0c685faeb8dd4ffbe" + "0x6daa621e22611091db5b051a7dbfb5c0f0ec3bf75454115e2fb4a9079c66289b": "0x3b013f20c0e68b196c5c4cd04e299b9faa4b2d71d25ac31bd70cc0d7a116e688" }, "CappedMerkleAllowlist": { "0x0249dded8310d17581f166a526ea9ded65b81112ccac0ee8a144e9770d2b8432": "0xf5746fa34aeff9866dc5ec58712f7f47045aea15db39a0aabf4dadc9d35c8854", From 0fe44ebaf6ac367ccc2fcb23af94f40bc8418192 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Mon, 24 Feb 2025 22:56:25 +0400 Subject: [PATCH 26/29] Updates to imports. Salts. --- script/salts/salts.json | 6 +++--- src/callbacks/liquidity/UniswapV2DTL.sol | 2 +- src/callbacks/liquidity/UniswapV3DTL.sol | 2 +- .../UniswapV3DTLWithAllocatedAllowlist.sol | 2 +- .../UniswapV3DTLWithAllocatedAllowlistTest.sol | 18 +++++++++--------- .../onBid.t.sol | 2 +- .../onCancel.t.sol | 2 +- .../onCreate.t.sol | 2 +- .../onCurate.t.sol | 2 +- .../onSettle.t.sol | 8 ++++---- .../setMerkleRoot.t.sol | 2 +- 11 files changed, 24 insertions(+), 24 deletions(-) diff --git a/script/salts/salts.json b/script/salts/salts.json index 62f5dbc2..6c5704bc 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -119,16 +119,16 @@ "0x71369782a004f899a09f30d15d07aea6e386231640ec5a67bf3f0ab2a7a335fe": "0xd546a781322897bd5be8fe859ddca634489f023edcc804545f0dc039f046cc2c" }, "Test_UniswapV2DirectToLiquidity": { - "0xf2b190e690a84e7be857af56398803943b855c7d589c61a9bb7795689a1f4086": "0x1446d0144b25261ce97bd9dfb74f095481741349546de789031f8189b39b687f" + "0x820db70374c2ffd13fd66deb7afba776b3a403561c28ce10994cae4694e96ee0": "0xb8f5361234f91908bda276227b012d5bb03026757344a7af40459a72ab0722f4" }, "Test_UniswapV2Router": { "0x82202d1015ce048c53cd194a4407a02c152ee834d4b503f3dbd41d3799ee0dbb": "0x67226a40a6c0b7968e2cf7c37240a16ea7f3deb588c2421d67ce10cb4494de7e" }, "Test_UniswapV3DTLWithAllocatedAllowlist": { - "0xd1693ad5a79e28f239ed97bcba831c44f94fdda24442c765182a676e3b6d48e1": "0x85a9a2e58352cc66d24640fbea18bf194ba67a6b85c4c8f81818089177f6ed65" + "0xbf5ebfb1c6601a4c83bbbe4701337ff6b3e558cb0221311247283d935a83a8fc": "0xa16fae553d108a500f1bb1c5a5b24764bd9e62d7b166452f6d624fabca71f8c5" }, "Test_UniswapV3DirectToLiquidity": { - "0x74a1f48af0886eb246c7a5ccd3fddc432320f2a6eab09cdeb998e4ea545bf8b4": "0x8d2eb44a9a6a44de1d0e1ccb0b9999633aaaf2bcf2b7b6671ec32b357939e645" + "0xa7b0391bbf2ed03a6ff5ee2b487f9bd689c7c030e44ca4c25de20346bc766a92": "0x46f99bc00335e71bcbeaaa0f83a5aca76278fda55cc32647f208ac5eb334166b" }, "Test_UniswapV3Factory": { "0xa56c03532e32af77794962a9477657f2caf39ad7070587c208fbf10ad705cf85": "0x19b9379f4d7172b3d99ce2f2bef5f3be5de1a581ed516956adcdf2f887aed861" diff --git a/src/callbacks/liquidity/UniswapV2DTL.sol b/src/callbacks/liquidity/UniswapV2DTL.sol index f7835962..f0e8cead 100644 --- a/src/callbacks/liquidity/UniswapV2DTL.sol +++ b/src/callbacks/liquidity/UniswapV2DTL.sol @@ -13,7 +13,7 @@ import {IUniswapV2Router02} from "@uniswap-v2-periphery-1.0.1/interfaces/IUniswa // Callbacks import {BaseDirectToLiquidity} from "./BaseDTL.sol"; -import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; +import {Callbacks} from "@axis-core-1.0.4/lib/Callbacks.sol"; /// @title UniswapV2DirectToLiquidity /// @notice This Callback contract deposits the proceeds from a batch auction into a Uniswap V2 pool diff --git a/src/callbacks/liquidity/UniswapV3DTL.sol b/src/callbacks/liquidity/UniswapV3DTL.sol index fd657044..57b18905 100644 --- a/src/callbacks/liquidity/UniswapV3DTL.sol +++ b/src/callbacks/liquidity/UniswapV3DTL.sol @@ -19,7 +19,7 @@ import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; // Callbacks import {BaseDirectToLiquidity} from "./BaseDTL.sol"; -import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; +import {Callbacks} from "@axis-core-1.0.4/lib/Callbacks.sol"; /// @title UniswapV3DirectToLiquidity /// @notice This Callback contract deposits the proceeds from a batch auction into a Uniswap V3 pool diff --git a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol index af51e3c1..4128f336 100644 --- a/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol +++ b/src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol @@ -5,7 +5,7 @@ import {MerkleProof} from "@openzeppelin-contracts-4.9.2/utils/cryptography/Merk import {UniswapV3DirectToLiquidity} from "./UniswapV3DTL.sol"; import {BaseDirectToLiquidity} from "./BaseDTL.sol"; -import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; +import {Callbacks} from "@axis-core-1.0.4/lib/Callbacks.sol"; import {IUniswapV3DTLWithAllocatedAllowlist} from "./IUniswapV3DTLWithAllocatedAllowlist.sol"; /// @notice Allocated allowlist version of the Uniswap V3 Direct To Liquidity callback. diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol index 3832b1d4..6b6b053c 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/UniswapV3DTLWithAllocatedAllowlistTest.sol @@ -2,12 +2,12 @@ pragma solidity 0.8.19; import {Test} from "@forge-std-1.9.1/Test.sol"; -import {Callbacks} from "@axis-core-1.0.1/lib/Callbacks.sol"; -import {Permit2User} from "@axis-core-1.0.1-test/lib/permit2/Permit2User.sol"; +import {Callbacks} from "@axis-core-1.0.4/lib/Callbacks.sol"; +import {Permit2User} from "@axis-core-1.0.4-test/lib/permit2/Permit2User.sol"; -import {IAuction} from "@axis-core-1.0.1/interfaces/modules/IAuction.sol"; -import {IAuctionHouse} from "@axis-core-1.0.1/interfaces/IAuctionHouse.sol"; -import {BatchAuctionHouse} from "@axis-core-1.0.1/BatchAuctionHouse.sol"; +import {IAuction} from "@axis-core-1.0.4/interfaces/modules/IAuction.sol"; +import {IAuctionHouse} from "@axis-core-1.0.4/interfaces/IAuctionHouse.sol"; +import {BatchAuctionHouse} from "@axis-core-1.0.4/BatchAuctionHouse.sol"; import {GUniFactory} from "@g-uni-v1-core-0.9.9/GUniFactory.sol"; import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; @@ -20,13 +20,13 @@ import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; import {UniswapV3DTLWithAllocatedAllowlist} from "../../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; -import {LinearVesting} from "@axis-core-1.0.1/modules/derivatives/LinearVesting.sol"; +import {LinearVesting} from "@axis-core-1.0.4/modules/derivatives/LinearVesting.sol"; import {MockBatchAuctionModule} from - "@axis-core-1.0.1-test/modules/Auction/MockBatchAuctionModule.sol"; + "@axis-core-1.0.4-test/modules/Auction/MockBatchAuctionModule.sol"; -import {keycodeFromVeecode, toKeycode} from "@axis-core-1.0.1/modules/Keycode.sol"; +import {keycodeFromVeecode, toKeycode} from "@axis-core-1.0.4/modules/Keycode.sol"; -import {MockERC20} from "@solmate-6.7.0/test/utils/mocks/MockERC20.sol"; +import {MockERC20} from "@solmate-6.8.0/test/utils/mocks/MockERC20.sol"; import {WithSalts} from "../../../lib/WithSalts.sol"; import {console2} from "@forge-std-1.9.1/console2.sol"; diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol index ab2e9556..f4eeb2d5 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onBid.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {UniswapV3DTLWithAllocatedAllowlist} from "../../../../src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; import {IUniswapV3DTLWithAllocatedAllowlist} from diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol index 4d426cd4..20b5347f 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCancel.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; contract UniswapV3DTLWithAllocatedAllowlistOnCancelTest is diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol index 98d382f4..7c798665 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCreate.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol index e7d44569..7a89d1c8 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onCurate.t.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.19; import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; contract UniswapV3DTLWithAllocatedAllowlistOnCurateTest is diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol index 2c7594e2..b12c077c 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/onSettle.t.sol @@ -5,8 +5,8 @@ import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; // Libraries -import {FixedPointMathLib} from "@solmate-6.7.0/utils/FixedPointMathLib.sol"; -import {ERC20} from "@solmate-6.7.0/tokens/ERC20.sol"; +import {FixedPointMathLib} from "@solmate-6.8.0/utils/FixedPointMathLib.sol"; +import {ERC20} from "@solmate-6.8.0/tokens/ERC20.sol"; // Uniswap import {IUniswapV3Pool} from @@ -18,10 +18,10 @@ import {TickMath} from "@uniswap-v3-core-1.0.1-solc-0.8-simulate/libraries/TickM import {GUniPool} from "@g-uni-v1-core-0.9.9/GUniPool.sol"; // AuctionHouse -import {ILinearVesting} from "@axis-core-1.0.1/interfaces/modules/derivatives/ILinearVesting.sol"; +import {ILinearVesting} from "@axis-core-1.0.4/interfaces/modules/derivatives/ILinearVesting.sol"; import {BaseDirectToLiquidity} from "../../../../src/callbacks/liquidity/BaseDTL.sol"; import {UniswapV3DirectToLiquidity} from "../../../../src/callbacks/liquidity/UniswapV3DTL.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {console2} from "@forge-std-1.9.1/console2.sol"; diff --git a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol index ff36eb69..11bf61cb 100644 --- a/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol +++ b/test/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist/setMerkleRoot.t.sol @@ -5,7 +5,7 @@ import {UniswapV3DirectToLiquidityWithAllocatedAllowlistTest} from "./UniswapV3DTLWithAllocatedAllowlistTest.sol"; import {UniswapV3DTLWithAllocatedAllowlist} from "src/callbacks/liquidity/UniswapV3DTLWithAllocatedAllowlist.sol"; -import {BaseCallback} from "@axis-core-1.0.1/bases/BaseCallback.sol"; +import {BaseCallback} from "@axis-core-1.0.4/bases/BaseCallback.sol"; import {BaseDirectToLiquidity} from "src/callbacks/liquidity/BaseDTL.sol"; import {IUniswapV3DTLWithAllocatedAllowlist} from "src/callbacks/liquidity/IUniswapV3DTLWithAllocatedAllowlist.sol"; From a0dea25ecdf20e39a2c78e25e78fdd0c4df0864e Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Mon, 24 Feb 2025 22:57:00 +0400 Subject: [PATCH 27/29] chore: update deployment salt --- script/salts/salts.json | 1 + 1 file changed, 1 insertion(+) diff --git a/script/salts/salts.json b/script/salts/salts.json index 6c5704bc..9daa39f7 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -37,6 +37,7 @@ "0x5425c9b9254dc9126002dd9f7b17b6ff643b79c5aed0ed2f116b70af3e163500": "0x262dcec529815acf06c81b7e0845ece78296140a248524da0cdd182fa8133ee9" }, "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": { + "0x181fdad91467a532ae9ebdc80915f54694efba1225f67606039c1b85f01fd483": "0x56fa0a987993fead1434db033954e96847b8fa412ba170eb7b3e3148dbf27e15", "0x6daa621e22611091db5b051a7dbfb5c0f0ec3bf75454115e2fb4a9079c66289b": "0x3b013f20c0e68b196c5c4cd04e299b9faa4b2d71d25ac31bd70cc0d7a116e688" }, "CappedMerkleAllowlist": { From f8ba1f06e8a9d9eba1409c56a6e129a946319840 Mon Sep 17 00:00:00 2001 From: Oighty Date: Mon, 24 Feb 2025 20:09:44 -0600 Subject: [PATCH 28/29] deploy: uni-v3 allocated allowlist to base --- deployments/.base-v1.0.1.json | 3 +++ script/env.json | 3 ++- script/salts/salts.json | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 deployments/.base-v1.0.1.json diff --git a/deployments/.base-v1.0.1.json b/deployments/.base-v1.0.1.json new file mode 100644 index 00000000..2763a03c --- /dev/null +++ b/deployments/.base-v1.0.1.json @@ -0,0 +1,3 @@ +{ +"deployments.callbacks.BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE25c5B81Ac47c97F4458c5b20916cE35B7638F7" +} diff --git a/script/env.json b/script/env.json index 2a212c39..2079a5df 100644 --- a/script/env.json +++ b/script/env.json @@ -68,7 +68,8 @@ "BatchMerkleAllowlist": "0x98c5c24eB3FFEFeCd1a666423978f7A030319A78", "BatchTokenAllowlist": "0x98a5d4827A57056d30df93C7Bd4Bc294cC6dC0b9", "BatchUniswapV2DirectToLiquidity": "0xE6F93df14cB554737A26acd2aB5fEf649921D7F2", - "BatchUniswapV3DirectToLiquidity": "0xE64d6e058dD5F76CCc8566c07b994090a24CCB75" + "BatchUniswapV3DirectToLiquidity": "0xE64d6e058dD5F76CCc8566c07b994090a24CCB75", + "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE25c5B81Ac47c97F4458c5b20916cE35B7638F7" } } }, diff --git a/script/salts/salts.json b/script/salts/salts.json index 9daa39f7..e48204b2 100644 --- a/script/salts/salts.json +++ b/script/salts/salts.json @@ -38,7 +38,8 @@ }, "BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": { "0x181fdad91467a532ae9ebdc80915f54694efba1225f67606039c1b85f01fd483": "0x56fa0a987993fead1434db033954e96847b8fa412ba170eb7b3e3148dbf27e15", - "0x6daa621e22611091db5b051a7dbfb5c0f0ec3bf75454115e2fb4a9079c66289b": "0x3b013f20c0e68b196c5c4cd04e299b9faa4b2d71d25ac31bd70cc0d7a116e688" + "0x6daa621e22611091db5b051a7dbfb5c0f0ec3bf75454115e2fb4a9079c66289b": "0x3b013f20c0e68b196c5c4cd04e299b9faa4b2d71d25ac31bd70cc0d7a116e688", + "0xfa068f11166e923192737f1de5d84c5c9f17a2cb504fdff8ab2bae2703c1dc55": "0xef23d7a54ac5936b84aad715bec0f1b580f0b35fee8236ddcf010491cb621399" }, "CappedMerkleAllowlist": { "0x0249dded8310d17581f166a526ea9ded65b81112ccac0ee8a144e9770d2b8432": "0xf5746fa34aeff9866dc5ec58712f7f47045aea15db39a0aabf4dadc9d35c8854", From 4aa6ef58ebebc09992b9058dd480c9947d732350 Mon Sep 17 00:00:00 2001 From: Jem <0x0xjem@gmail.com> Date: Tue, 25 Feb 2025 13:22:47 +0400 Subject: [PATCH 29/29] chore: linting --- deployments/.base-v1.0.1.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployments/.base-v1.0.1.json b/deployments/.base-v1.0.1.json index 2763a03c..211b7c0f 100644 --- a/deployments/.base-v1.0.1.json +++ b/deployments/.base-v1.0.1.json @@ -1,3 +1,3 @@ { -"deployments.callbacks.BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE25c5B81Ac47c97F4458c5b20916cE35B7638F7" + "deployments.callbacks.BatchUniswapV3DirectToLiquidityWithAllocatedAllowlist": "0xEE25c5B81Ac47c97F4458c5b20916cE35B7638F7" }