From cc384d156a4e5a0a06e1ec783041899013d27fb0 Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Fri, 26 Jul 2024 12:43:35 +0300 Subject: [PATCH 01/34] docs: status temperature (#984) * docs: status temperature * Update src/types/DataTypes.sol Co-authored-by: smol-ninja --------- Co-authored-by: smol-ninja --- src/types/DataTypes.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index c73b01b93..d43c94030 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -53,14 +53,19 @@ library Lockup { } /// @notice Enum representing the different statuses of a stream. + /// @dev The status can have a "temperature": + /// 1. Warm: Pending, Streaming. The passage of time alone can change the status. + /// 2. Cold: Settled, Canceled, Depleted. The passage of time alone cannot change the status. /// @custom:value0 PENDING Stream created but not started; assets are in a pending state. /// @custom:value1 STREAMING Active stream where assets are currently being streamed. /// @custom:value2 SETTLED All assets have been streamed; recipient is due to withdraw them. /// @custom:value3 CANCELED Canceled stream; remaining assets await recipient's withdrawal. /// @custom:value4 DEPLETED Depleted stream; all assets have been withdrawn and/or refunded. enum Status { + // Warm PENDING, STREAMING, + // Cold SETTLED, CANCELED, DEPLETED From c5b9e0d4b415a346c841801e8bf3eb8774ce733a Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Mon, 29 Jul 2024 12:23:46 +0300 Subject: [PATCH 02/34] refactor: reorder constant functions in interface (#992) * refactor: reorder MAX_BROKER_FEE * refactor: prioritise constants in interface --------- Co-authored-by: smol-ninja --- src/interfaces/ISablierV2Lockup.sol | 10 +++++----- src/interfaces/ISablierV2LockupDynamic.sol | 8 ++++---- src/interfaces/ISablierV2LockupTranched.sol | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol index 72c6fcf48..3be3d2309 100644 --- a/src/interfaces/ISablierV2Lockup.sol +++ b/src/interfaces/ISablierV2Lockup.sol @@ -67,6 +67,11 @@ interface ISablierV2Lockup is CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point + /// number where 1e18 is 100%. + /// @dev This value is hard coded as a constant. + function MAX_BROKER_FEE() external view returns (UD60x18); + /// @notice Retrieves the address of the ERC-20 asset to be distributed. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. @@ -144,11 +149,6 @@ interface ISablierV2Lockup is /// @param streamId The stream ID for the query. function isWarm(uint256 streamId) external view returns (bool result); - /// @notice Retrieves the maximum broker fee that can be charged by the broker, denoted as a fixed-point - /// number where 1e18 is 100%. - /// @dev This value is hard coded as a constant. - function MAX_BROKER_FEE() external view returns (UD60x18); - /// @notice Counter for stream IDs, used in the create functions. function nextStreamId() external view returns (uint256); diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol index df77c8f84..292b48d86 100644 --- a/src/interfaces/ISablierV2LockupDynamic.sol +++ b/src/interfaces/ISablierV2LockupDynamic.sol @@ -44,6 +44,10 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice The maximum number of segments allowed in a stream. + /// @dev This is initialized at construction time and cannot be changed later. + function MAX_SEGMENT_COUNT() external view returns (uint256); + /// @notice Retrieves the segments used to compose the dynamic distribution function. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. @@ -61,10 +65,6 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup { /// @return timestamps See the documentation in {DataTypes}. function getTimestamps(uint256 streamId) external view returns (LockupDynamic.Timestamps memory timestamps); - /// @notice The maximum number of segments allowed in a stream. - /// @dev This is initialized at construction time and cannot be changed later. - function MAX_SEGMENT_COUNT() external view returns (uint256); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/interfaces/ISablierV2LockupTranched.sol index 836925ccc..261accb9a 100644 --- a/src/interfaces/ISablierV2LockupTranched.sol +++ b/src/interfaces/ISablierV2LockupTranched.sol @@ -44,6 +44,10 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice The maximum number of tranches allowed in a stream. + /// @dev This is initialized at construction time and cannot be changed later. + function MAX_TRANCHE_COUNT() external view returns (uint256); + /// @notice Retrieves the full stream details. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. @@ -61,10 +65,6 @@ interface ISablierV2LockupTranched is ISablierV2Lockup { /// @param streamId The stream ID for the query. function getTranches(uint256 streamId) external view returns (LockupTranched.Tranche[] memory tranches); - /// @notice The maximum number of tranches allowed in a stream. - /// @dev This is initialized at construction time and cannot be changed later. - function MAX_TRANCHE_COUNT() external view returns (uint256); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ From 14bf8c9c41a8efb4a3f3eb9dcce9123545cd040b Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Fri, 19 Jul 2024 14:41:20 +0300 Subject: [PATCH 03/34] feat: add periphery contracts in src feat: add core dir in src refactor: remove redundant imports Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- script/DeployCore.s.sol | 8 +- script/DeployCore2.s.sol | 8 +- script/DeployDeterministicCore.s.sol | 8 +- script/DeployDeterministicCore2.s.sol | 8 +- script/DeployDeterministicLockupDynamic.s.sol | 4 +- script/DeployDeterministicLockupLinear.s.sol | 4 +- .../DeployDeterministicLockupTranched.s.sol | 4 +- script/DeployDeterministicNFTDescriptor.s.sol | 2 +- script/DeployLockupDynamic.s.sol | 4 +- script/DeployLockupLinear.s.sol | 4 +- script/DeployLockupTranched.s.sol | 4 +- script/DeployNFTDescriptor.s.sol | 2 +- script/GenerateSVG.s.sol | 6 +- script/Init.s.sol | 6 +- src/{ => core}/SablierV2LockupDynamic.sol | 0 src/{ => core}/SablierV2LockupLinear.sol | 0 src/{ => core}/SablierV2LockupTranched.sol | 0 src/{ => core}/SablierV2NFTDescriptor.sol | 0 src/{ => core}/abstracts/Adminable.sol | 0 src/{ => core}/abstracts/NoDelegateCall.sol | 0 src/{ => core}/abstracts/SablierV2Lockup.sol | 0 src/{ => core}/interfaces/IAdminable.sol | 0 .../interfaces/ISablierLockupRecipient.sol | 0 .../interfaces/ISablierV2Lockup.sol | 0 .../interfaces/ISablierV2LockupDynamic.sol | 0 .../interfaces/ISablierV2LockupLinear.sol | 0 .../interfaces/ISablierV2LockupTranched.sol | 0 .../interfaces/ISablierV2NFTDescriptor.sol | 0 src/{ => core}/libraries/Errors.sol | 0 src/{ => core}/libraries/Helpers.sol | 0 src/{ => core}/libraries/NFTSVG.sol | 0 src/{ => core}/libraries/SVGElements.sol | 0 src/{ => core}/types/DataTypes.sol | 0 src/periphery/SablierV2BatchLockup.sol | 347 ++++++++++++++++++ src/periphery/SablierV2MerkleLL.sol | 97 +++++ src/periphery/SablierV2MerkleLT.sol | 179 +++++++++ .../SablierV2MerkleLockupFactory.sol | 133 +++++++ .../abstracts/SablierV2MerkleLockup.sol | 164 +++++++++ .../interfaces/ISablierV2BatchLockup.sol | 140 +++++++ .../interfaces/ISablierV2MerkleLL.sol | 48 +++ .../interfaces/ISablierV2MerkleLT.sol | 53 +++ .../interfaces/ISablierV2MerkleLockup.sol | 82 +++++ .../ISablierV2MerkleLockupFactory.sol | 95 +++++ src/periphery/libraries/Errors.sol | 39 ++ src/periphery/types/DataTypes.sol | 119 ++++++ 45 files changed, 1532 insertions(+), 36 deletions(-) rename src/{ => core}/SablierV2LockupDynamic.sol (100%) rename src/{ => core}/SablierV2LockupLinear.sol (100%) rename src/{ => core}/SablierV2LockupTranched.sol (100%) rename src/{ => core}/SablierV2NFTDescriptor.sol (100%) rename src/{ => core}/abstracts/Adminable.sol (100%) rename src/{ => core}/abstracts/NoDelegateCall.sol (100%) rename src/{ => core}/abstracts/SablierV2Lockup.sol (100%) rename src/{ => core}/interfaces/IAdminable.sol (100%) rename src/{ => core}/interfaces/ISablierLockupRecipient.sol (100%) rename src/{ => core}/interfaces/ISablierV2Lockup.sol (100%) rename src/{ => core}/interfaces/ISablierV2LockupDynamic.sol (100%) rename src/{ => core}/interfaces/ISablierV2LockupLinear.sol (100%) rename src/{ => core}/interfaces/ISablierV2LockupTranched.sol (100%) rename src/{ => core}/interfaces/ISablierV2NFTDescriptor.sol (100%) rename src/{ => core}/libraries/Errors.sol (100%) rename src/{ => core}/libraries/Helpers.sol (100%) rename src/{ => core}/libraries/NFTSVG.sol (100%) rename src/{ => core}/libraries/SVGElements.sol (100%) rename src/{ => core}/types/DataTypes.sol (100%) create mode 100644 src/periphery/SablierV2BatchLockup.sol create mode 100644 src/periphery/SablierV2MerkleLL.sol create mode 100644 src/periphery/SablierV2MerkleLT.sol create mode 100644 src/periphery/SablierV2MerkleLockupFactory.sol create mode 100644 src/periphery/abstracts/SablierV2MerkleLockup.sol create mode 100644 src/periphery/interfaces/ISablierV2BatchLockup.sol create mode 100644 src/periphery/interfaces/ISablierV2MerkleLL.sol create mode 100644 src/periphery/interfaces/ISablierV2MerkleLT.sol create mode 100644 src/periphery/interfaces/ISablierV2MerkleLockup.sol create mode 100644 src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol create mode 100644 src/periphery/libraries/Errors.sol create mode 100644 src/periphery/types/DataTypes.sol diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol index df6239c8a..317f0746b 100644 --- a/script/DeployCore.s.sol +++ b/script/DeployCore.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol index a8059dabc..eafa8f9a4 100644 --- a/script/DeployCore2.s.sol +++ b/script/DeployCore2.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol index b65be9ae7..274c5dad7 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/DeployDeterministicCore.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol index 7b50fb75d..aa995688d 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/DeployDeterministicCore2.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol index 512f89223..e27c5012d 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/DeployDeterministicLockupDynamic.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol index de36726ab..dabca6452 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/DeployDeterministicLockupLinear.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/DeployDeterministicLockupTranched.s.sol index 9e2641c99..c9451f95e 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/DeployDeterministicLockupTranched.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/DeployDeterministicNFTDescriptor.s.sol index f7a72bff2..9d4a9cf1a 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/DeployDeterministicNFTDescriptor.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol index ae5a9a7cc..87ff72b38 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/DeployLockupDynamic.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol index 940966a2f..4b2a8fd49 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/DeployLockupLinear.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployLockupTranched.s.sol b/script/DeployLockupTranched.s.sol index adae8f7fe..a8d87ce78 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/DeployLockupTranched.s.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/DeployNFTDescriptor.s.sol b/script/DeployNFTDescriptor.s.sol index 6f3019171..3bef69c08 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/DeployNFTDescriptor.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/GenerateSVG.s.sol b/script/GenerateSVG.s.sol index 9a3b63b98..f8c2f08ce 100644 --- a/script/GenerateSVG.s.sol +++ b/script/GenerateSVG.s.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { NFTSVG } from "../src/libraries/NFTSVG.sol"; -import { SVGElements } from "../src/libraries/SVGElements.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { NFTSVG } from "../src/core/libraries/NFTSVG.sol"; +import { SVGElements } from "../src/core/libraries/SVGElements.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/script/Init.s.sol b/script/Init.s.sol index a944d4a94..1677ea7e9 100644 --- a/script/Init.s.sol +++ b/script/Init.s.sol @@ -7,9 +7,9 @@ import { ud60x18 } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; -import { Broker, LockupDynamic, LockupLinear } from "../src/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "../src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { Broker, LockupDynamic, LockupLinear } from "../src/core/types/DataTypes.sol"; import { BaseScript } from "./Base.s.sol"; diff --git a/src/SablierV2LockupDynamic.sol b/src/core/SablierV2LockupDynamic.sol similarity index 100% rename from src/SablierV2LockupDynamic.sol rename to src/core/SablierV2LockupDynamic.sol diff --git a/src/SablierV2LockupLinear.sol b/src/core/SablierV2LockupLinear.sol similarity index 100% rename from src/SablierV2LockupLinear.sol rename to src/core/SablierV2LockupLinear.sol diff --git a/src/SablierV2LockupTranched.sol b/src/core/SablierV2LockupTranched.sol similarity index 100% rename from src/SablierV2LockupTranched.sol rename to src/core/SablierV2LockupTranched.sol diff --git a/src/SablierV2NFTDescriptor.sol b/src/core/SablierV2NFTDescriptor.sol similarity index 100% rename from src/SablierV2NFTDescriptor.sol rename to src/core/SablierV2NFTDescriptor.sol diff --git a/src/abstracts/Adminable.sol b/src/core/abstracts/Adminable.sol similarity index 100% rename from src/abstracts/Adminable.sol rename to src/core/abstracts/Adminable.sol diff --git a/src/abstracts/NoDelegateCall.sol b/src/core/abstracts/NoDelegateCall.sol similarity index 100% rename from src/abstracts/NoDelegateCall.sol rename to src/core/abstracts/NoDelegateCall.sol diff --git a/src/abstracts/SablierV2Lockup.sol b/src/core/abstracts/SablierV2Lockup.sol similarity index 100% rename from src/abstracts/SablierV2Lockup.sol rename to src/core/abstracts/SablierV2Lockup.sol diff --git a/src/interfaces/IAdminable.sol b/src/core/interfaces/IAdminable.sol similarity index 100% rename from src/interfaces/IAdminable.sol rename to src/core/interfaces/IAdminable.sol diff --git a/src/interfaces/ISablierLockupRecipient.sol b/src/core/interfaces/ISablierLockupRecipient.sol similarity index 100% rename from src/interfaces/ISablierLockupRecipient.sol rename to src/core/interfaces/ISablierLockupRecipient.sol diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/core/interfaces/ISablierV2Lockup.sol similarity index 100% rename from src/interfaces/ISablierV2Lockup.sol rename to src/core/interfaces/ISablierV2Lockup.sol diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/core/interfaces/ISablierV2LockupDynamic.sol similarity index 100% rename from src/interfaces/ISablierV2LockupDynamic.sol rename to src/core/interfaces/ISablierV2LockupDynamic.sol diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/core/interfaces/ISablierV2LockupLinear.sol similarity index 100% rename from src/interfaces/ISablierV2LockupLinear.sol rename to src/core/interfaces/ISablierV2LockupLinear.sol diff --git a/src/interfaces/ISablierV2LockupTranched.sol b/src/core/interfaces/ISablierV2LockupTranched.sol similarity index 100% rename from src/interfaces/ISablierV2LockupTranched.sol rename to src/core/interfaces/ISablierV2LockupTranched.sol diff --git a/src/interfaces/ISablierV2NFTDescriptor.sol b/src/core/interfaces/ISablierV2NFTDescriptor.sol similarity index 100% rename from src/interfaces/ISablierV2NFTDescriptor.sol rename to src/core/interfaces/ISablierV2NFTDescriptor.sol diff --git a/src/libraries/Errors.sol b/src/core/libraries/Errors.sol similarity index 100% rename from src/libraries/Errors.sol rename to src/core/libraries/Errors.sol diff --git a/src/libraries/Helpers.sol b/src/core/libraries/Helpers.sol similarity index 100% rename from src/libraries/Helpers.sol rename to src/core/libraries/Helpers.sol diff --git a/src/libraries/NFTSVG.sol b/src/core/libraries/NFTSVG.sol similarity index 100% rename from src/libraries/NFTSVG.sol rename to src/core/libraries/NFTSVG.sol diff --git a/src/libraries/SVGElements.sol b/src/core/libraries/SVGElements.sol similarity index 100% rename from src/libraries/SVGElements.sol rename to src/core/libraries/SVGElements.sol diff --git a/src/types/DataTypes.sol b/src/core/types/DataTypes.sol similarity index 100% rename from src/types/DataTypes.sol rename to src/core/types/DataTypes.sol diff --git a/src/periphery/SablierV2BatchLockup.sol b/src/periphery/SablierV2BatchLockup.sol new file mode 100644 index 000000000..fb2b8b3b7 --- /dev/null +++ b/src/periphery/SablierV2BatchLockup.sol @@ -0,0 +1,347 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { ISablierV2LockupDynamic } from "../core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "../core/types/DataTypes.sol"; + +import { ISablierV2BatchLockup } from "./interfaces/ISablierV2BatchLockup.sol"; +import { Errors } from "./libraries/Errors.sol"; +import { BatchLockup } from "./types/DataTypes.sol"; + +/// @title SablierV2BatchLockup +/// @notice See the documentation in {ISablierV2BatchLockup}. +contract SablierV2BatchLockup is ISablierV2BatchLockup { + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-DYNAMIC + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2BatchLockup + function createWithDurationsLD( + ISablierV2LockupDynamic lockupDynamic, + IERC20 asset, + BatchLockup.CreateWithDurationsLD[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets. + _handleTransfer(address(lockupDynamic), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupDynamic.createWithDurations( + LockupDynamic.CreateWithDurations({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + segments: batch[i].segments, + broker: batch[i].broker + }) + ); + } + } + + /// @inheritdoc ISablierV2BatchLockup + function createWithTimestampsLD( + ISablierV2LockupDynamic lockupDynamic, + IERC20 asset, + BatchLockup.CreateWithTimestampsLD[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets. + _handleTransfer(address(lockupDynamic), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupDynamic.createWithTimestamps( + LockupDynamic.CreateWithTimestamps({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + startTime: batch[i].startTime, + segments: batch[i].segments, + broker: batch[i].broker + }) + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-LINEAR + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2BatchLockup + function createWithDurationsLL( + ISablierV2LockupLinear lockupLinear, + IERC20 asset, + BatchLockup.CreateWithDurationsLL[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupLinear} to spend the amount of assets. + _handleTransfer(address(lockupLinear), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupLinear.createWithDurations( + LockupLinear.CreateWithDurations({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + durations: batch[i].durations, + broker: batch[i].broker + }) + ); + } + } + + /// @inheritdoc ISablierV2BatchLockup + function createWithTimestampsLL( + ISablierV2LockupLinear lockupLinear, + IERC20 asset, + BatchLockup.CreateWithTimestampsLL[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch is not empty. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupLinear} to spend the amount of assets. + _handleTransfer(address(lockupLinear), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupLinear.createWithTimestamps( + LockupLinear.CreateWithTimestamps({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + timestamps: batch[i].timestamps, + broker: batch[i].broker + }) + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2BatchLockup + function createWithDurationsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + BatchLockup.CreateWithDurationsLT[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + _handleTransfer(address(lockupTranched), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupTranched.createWithDurations( + LockupTranched.CreateWithDurations({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + tranches: batch[i].tranches, + broker: batch[i].broker + }) + ); + } + } + + /// @inheritdoc ISablierV2BatchLockup + function createWithTimestampsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + BatchLockup.CreateWithTimestampsLT[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2BatchLockup_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + _handleTransfer(address(lockupTranched), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupTranched.createWithTimestamps( + LockupTranched.CreateWithTimestamps({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + startTime: batch[i].startTime, + tranches: batch[i].tranches, + broker: batch[i].broker + }) + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + HELPER FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Helper function to approve a Sablier contract to spend funds from the batchLockup. If the current allowance + /// is insufficient, this function approves Sablier to spend the exact `amount`. + /// The {SafeERC20.forceApprove} function is used to handle special ERC-20 assets (e.g. USDT) that require the + /// current allowance to be zero before setting it to a non-zero value. + function _approve(address sablierContract, IERC20 asset, uint256 amount) internal { + uint256 allowance = asset.allowance({ owner: address(this), spender: sablierContract }); + if (allowance < amount) { + asset.forceApprove({ spender: sablierContract, value: amount }); + } + } + + /// @dev Helper function to transfer assets from the caller to the batchLockup contract and approve the Sablier + /// contract. + function _handleTransfer(address sablierContract, IERC20 asset, uint256 amount) internal { + // Transfer the assets to the batchLockup contract. + asset.safeTransferFrom({ from: msg.sender, to: address(this), value: amount }); + + // Approve the Sablier contract to spend funds. + _approve(sablierContract, asset, amount); + } +} diff --git a/src/periphery/SablierV2MerkleLL.sol b/src/periphery/SablierV2MerkleLL.sol new file mode 100644 index 000000000..731b3869a --- /dev/null +++ b/src/periphery/SablierV2MerkleLL.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { ud } from "@prb/math/src/UD60x18.sol"; + +import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; +import { Broker, LockupLinear } from "../core/types/DataTypes.sol"; + +import { SablierV2MerkleLockup } from "./abstracts/SablierV2MerkleLockup.sol"; +import { ISablierV2MerkleLL } from "./interfaces/ISablierV2MerkleLL.sol"; +import { MerkleLockup } from "./types/DataTypes.sol"; + +/// @title SablierV2MerkleLL +/// @notice See the documentation in {ISablierV2MerkleLL}. +contract SablierV2MerkleLL is + ISablierV2MerkleLL, // 2 inherited components + SablierV2MerkleLockup // 4 inherited components +{ + using BitMaps for BitMaps.BitMap; + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLL + ISablierV2LockupLinear public immutable override LOCKUP_LINEAR; + + /// @inheritdoc ISablierV2MerkleLL + LockupLinear.Durations public override streamDurations; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier + /// contract. + constructor( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations_ + ) + SablierV2MerkleLockup(baseParams) + { + LOCKUP_LINEAR = lockupLinear; + streamDurations = streamDurations_; + + // Max approve the Sablier contract to spend funds from the MerkleLockup contract. + ASSET.forceApprove(address(LOCKUP_LINEAR), type(uint256).max); + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLL + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + override + returns (uint256 streamId) + { + // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second + // preimage attacks. + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); + + // Check: validate the function. + _checkClaim(index, leaf, merkleProof); + + // Effect: mark the index as claimed. + _claimedBitMap.set(index); + + // Interaction: create the stream via {SablierV2LockupLinear}. + streamId = LOCKUP_LINEAR.createWithDurations( + LockupLinear.CreateWithDurations({ + sender: admin, + recipient: recipient, + totalAmount: amount, + asset: ASSET, + cancelable: CANCELABLE, + transferable: TRANSFERABLE, + durations: streamDurations, + broker: Broker({ account: address(0), fee: ud(0) }) + }) + ); + + // Log the claim. + emit Claim(index, recipient, amount, streamId); + } +} diff --git a/src/periphery/SablierV2MerkleLT.sol b/src/periphery/SablierV2MerkleLT.sol new file mode 100644 index 000000000..ad9414de6 --- /dev/null +++ b/src/periphery/SablierV2MerkleLT.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { uUNIT } from "@prb/math/src/UD2x18.sol"; +import { UD60x18, ud60x18, ZERO } from "@prb/math/src/UD60x18.sol"; + +import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { Broker, LockupTranched } from "../core/types/DataTypes.sol"; + +import { SablierV2MerkleLockup } from "./abstracts/SablierV2MerkleLockup.sol"; +import { ISablierV2MerkleLT } from "./interfaces/ISablierV2MerkleLT.sol"; +import { Errors } from "./libraries/Errors.sol"; +import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; + +/// @title SablierV2MerkleLT +/// @notice See the documentation in {ISablierV2MerkleLT}. +contract SablierV2MerkleLT is + ISablierV2MerkleLT, // 2 inherited components + SablierV2MerkleLockup // 4 inherited components +{ + using BitMaps for BitMaps.BitMap; + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLT + ISablierV2LockupTranched public immutable override LOCKUP_TRANCHED; + + /// @inheritdoc ISablierV2MerkleLT + uint64 public immutable override TOTAL_PERCENTAGE; + + /// @dev The tranches with their respective unlock percentages and durations. + MerkleLT.TrancheWithPercentage[] internal _tranchesWithPercentages; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier + /// contract. + constructor( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages + ) + SablierV2MerkleLockup(baseParams) + { + LOCKUP_TRANCHED = lockupTranched; + + uint256 count = tranchesWithPercentages.length; + + // Calculate the total percentage of the tranches and save them in the contract state. + uint64 totalPercentage; + for (uint256 i = 0; i < count; ++i) { + uint64 percentage = tranchesWithPercentages[i].unlockPercentage.unwrap(); + totalPercentage += percentage; + _tranchesWithPercentages.push(tranchesWithPercentages[i]); + } + TOTAL_PERCENTAGE = totalPercentage; + + // Max approve the Sablier contract to spend funds from the MerkleLockup contract. + ASSET.forceApprove(address(LOCKUP_TRANCHED), type(uint256).max); + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLT + function getTranchesWithPercentages() external view override returns (MerkleLT.TrancheWithPercentage[] memory) { + return _tranchesWithPercentages; + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLT + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + override + returns (uint256 streamId) + { + // Check: the sum of percentages equals 100%. + if (TOTAL_PERCENTAGE != uUNIT) { + revert Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred(TOTAL_PERCENTAGE); + } + + // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second + // preimage attacks. + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); + + // Check: validate the function. + _checkClaim(index, leaf, merkleProof); + + // Calculate the tranches based on the unlock percentages. + LockupTranched.TrancheWithDuration[] memory tranches = _calculateTranches(amount); + + // Effect: mark the index as claimed. + _claimedBitMap.set(index); + + // Interaction: create the stream via {SablierV2LockupTranched}. + streamId = LOCKUP_TRANCHED.createWithDurations( + LockupTranched.CreateWithDurations({ + sender: admin, + recipient: recipient, + totalAmount: amount, + asset: ASSET, + cancelable: CANCELABLE, + transferable: TRANSFERABLE, + tranches: tranches, + broker: Broker({ account: address(0), fee: ZERO }) + }) + ); + + // Log the claim. + emit Claim(index, recipient, amount, streamId); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Calculates the tranches based on the claim amount and the unlock percentages for each tranche. + function _calculateTranches(uint128 claimAmount) + internal + view + returns (LockupTranched.TrancheWithDuration[] memory tranches) + { + // Load the tranches in memory (to save gas). + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = _tranchesWithPercentages; + + // Declare the variables needed for calculation. + uint128 calculatedAmountsSum; + UD60x18 claimAmountUD = ud60x18(claimAmount); + uint256 trancheCount = tranchesWithPercentages.length; + tranches = new LockupTranched.TrancheWithDuration[](trancheCount); + + // Iterate over each tranche to calculate its unlock amount. + for (uint256 i = 0; i < trancheCount; ++i) { + // Convert the tranche's percentage from the `UD2x18` to the `UD60x18` type. + UD60x18 percentage = (tranchesWithPercentages[i].unlockPercentage).intoUD60x18(); + + // Calculate the tranche's amount by multiplying the claim amount by the unlock percentage. + uint128 calculatedAmount = claimAmountUD.mul(percentage).intoUint128(); + + // Create the tranche with duration. + tranches[i] = LockupTranched.TrancheWithDuration({ + amount: calculatedAmount, + duration: tranchesWithPercentages[i].duration + }); + + // Add the calculated tranche amount. + calculatedAmountsSum += calculatedAmount; + } + + // It should never be the case that the sum of the calculated amounts is greater than the claim amount because + // PRBMath always rounds down. + assert(calculatedAmountsSum <= claimAmount); + + // Since there can be rounding errors, the last tranche amount needs to be adjusted to ensure the sum of all + // tranche amounts equals the claim amount. + if (calculatedAmountsSum < claimAmount) { + unchecked { + tranches[trancheCount - 1].amount += claimAmount - calculatedAmountsSum; + } + } + } +} diff --git a/src/periphery/SablierV2MerkleLockupFactory.sol b/src/periphery/SablierV2MerkleLockupFactory.sol new file mode 100644 index 000000000..a4aede999 --- /dev/null +++ b/src/periphery/SablierV2MerkleLockupFactory.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { uUNIT } from "@prb/math/src/UD2x18.sol"; + +import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupLinear } from "../core/types/DataTypes.sol"; + +import { ISablierV2MerkleLL } from "./interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLockupFactory } from "./interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ISablierV2MerkleLT } from "./interfaces/ISablierV2MerkleLT.sol"; +import { SablierV2MerkleLL } from "./SablierV2MerkleLL.sol"; +import { SablierV2MerkleLT } from "./SablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; + +/// @title SablierV2MerkleLockupFactory +/// @notice See the documentation in {ISablierV2MerkleLockupFactory}. +contract SablierV2MerkleLockupFactory is ISablierV2MerkleLockupFactory { + /*////////////////////////////////////////////////////////////////////////// + USER-FACING CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLockupFactory + function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) + external + pure + override + returns (bool result) + { + uint64 totalPercentage; + for (uint256 i = 0; i < tranches.length; ++i) { + totalPercentage += tranches[i].unlockPercentage.unwrap(); + } + return totalPercentage == uUNIT; + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice inheritdoc ISablierV2MerkleLockupFactory + function createMerkleLL( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierV2MerkleLL merkleLL) + { + // Hash the parameters to generate a salt. + bytes32 salt = keccak256( + abi.encodePacked( + msg.sender, + baseParams.asset, + baseParams.cancelable, + baseParams.expiration, + baseParams.initialAdmin, + abi.encode(baseParams.ipfsCID), + baseParams.merkleRoot, + bytes32(abi.encodePacked(baseParams.name)), + baseParams.transferable, + lockupLinear, + abi.encode(streamDurations) + ) + ); + + // Deploy the MerkleLockup contract with CREATE2. + merkleLL = new SablierV2MerkleLL{ salt: salt }(baseParams, lockupLinear, streamDurations); + + // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. + emit CreateMerkleLL(merkleLL, baseParams, lockupLinear, streamDurations, aggregateAmount, recipientCount); + } + + /// @notice inheritdoc ISablierV2MerkleLockupFactory + function createMerkleLT( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierV2MerkleLT merkleLT) + { + uint256 totalDuration; + + // Need a separate scope to prevent the stack too deep error. + { + // Calculate the sum of percentages and durations across all tranches. + uint256 count = tranchesWithPercentages.length; + for (uint256 i = 0; i < count; ++i) { + unchecked { + // Safe to use `unchecked` because its only used in the event. + totalDuration += tranchesWithPercentages[i].duration; + } + } + } + + // Hash the parameters to generate a salt. + bytes32 salt = keccak256( + abi.encodePacked( + msg.sender, + baseParams.asset, + baseParams.cancelable, + baseParams.expiration, + baseParams.initialAdmin, + abi.encode(baseParams.ipfsCID), + baseParams.merkleRoot, + bytes32(abi.encodePacked(baseParams.name)), + baseParams.transferable, + lockupTranched, + abi.encode(tranchesWithPercentages) + ) + ); + + // Deploy the MerkleLockup contract with CREATE2. + merkleLT = new SablierV2MerkleLT{ salt: salt }(baseParams, lockupTranched, tranchesWithPercentages); + + // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. + emit CreateMerkleLT( + merkleLT, + baseParams, + lockupTranched, + tranchesWithPercentages, + totalDuration, + aggregateAmount, + recipientCount + ); + } +} diff --git a/src/periphery/abstracts/SablierV2MerkleLockup.sol b/src/periphery/abstracts/SablierV2MerkleLockup.sol new file mode 100644 index 000000000..17f84485a --- /dev/null +++ b/src/periphery/abstracts/SablierV2MerkleLockup.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import { MerkleProof } from "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; +import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; + +import { Adminable } from "../../core/abstracts/Adminable.sol"; + +import { ISablierV2MerkleLockup } from "../interfaces/ISablierV2MerkleLockup.sol"; +import { MerkleLockup } from "../types/DataTypes.sol"; +import { Errors } from "../libraries/Errors.sol"; + +/// @title SablierV2MerkleLockup +/// @notice See the documentation in {ISablierV2MerkleLockup}. +abstract contract SablierV2MerkleLockup is + ISablierV2MerkleLockup, // 2 inherited component + Adminable // 1 inherited component +{ + using BitMaps for BitMaps.BitMap; + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLockup + IERC20 public immutable override ASSET; + + /// @inheritdoc ISablierV2MerkleLockup + bool public immutable override CANCELABLE; + + /// @inheritdoc ISablierV2MerkleLockup + uint40 public immutable override EXPIRATION; + + /// @inheritdoc ISablierV2MerkleLockup + bytes32 public immutable override MERKLE_ROOT; + + /// @dev The name of the campaign stored as bytes32. + bytes32 internal immutable NAME; + + /// @inheritdoc ISablierV2MerkleLockup + bool public immutable override TRANSFERABLE; + + /// @inheritdoc ISablierV2MerkleLockup + string public ipfsCID; + + /// @dev Packed booleans that record the history of claims. + BitMaps.BitMap internal _claimedBitMap; + + /// @dev The timestamp when the first claim is made. + uint40 internal _firstClaimTime; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Constructs the contract by initializing the immutable state variables. + constructor(MerkleLockup.ConstructorParams memory params) { + // Check: the campaign name is not greater than 32 bytes + if (bytes(params.name).length > 32) { + revert Errors.SablierV2MerkleLockup_CampaignNameTooLong({ + nameLength: bytes(params.name).length, + maxLength: 32 + }); + } + + admin = params.initialAdmin; + ASSET = params.asset; + CANCELABLE = params.cancelable; + EXPIRATION = params.expiration; + ipfsCID = params.ipfsCID; + MERKLE_ROOT = params.merkleRoot; + NAME = bytes32(abi.encodePacked(params.name)); + TRANSFERABLE = params.transferable; + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLockup + function getFirstClaimTime() external view override returns (uint40) { + return _firstClaimTime; + } + + /// @inheritdoc ISablierV2MerkleLockup + function hasClaimed(uint256 index) public view override returns (bool) { + return _claimedBitMap.get(index); + } + + /// @inheritdoc ISablierV2MerkleLockup + function hasExpired() public view override returns (bool) { + return EXPIRATION > 0 && EXPIRATION <= block.timestamp; + } + + /// @inheritdoc ISablierV2MerkleLockup + function name() external view override returns (string memory) { + return string(abi.encodePacked(NAME)); + } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2MerkleLockup + function clawback(address to, uint128 amount) external override onlyAdmin { + // Check: current timestamp is over the grace period and the campaign has not expired. + if (_hasGracePeriodPassed() && !hasExpired()) { + revert Errors.SablierV2MerkleLockup_ClawbackNotAllowed({ + blockTimestamp: block.timestamp, + expiration: EXPIRATION, + firstClaimTime: _firstClaimTime + }); + } + + // Effect: transfer the tokens to the provided address. + ASSET.safeTransfer(to, amount); + + // Log the clawback. + emit Clawback(admin, to, amount); + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Returns a flag indicating whether the grace period has passed. + /// @dev The grace period is 7 days after the first claim. + function _hasGracePeriodPassed() internal view returns (bool) { + return _firstClaimTime > 0 && block.timestamp > _firstClaimTime + 7 days; + } + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Validates the parameters of the `claim` function, which is implemented by child contracts. + function _checkClaim(uint256 index, bytes32 leaf, bytes32[] calldata merkleProof) internal { + // Check: the campaign has not expired. + if (hasExpired()) { + revert Errors.SablierV2MerkleLockup_CampaignExpired({ + blockTimestamp: block.timestamp, + expiration: EXPIRATION + }); + } + + // Check: the index has not been claimed. + if (_claimedBitMap.get(index)) { + revert Errors.SablierV2MerkleLockup_StreamClaimed(index); + } + + // Check: the input claim is included in the Merkle tree. + if (!MerkleProof.verify(merkleProof, MERKLE_ROOT, leaf)) { + revert Errors.SablierV2MerkleLockup_InvalidProof(); + } + + // Effect: set the `_firstClaimTime` if its zero. + if (_firstClaimTime == 0) { + _firstClaimTime = uint40(block.timestamp); + } + } +} diff --git a/src/periphery/interfaces/ISablierV2BatchLockup.sol b/src/periphery/interfaces/ISablierV2BatchLockup.sol new file mode 100644 index 000000000..4e0991113 --- /dev/null +++ b/src/periphery/interfaces/ISablierV2BatchLockup.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2LockupDynamic } from "../../core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; + +import { BatchLockup } from "../types/DataTypes.sol"; + +/// @title ISablierV2BatchLockup +/// @notice Helper to batch create Sablier V2 Lockup streams. +interface ISablierV2BatchLockup { + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-LINEAR + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a batch of LockupLinear streams using `createWithDurations`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupLinear.createWithDurations} must be met for each stream. + /// + /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupLinear.createWithDurations}. + /// @return streamIds The ids of the newly created streams. + function createWithDurationsLL( + ISablierV2LockupLinear lockupLinear, + IERC20 asset, + BatchLockup.CreateWithDurationsLL[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /// @notice Creates a batch of LockupLinear streams using `createWithTimestamps`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupLinear.createWithTimestamps} must be met for each stream. + /// + /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupLinear.createWithTimestamps}. + /// @return streamIds The ids of the newly created streams. + function createWithTimestampsLL( + ISablierV2LockupLinear lockupLinear, + IERC20 asset, + BatchLockup.CreateWithTimestampsLL[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-DYNAMIC + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a batch of Lockup Dynamic streams using `createWithDurations`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupDynamic.createWithDurations} must be met for each stream. + /// + /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupDynamic.createWithDurations}. + /// @return streamIds The ids of the newly created streams. + function createWithDurationsLD( + ISablierV2LockupDynamic lockupDynamic, + IERC20 asset, + BatchLockup.CreateWithDurationsLD[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /// @notice Creates a batch of Lockup Dynamic streams using `createWithTimestamps`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupDynamic.createWithTimestamps} must be met for each stream. + /// + /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupDynamic.createWithTimestamps}. + /// @return streamIds The ids of the newly created streams. + function createWithTimestampsLD( + ISablierV2LockupDynamic lockupDynamic, + IERC20 asset, + BatchLockup.CreateWithTimestampsLD[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a batch of LockupTranched streams using `createWithDurations`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupTranched.createWithDurations} must be met for each stream. + /// + /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupTranched.createWithDurations}. + /// @return streamIds The ids of the newly created streams. + function createWithDurationsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + BatchLockup.CreateWithDurationsLT[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /// @notice Creates a batch of LockupTranched streams using `createWithTimestamps`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupTranched.createWithTimestamps} must be met for each stream. + /// + /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupTranched.createWithTimestamps}. + /// @return streamIds The ids of the newly created streams. + function createWithTimestampsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + BatchLockup.CreateWithTimestampsLT[] calldata batch + ) + external + returns (uint256[] memory streamIds); +} diff --git a/src/periphery/interfaces/ISablierV2MerkleLL.sol b/src/periphery/interfaces/ISablierV2MerkleLL.sol new file mode 100644 index 000000000..89bba74a3 --- /dev/null +++ b/src/periphery/interfaces/ISablierV2MerkleLL.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; + +import { ISablierV2MerkleLockup } from "./ISablierV2MerkleLockup.sol"; + +/// @title ISablierV2MerkleLL +/// @notice MerkleLockup campaign that creates LockupLinear streams. +interface ISablierV2MerkleLL is ISablierV2MerkleLockup { + /*////////////////////////////////////////////////////////////////////////// + CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice The address of the {SablierV2LockupLinear} contract. + function LOCKUP_LINEAR() external view returns (ISablierV2LockupLinear); + + /// @notice The total streaming duration of each stream. + function streamDurations() external view returns (uint40 cliff, uint40 duration); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Makes the claim by creating a LockupLinear stream to the recipient. A stream NFT is minted to the + /// recipient. + /// + /// @dev Emits a {Claim} event. + /// + /// Requirements: + /// - The campaign must not have expired. + /// - The stream must not have been claimed already. + /// - The Merkle proof must be valid. + /// + /// @param index The index of the recipient in the Merkle tree. + /// @param recipient The address of the stream holder. + /// @param amount The amount of ERC-20 assets to be distributed via the claimed stream. + /// @param merkleProof The proof of inclusion in the Merkle tree. + /// @return streamId The id of the newly created stream. + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + returns (uint256 streamId); +} diff --git a/src/periphery/interfaces/ISablierV2MerkleLT.sol b/src/periphery/interfaces/ISablierV2MerkleLT.sol new file mode 100644 index 000000000..aad3f0602 --- /dev/null +++ b/src/periphery/interfaces/ISablierV2MerkleLT.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; + +import { ISablierV2MerkleLockup } from "./ISablierV2MerkleLockup.sol"; +import { MerkleLT } from "../types/DataTypes.sol"; + +/// @title ISablierV2MerkleLT +/// @notice MerkleLockup campaign that creates LockupTranched streams. +interface ISablierV2MerkleLT is ISablierV2MerkleLockup { + /*////////////////////////////////////////////////////////////////////////// + CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Retrieves the tranches with their respective unlock percentages and durations. + function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); + + /// @notice The address of the {SablierV2LockupTranched} contract. + function LOCKUP_TRANCHED() external view returns (ISablierV2LockupTranched); + + /// @notice The total percentage of the tranches. + function TOTAL_PERCENTAGE() external view returns (uint64); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Makes the claim by creating a LockupTranched stream to the recipient. A stream NFT is minted to the + /// recipient. + /// + /// @dev Emits a {Claim} event. + /// + /// Requirements: + /// - The campaign must not have expired. + /// - The stream must not have been claimed already. + /// - The Merkle proof must be valid. + /// - TOTAL_PERCENTAGE must be equal to 100%. + /// + /// @param index The index of the recipient in the Merkle tree. + /// @param recipient The address of the stream holder. + /// @param amount The amount of ERC-20 assets to be distributed via the claimed stream. + /// @param merkleProof The proof of inclusion in the Merkle tree. + /// @return streamId The id of the newly created stream. + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + returns (uint256 streamId); +} diff --git a/src/periphery/interfaces/ISablierV2MerkleLockup.sol b/src/periphery/interfaces/ISablierV2MerkleLockup.sol new file mode 100644 index 000000000..47e3f3c00 --- /dev/null +++ b/src/periphery/interfaces/ISablierV2MerkleLockup.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { IAdminable } from "../../core/interfaces/IAdminable.sol"; + +/// @title ISablierV2MerkleLockup +/// @notice A contract that lets user claim Sablier streams using Merkle proofs. A popular use case for MerkleLockup +/// is airstreams: a portmanteau of "airdrop" and "stream". This is an airdrop model where the tokens are distributed +/// over time, as opposed to all at once. +/// @dev This is the base interface for MerkleLockup. See the Sablier docs for more guidance: https://docs.sablier.com +interface ISablierV2MerkleLockup is IAdminable { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a recipient claims a stream. + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); + + /// @notice Emitted when the admin claws back the unclaimed tokens. + event Clawback(address indexed admin, address indexed to, uint128 amount); + + /*////////////////////////////////////////////////////////////////////////// + CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice The ERC-20 asset to distribute. + /// @dev This is an immutable state variable. + function ASSET() external returns (IERC20); + + /// @notice A flag indicating whether the streams can be canceled. + /// @dev This is an immutable state variable. + function CANCELABLE() external returns (bool); + + /// @notice The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. + /// @dev This is an immutable state variable. + function EXPIRATION() external returns (uint40); + + /// @notice Returns the timestamp when the first claim is made. + function getFirstClaimTime() external view returns (uint40); + + /// @notice Returns a flag indicating whether a claim has been made for a given index. + /// @dev Uses a bitmap to save gas. + /// @param index The index of the recipient to check. + function hasClaimed(uint256 index) external returns (bool); + + /// @notice Returns a flag indicating whether the campaign has expired. + function hasExpired() external view returns (bool); + + /// @notice The content identifier for indexing the campaign on IPFS. + function ipfsCID() external view returns (string memory); + + /// @notice The root of the Merkle tree used to validate the proofs of inclusion. + /// @dev This is an immutable state variable. + function MERKLE_ROOT() external returns (bytes32); + + /// @notice Retrieves the name of the campaign. + function name() external returns (string memory); + + /// @notice A flag indicating whether the stream NFTs are transferable. + /// @dev This is an immutable state variable. + function TRANSFERABLE() external returns (bool); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Claws back the unclaimed tokens from the campaign. + /// + /// @dev Emits a {Clawback} event. + /// + /// Requirements: + /// - The caller must be the admin. + /// - No claim must be made, OR + /// The current timestamp must not exceed 7 days after the first claim, OR + /// The campaign must be expired. + /// + /// @param to The address to receive the tokens. + /// @param amount The amount of tokens to claw back. + function clawback(address to, uint128 amount) external; +} diff --git a/src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol b/src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol new file mode 100644 index 000000000..0aa0b83df --- /dev/null +++ b/src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupLinear } from "../../core/types/DataTypes.sol"; + +import { ISablierV2MerkleLL } from "./ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "./ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "../types/DataTypes.sol"; + +/// @title ISablierV2MerkleLockupFactory +/// @notice Deploys MerkleLockup campaigns with CREATE2. +interface ISablierV2MerkleLockupFactory { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a {SablierV2MerkleLL} campaign is created. + event CreateMerkleLL( + ISablierV2MerkleLL indexed merkleLL, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations streamDurations, + uint256 aggregateAmount, + uint256 recipientCount + ); + + /// @notice Emitted when a {SablierV2MerkleLT} campaign is created. + event CreateMerkleLT( + ISablierV2MerkleLT indexed merkleLT, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, + uint256 totalDuration, + uint256 aggregateAmount, + uint256 recipientCount + ); + + /*////////////////////////////////////////////////////////////////////////// + CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Verifies if the sum of percentages in `tranches` equals 100% , i.e. 1e18. + /// @dev Reverts if the sum of percentages overflows. + /// @param tranches The tranches with their respective unlock percentages. + /// @return result True if the sum of percentages equals 100%, otherwise false. + function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) + external + pure + returns (bool result); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a new MerkleLockup campaign with a LockupLinear distribution. + /// @dev Emits a {CreateMerkleLL} event. + /// @param baseParams Struct encapsulating the {SablierV2MerkleLockup} parameters, which are documented in + /// {DataTypes}. + /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param streamDurations The durations for each stream. + /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. + /// @param recipientCount The total number of recipients who are eligible to claim. + /// @return merkleLL The address of the newly created MerkleLockup contract. + function createMerkleLL( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations memory streamDurations, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierV2MerkleLL merkleLL); + + /// @notice Creates a new MerkleLockup campaign with a LockupTranched distribution. + /// @dev Emits a {CreateMerkleLT} event. + /// + /// @param baseParams Struct encapsulating the {SablierV2MerkleLockup} parameters, which are documented in + /// {DataTypes}. + /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param tranchesWithPercentages The tranches with their respective unlock percentages. + /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. + /// @param recipientCount The total number of recipients who are eligible to claim. + /// @return merkleLT The address of the newly created MerkleLockup contract. + function createMerkleLT( + MerkleLockup.ConstructorParams memory baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierV2MerkleLT merkleLT); +} diff --git a/src/periphery/libraries/Errors.sol b/src/periphery/libraries/Errors.sol new file mode 100644 index 000000000..ecd1b2e17 --- /dev/null +++ b/src/periphery/libraries/Errors.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +/// @title Errors +/// @notice Library containing all custom errors the protocol may revert with. +library Errors { + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-BATCH-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + error SablierV2BatchLockup_BatchSizeZero(); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-MERKLE-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when trying to claim after the campaign has expired. + error SablierV2MerkleLockup_CampaignExpired(uint256 blockTimestamp, uint40 expiration); + + /// @notice Thrown when trying to create a campaign with a name that is too long. + error SablierV2MerkleLockup_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); + + /// @notice Thrown when trying to clawback when the current timestamp is over the grace period and the campaign has + /// not expired. + error SablierV2MerkleLockup_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); + + /// @notice Thrown when trying to claim with an invalid Merkle proof. + error SablierV2MerkleLockup_InvalidProof(); + + /// @notice Thrown when trying to claim the same stream more than once. + error SablierV2MerkleLockup_StreamClaimed(uint256 index); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-MERKLE-LT + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when trying to claim from an LT campaign with tranches' unlock percentages not adding up to 100%. + error SablierV2MerkleLT_TotalPercentageNotOneHundred(uint64 totalPercentage); +} diff --git a/src/periphery/types/DataTypes.sol b/src/periphery/types/DataTypes.sol new file mode 100644 index 000000000..bd1df1214 --- /dev/null +++ b/src/periphery/types/DataTypes.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { UD2x18 } from "@prb/math/src/UD2x18.sol"; + +import { Broker, LockupDynamic, LockupLinear, LockupTranched } from "../../core/types/DataTypes.sol"; + +library BatchLockup { + /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithDurations} except for the + /// asset. + struct CreateWithDurationsLD { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + LockupDynamic.SegmentWithDuration[] segments; + Broker broker; + } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithDurations} except for the + /// asset. + struct CreateWithDurationsLL { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + LockupLinear.Durations durations; + Broker broker; + } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithDurations} except for the + /// asset. + struct CreateWithDurationsLT { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + LockupTranched.TrancheWithDuration[] tranches; + Broker broker; + } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithTimestamps} except for the + /// asset. + struct CreateWithTimestampsLD { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + uint40 startTime; + LockupDynamic.Segment[] segments; + Broker broker; + } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithTimestamps} except for the + /// asset. + struct CreateWithTimestampsLL { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + LockupLinear.Timestamps timestamps; + Broker broker; + } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithTimestamps} except for the + /// asset. + struct CreateWithTimestampsLT { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + uint40 startTime; + LockupTranched.Tranche[] tranches; + Broker broker; + } +} + +library MerkleLockup { + /// @notice Struct encapsulating the base constructor parameters of a MerkleLockup campaign. + /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param cancelable Indicates if the stream will be cancelable after claiming. + /// @param expiration The expiration of the campaign, as a Unix timestamp. + /// @param initialAdmin The initial admin of the MerkleLockup campaign. + /// @param ipfsCID The content identifier for indexing the contract on IPFS. + /// @param merkleRoot The Merkle root of the claim data. + /// @param name The name of the campaign. + /// @param transferable Indicates if the stream will be transferable after claiming. + struct ConstructorParams { + IERC20 asset; + bool cancelable; + uint40 expiration; + address initialAdmin; + string ipfsCID; + bytes32 merkleRoot; + string name; + bool transferable; + } +} + +library MerkleLT { + /// @notice Struct encapsulating the unlock percentage and duration of a tranche. + /// @dev Since users may have different amounts allocated, this struct makes it possible to calculate the amounts + /// at claim time. An 18-decimal format is used to represent percentages: 100% = 1e18. For more information, see + /// the PRBMath documentation on UD2x18: https://github.com/PaulRBerg/prb-math + /// @param unlockPercentage The percentage designated to be unlocked in this tranche. + /// @param duration The time difference in seconds between this tranche and the previous one. + struct TrancheWithPercentage { + // slot 0 + UD2x18 unlockPercentage; + uint40 duration; + } +} From cd733fbf542732992ec31b7300da8deecfc37205 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Fri, 19 Jul 2024 15:09:26 +0300 Subject: [PATCH 04/34] test: add periphery tests Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- precompiles/Precompiles.sol | 88 +++- remappings.txt | 4 +- shell/update-precompiles.sh | 4 + test/{ => core}/Base.t.sol | 16 +- test/{ => core}/fork/Fork.t.sol | 0 test/{ => core}/fork/LockupDynamic.t.sol | 2 +- test/{ => core}/fork/LockupLinear.t.sol | 2 +- test/{ => core}/fork/LockupTranched.t.sol | 2 +- test/{ => core}/fork/NFTDescriptor.t.sol | 4 +- test/{ => core}/fork/assets/DAI.t.sol | 0 test/{ => core}/fork/assets/EURS.t.sol | 0 test/{ => core}/fork/assets/SHIB.t.sol | 0 test/{ => core}/fork/assets/USDC.t.sol | 0 test/{ => core}/fork/assets/USDT.t.sol | 0 test/{ => core}/integration/Integration.t.sol | 2 +- .../lockup-dynamic/LockupDynamic.t.sol | 2 +- .../concrete/lockup-dynamic/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 6 +- .../createWithDurations.tree | 0 .../createWithTimestamps.t.sol | 6 +- .../createWithTimestamps.tree | 0 .../get-segments/getSegments.t.sol | 4 +- .../get-segments/getSegments.tree | 0 .../lockup-dynamic/get-stream/getStream.t.sol | 4 +- .../lockup-dynamic/get-stream/getStream.tree | 0 .../get-timestamps/getTimestamps.t.sol | 4 +- .../get-timestamps/getTimestamps.tree | 0 .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.tree | 0 .../lockup-dynamic/token-uri/tokenURI.t.sol | 0 .../lockup-dynamic/token-uri/tokenURI.tree | 0 .../withdrawableAmountOf.t.sol | 0 .../withdrawableAmountOf.tree | 0 .../concrete/lockup-linear/LockupLinear.t.sol | 2 +- .../concrete/lockup-linear/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 6 +- .../createWithDurations.tree | 0 .../createWithTimestamps.t.sol | 6 +- .../createWithTimestamps.tree | 0 .../get-cliff-time/getCliffTime.t.sol | 2 +- .../get-cliff-time/getCliffTime.tree | 0 .../lockup-linear/get-stream/getStream.t.sol | 4 +- .../lockup-linear/get-stream/getStream.tree | 0 .../get-timestamps/getTimestamps.t.sol | 4 +- .../get-timestamps/getTimestamps.tree | 0 .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.tree | 0 .../lockup-linear/token-uri/tokenURI.t.sol | 0 .../lockup-linear/token-uri/tokenURI.tree | 0 .../withdrawableAmountOf.t.sol | 0 .../withdrawableAmountOf.tree | 0 .../lockup-tranched/LockupTranched.t.sol | 2 +- .../lockup-tranched/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 6 +- .../createWithDurations.tree | 0 .../createWithTimestamps.t.sol | 6 +- .../createWithTimestamps.tree | 0 .../get-stream/getStream.t.sol | 4 +- .../lockup-tranched/get-stream/getStream.tree | 0 .../get-timestamps/getTimestamps.t.sol | 4 +- .../get-timestamps/getTimestamps.tree | 0 .../get-tranches/getTranches.t.sol | 4 +- .../get-tranches/getTranches.tree | 0 .../streamed-amount-of/streamedAmountOf.t.sol | 0 .../streamed-amount-of/streamedAmountOf.tree | 0 .../lockup-tranched/token-uri/tokenURI.t.sol | 0 .../lockup-tranched/token-uri/tokenURI.tree | 0 .../withdrawableAmountOf.t.sol | 0 .../withdrawableAmountOf.tree | 0 .../lockup/allow-to-hook/allowToHook.t.sol | 2 +- .../lockup/allow-to-hook/allowToHook.tree | 0 .../concrete/lockup/burn/burn.t.sol | 4 +- .../concrete/lockup/burn/burn.tree | 0 .../cancel-multiple/cancelMultiple.t.sol | 6 +- .../cancel-multiple/cancelMultiple.tree | 0 .../concrete/lockup/cancel/cancel.t.sol | 8 +- .../concrete/lockup/cancel/cancel.tree | 0 .../concrete/lockup/get-asset/getAsset.t.sol | 2 +- .../concrete/lockup/get-asset/getAsset.tree | 0 .../getDepositedAmount.t.sol | 2 +- .../getDepositedAmount.tree | 0 .../lockup/get-end-time/getEndTime.t.sol | 2 +- .../lockup/get-end-time/getEndTime.tree | 0 .../lockup/get-recipient/getRecipient.t.sol | 0 .../lockup/get-recipient/getRecipient.tree | 0 .../getRefundedAmount.t.sol | 2 +- .../getRefundedAmount.tree | 0 .../lockup/get-sender/getSender.t.sol | 2 +- .../concrete/lockup/get-sender/getSender.tree | 0 .../lockup/get-start-time/getStartTime.t.sol | 2 +- .../lockup/get-start-time/getStartTime.tree | 0 .../getWithdrawnAmount.t.sol | 2 +- .../getWithdrawnAmount.tree | 0 .../is-allowed-to-hook/isAllowedToHook.t.sol | 0 .../is-allowed-to-hook/isAllowedToHook.tree | 0 .../lockup/is-cancelable/isCancelable.t.sol | 2 +- .../lockup/is-cancelable/isCancelable.tree | 0 .../concrete/lockup/is-cold/isCold.t.sol | 2 +- .../concrete/lockup/is-cold/isCold.tree | 0 .../lockup/is-depleted/isDepleted.t.sol | 2 +- .../lockup/is-depleted/isDepleted.tree | 0 .../concrete/lockup/is-stream/isStream.t.sol | 0 .../concrete/lockup/is-stream/isStream.tree | 0 .../is-transferable/isTransferable.t.sol | 2 +- .../is-transferable/isTransferable.tree | 0 .../concrete/lockup/is-warm/isWarm.t.sol | 2 +- .../concrete/lockup/is-warm/isWarm.tree | 0 .../refundableAmountOf.t.sol | 2 +- .../refundableAmountOf.tree | 0 .../concrete/lockup/renounce/renounce.t.sol | 4 +- .../concrete/lockup/renounce/renounce.tree | 0 .../set-nft-descriptor/setNFTDescriptor.t.sol | 6 +- .../set-nft-descriptor/setNFTDescriptor.tree | 0 .../concrete/lockup/status-of/statusOf.t.sol | 4 +- .../concrete/lockup/status-of/statusOf.tree | 0 .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.tree | 0 .../lockup/transfer-from/transferFrom.t.sol | 2 +- .../lockup/transfer-from/transferFrom.tree | 0 .../lockup/was-canceled/wasCanceled.t.sol | 2 +- .../lockup/was-canceled/wasCanceled.tree | 0 .../lockup/withdraw-hooks/withdrawHooks.t.sol | 2 +- .../lockup/withdraw-hooks/withdrawHooks.tree | 0 .../withdrawMaxAndTransfer.t.sol | 4 +- .../withdrawMaxAndTransfer.tree | 0 .../lockup/withdraw-max/withdrawMax.t.sol | 2 +- .../lockup/withdraw-max/withdrawMax.tree | 0 .../withdraw-multiple/withdrawMultiple.t.sol | 6 +- .../withdraw-multiple/withdrawMultiple.tree | 0 .../concrete/lockup/withdraw/withdraw.t.sol | 8 +- .../concrete/lockup/withdraw/withdraw.tree | 0 .../withdrawableAmountOf.t.sol | 2 +- .../withdrawableAmountOf.tree | 0 .../nft-descriptor/generateAccentColor.t.sol | 0 .../IsAllowedCharacter.t.sol | 0 .../IsAllowedCharacter.tree | 0 .../nft-descriptor/map-symbol/mapSymbol.t.sol | 2 +- .../nft-descriptor/map-symbol/mapSymbol.tree | 0 .../safeAssetDecimals.t.sol | 0 .../safeAssetDecimals.tree | 0 .../safe-asset-symbol/safeAssetSymbol.t.sol | 0 .../safe-asset-symbol/safeAssetSymbol.tree | 0 .../fuzz/lockup-dynamic/LockupDynamic.t.sol | 2 +- .../lockup-dynamic/createWithDurations.t.sol | 2 +- .../lockup-dynamic/createWithTimestamps.t.sol | 4 +- .../lockup-dynamic/streamedAmountOf.t.sol | 2 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 2 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 2 +- .../fuzz/lockup-linear/LockupLinear.t.sol | 2 +- .../lockup-linear/createWithDurations.t.sol | 4 +- .../lockup-linear/createWithTimestamps.t.sol | 4 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 2 +- .../lockup-linear/withdrawableAmountOf.t.sol | 2 +- .../fuzz/lockup-tranched/LockupTranched.t.sol | 2 +- .../lockup-tranched/createWithDurations.t.sol | 2 +- .../createWithTimestamps.t.sol | 4 +- .../lockup-tranched/streamedAmountOf.t.sol | 2 +- .../fuzz/lockup-tranched/withdraw.t.sol | 2 +- .../withdrawableAmountOf.t.sol | 2 +- .../integration/fuzz/lockup/cancel.t.sol | 2 +- .../fuzz/lockup/cancelMultiple.t.sol | 2 +- .../fuzz/lockup/getWithdrawnAmount.t.sol | 0 .../fuzz/lockup/refundableAmountOf.t.sol | 0 .../integration/fuzz/lockup/withdraw.t.sol | 2 +- .../integration/fuzz/lockup/withdrawMax.t.sol | 2 +- .../fuzz/lockup/withdrawMaxAndTransfer.t.sol | 0 .../fuzz/lockup/withdrawMultiple.t.sol | 2 +- .../nft-descriptor/isAllowedCharacter.t.sol | 0 .../shared/lockup-dynamic/LockupDynamic.t.sol | 2 +- .../shared/lockup-linear/LockupLinear.t.sol | 2 +- .../lockup-tranched/LockupTranched.t.sol | 2 +- .../integration/shared/lockup/Lockup.t.sol | 6 +- .../integration/shared/lockup/cancel.t.sol | 0 .../shared/lockup/cancelMultiple.t.sol | 0 .../shared/lockup/createWithDurations.t.sol | 0 .../shared/lockup/createWithTimestamps.t.sol | 0 .../shared/lockup/getWithdrawnAmount.t.sol | 0 .../shared/lockup/streamedAmountOf.t.sol | 0 .../integration/shared/lockup/withdraw.t.sol | 0 .../shared/lockup/withdrawMax.t.sol | 0 .../lockup/withdrawMaxAndTransfer.t.sol | 0 .../shared/lockup/withdrawMultiple.t.sol | 0 .../shared/lockup/withdrawableAmountOf.t.sol | 0 .../shared/nft-descriptor/NFTDescriptor.t.sol | 0 test/{ => core}/invariant/Invariant.t.sol | 0 test/{ => core}/invariant/Lockup.t.sol | 4 +- test/{ => core}/invariant/LockupDynamic.t.sol | 2 +- test/{ => core}/invariant/LockupLinear.t.sol | 2 +- .../{ => core}/invariant/LockupTranched.t.sol | 2 +- .../invariant/handlers/BaseHandler.sol | 0 .../handlers/LockupDynamicCreateHandler.sol | 4 +- .../handlers/LockupDynamicHandler.sol | 2 +- .../invariant/handlers/LockupHandler.sol | 4 +- .../handlers/LockupLinearCreateHandler.sol | 4 +- .../handlers/LockupLinearHandler.sol | 2 +- .../handlers/LockupTranchedCreateHandler.sol | 4 +- .../handlers/LockupTranchedHandler.sol | 2 +- .../invariant/stores/LockupStore.sol | 2 +- test/{ => core}/mocks/AdminableMock.sol | 4 +- test/{ => core}/mocks/Hooks.sol | 4 +- test/{ => core}/mocks/NFTDescriptorMock.sol | 8 +- test/{ => core}/mocks/Noop.sol | 0 test/{ => core}/mocks/erc20/ERC20Bytes32.sol | 0 .../mocks/erc20/ERC20MissingReturn.sol | 0 test/{ => core}/mocks/erc20/ERC20Mock.sol | 0 .../transfer-admin/transferAdmin.t.sol | 2 +- .../transfer-admin/transferAdmin.tree | 0 .../nft-descriptor/NFTDescriptor.t.sol | 2 +- .../nft-descriptor/abbreviateAmount.t.sol | 2 +- .../calculateDurationInDays.t.sol | 2 +- .../nft-descriptor/calculatePixelWidth.t.sol | 0 .../calculateStreamedPercentage.t.sol | 0 .../nft-descriptor/generateAttributes.t.sol | 0 .../nft-descriptor/generateDescription.t.sol | 0 .../nft-descriptor/generateName.t.sol | 0 .../concrete/nft-descriptor/generateSVG.t.sol | 4 +- .../concrete/nft-descriptor/hourglass.t.sol | 2 +- .../nft-descriptor/stringifyCardType.t.sol | 2 +- .../stringifyFractionalAmount.t.sol | 0 .../nft-descriptor/stringifyPercentage.t.sol | 0 .../nft-descriptor/stringifyStatus.t.sol | 2 +- test/{ => core}/unit/fuzz/transferAdmin.t.sol | 2 +- test/{ => core}/unit/shared/Adminable.t.sol | 0 test/{ => core}/utils/.npmignore | 0 test/{ => core}/utils/Assertions.sol | 2 +- test/{ => core}/utils/BaseScript.t.sol | 0 test/{ => core}/utils/Calculations.sol | 2 +- test/{ => core}/utils/Constants.sol | 0 test/{ => core}/utils/Defaults.sol | 2 +- test/{ => core}/utils/DeployOptimized.sol | 8 +- test/{ => core}/utils/Events.sol | 4 +- test/{ => core}/utils/Fuzzers.sol | 2 +- test/{ => core}/utils/Precompiles.t.sol | 8 +- test/{ => core}/utils/Types.sol | 0 test/{ => core}/utils/Utils.sol | 2 +- test/periphery/Base.t.sol | 397 +++++++++++++++ test/periphery/fork/Fork.t.sol | 85 ++++ test/periphery/fork/assets/USDC.t.sol | 29 ++ test/periphery/fork/assets/USDT.t.sol | 29 ++ .../batch-lockup/createWithTimestampsLD.t.sol | 82 +++ .../batch-lockup/createWithTimestampsLL.t.sol | 81 +++ .../batch-lockup/createWithTimestampsLT.t.sol | 82 +++ .../fork/merkle-lockup/MerkleLL.t.sol | 193 +++++++ .../fork/merkle-lockup/MerkleLT.t.sol | 195 ++++++++ test/periphery/integration/Integration.t.sol | 42 ++ .../createWithDurationsLD.t.sol | 49 ++ .../createWithDurationsLD.tree | 6 + .../createWithDurationsLL.t.sol | 49 ++ .../createWithDurationsLL.tree | 6 + .../createWithDurationsLT.t.sol | 49 ++ .../createWithDurationsLT.tree | 6 + .../createWithTimestampsLD.t.sol | 49 ++ .../createWithTimestampsLD.tree | 6 + .../createWithTimestamps.t.sol | 49 ++ .../createWithTimestamps.tree | 6 + .../createWithTimestampsLT.t.sol | 49 ++ .../createWithTimestampsLT.tree | 6 + .../merkle-lockup/MerkleLockup.t.sol | 123 +++++ .../create-merkle-ll/createMerkleLL.t.sol | 101 ++++ .../create-merkle-ll/createMerkleLL.tree | 9 + .../create-merkle-lt/createMerkleLT.t.sol | 92 ++++ .../create-merkle-lt/createMerkleLT.tree | 9 + .../isPercentagesSum100.t.sol | 60 +++ .../isPercentagesSum100.tree | 11 + .../merkle-lockup/ll/claim/claim.t.sol | 131 +++++ .../merkle-lockup/ll/claim/claim.tree | 20 + .../merkle-lockup/ll/clawback/clawback.t.sol | 85 ++++ .../merkle-lockup/ll/clawback/clawback.tree | 17 + .../ll/constructor/constructor.t.sol | 88 ++++ .../getFirstClaimTime.t.sol | 26 + .../getFirstClaimTime.tree | 5 + .../ll/has-claimed/hasClaimed.t.sol | 32 ++ .../ll/has-claimed/hasClaimed.tree | 8 + .../ll/has-expired/hasExpired.t.sol | 35 ++ .../ll/has-expired/hasExpired.tree | 10 + .../merkle-lockup/lt/claim/claim.t.sol | 281 +++++++++++ .../merkle-lockup/lt/claim/claim.tree | 33 ++ .../merkle-lockup/lt/clawback/clawback.t.sol | 84 ++++ .../merkle-lockup/lt/clawback/clawback.tree | 17 + .../lt/constructor/constructor.t.sol | 92 ++++ .../getFirstClaimTime.t.sol | 26 + .../getFirstClaimTime.tree | 5 + .../lt/has-claimed/hasClaimed.t.sol | 32 ++ .../lt/has-claimed/hasClaimed.tree | 8 + .../lt/has-expired/hasExpired.t.sol | 35 ++ .../lt/has-expired/hasExpired.tree | 10 + test/periphery/mocks/erc20/ERC20Mock.sol | 8 + test/periphery/utils/.npmignore | 1 + test/periphery/utils/ArrayBuilder.sol | 20 + test/periphery/utils/Assertions.sol | 35 ++ test/periphery/utils/BaseScript.t.sol | 23 + test/periphery/utils/BatchLockupBuilder.sol | 232 +++++++++ test/periphery/utils/Defaults.sol | 473 ++++++++++++++++++ test/periphery/utils/DeployOptimized.sol | 29 ++ test/periphery/utils/Events.sol | 33 ++ test/periphery/utils/MerkleBuilder.sol | 59 +++ test/periphery/utils/MerkleBuilder.t.sol | 46 ++ test/periphery/utils/Murky.sol | 223 +++++++++ test/periphery/utils/Precompiles.t.sol | 43 ++ test/periphery/utils/Types.sol | 14 + 300 files changed, 4539 insertions(+), 196 deletions(-) rename test/{ => core}/Base.t.sol (91%) rename test/{ => core}/fork/Fork.t.sol (100%) rename test/{ => core}/fork/LockupDynamic.t.sol (99%) rename test/{ => core}/fork/LockupLinear.t.sol (99%) rename test/{ => core}/fork/LockupTranched.t.sol (99%) rename test/{ => core}/fork/NFTDescriptor.t.sol (97%) rename test/{ => core}/fork/assets/DAI.t.sol (100%) rename test/{ => core}/fork/assets/EURS.t.sol (100%) rename test/{ => core}/fork/assets/SHIB.t.sol (100%) rename test/{ => core}/fork/assets/USDC.t.sol (100%) rename test/{ => core}/fork/assets/USDT.t.sol (100%) rename test/{ => core}/integration/Integration.t.sol (98%) rename test/{ => core}/integration/concrete/lockup-dynamic/LockupDynamic.t.sol (99%) rename test/{ => core}/integration/concrete/lockup-dynamic/constructor.t.sol (96%) rename test/{ => core}/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol (97%) rename test/{ => core}/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol (89%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-segments/getSegments.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol (93%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-stream/getStream.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol (89%) rename test/{ => core}/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol (98%) rename test/{ => core}/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/LockupLinear.t.sol (99%) rename test/{ => core}/integration/concrete/lockup-linear/constructor.t.sol (96%) rename test/{ => core}/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol (96%) rename test/{ => core}/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol (94%) rename test/{ => core}/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/get-stream/getStream.t.sol (93%) rename test/{ => core}/integration/concrete/lockup-linear/get-stream/getStream.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol (89%) rename test/{ => core}/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol (97%) rename test/{ => core}/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-linear/token-uri/tokenURI.tree (100%) rename test/{ => core}/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/LockupTranched.t.sol (99%) rename test/{ => core}/integration/concrete/lockup-tranched/constructor.t.sol (96%) rename test/{ => core}/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol (97%) rename test/{ => core}/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/get-stream/getStream.t.sol (93%) rename test/{ => core}/integration/concrete/lockup-tranched/get-stream/getStream.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol (89%) rename test/{ => core}/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol (89%) rename test/{ => core}/integration/concrete/lockup-tranched/get-tranches/getTranches.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-tranched/token-uri/tokenURI.tree (100%) rename test/{ => core}/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol (100%) rename test/{ => core}/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/allow-to-hook/allowToHook.tree (100%) rename test/{ => core}/integration/concrete/lockup/burn/burn.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/burn/burn.tree (100%) rename test/{ => core}/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree (100%) rename test/{ => core}/integration/concrete/lockup/cancel/cancel.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/cancel/cancel.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-asset/getAsset.t.sol (95%) rename test/{ => core}/integration/concrete/lockup/get-asset/getAsset.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol (95%) rename test/{ => core}/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-end-time/getEndTime.t.sol (95%) rename test/{ => core}/integration/concrete/lockup/get-end-time/getEndTime.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-recipient/getRecipient.t.sol (100%) rename test/{ => core}/integration/concrete/lockup/get-recipient/getRecipient.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-sender/getSender.t.sol (95%) rename test/{ => core}/integration/concrete/lockup/get-sender/getSender.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-start-time/getStartTime.t.sol (95%) rename test/{ => core}/integration/concrete/lockup/get-start-time/getStartTime.tree (100%) rename test/{ => core}/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol (100%) rename test/{ => core}/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-cancelable/isCancelable.t.sol (96%) rename test/{ => core}/integration/concrete/lockup/is-cancelable/isCancelable.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-cold/isCold.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/is-cold/isCold.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-depleted/isDepleted.t.sol (96%) rename test/{ => core}/integration/concrete/lockup/is-depleted/isDepleted.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-stream/isStream.t.sol (100%) rename test/{ => core}/integration/concrete/lockup/is-stream/isStream.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-transferable/isTransferable.t.sol (96%) rename test/{ => core}/integration/concrete/lockup/is-transferable/isTransferable.tree (100%) rename test/{ => core}/integration/concrete/lockup/is-warm/isWarm.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/is-warm/isWarm.tree (100%) rename test/{ => core}/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup/renounce/renounce.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/renounce/renounce.tree (100%) rename test/{ => core}/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol (92%) rename test/{ => core}/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree (100%) rename test/{ => core}/integration/concrete/lockup/status-of/statusOf.t.sol (96%) rename test/{ => core}/integration/concrete/lockup/status-of/statusOf.tree (100%) rename test/{ => core}/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree (100%) rename test/{ => core}/integration/concrete/lockup/transfer-from/transferFrom.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/transfer-from/transferFrom.tree (100%) rename test/{ => core}/integration/concrete/lockup/was-canceled/wasCanceled.t.sol (96%) rename test/{ => core}/integration/concrete/lockup/was-canceled/wasCanceled.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol (97%) rename test/{ => core}/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/withdraw-max/withdrawMax.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdraw/withdraw.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/withdraw/withdraw.tree (100%) rename test/{ => core}/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol (98%) rename test/{ => core}/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree (100%) rename test/{ => core}/integration/concrete/nft-descriptor/generateAccentColor.t.sol (100%) rename test/{ => core}/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol (100%) rename test/{ => core}/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree (100%) rename test/{ => core}/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol (97%) rename test/{ => core}/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree (100%) rename test/{ => core}/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol (100%) rename test/{ => core}/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree (100%) rename test/{ => core}/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol (100%) rename test/{ => core}/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree (100%) rename test/{ => core}/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-dynamic/createWithDurations.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol (99%) rename test/{ => core}/integration/fuzz/lockup-dynamic/withdraw.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-linear/LockupLinear.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-linear/createWithDurations.t.sol (97%) rename test/{ => core}/integration/fuzz/lockup-linear/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-linear/streamedAmountOf.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/LockupTranched.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/createWithDurations.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/withdraw.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup/cancel.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup/cancelMultiple.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup/getWithdrawnAmount.t.sol (100%) rename test/{ => core}/integration/fuzz/lockup/refundableAmountOf.t.sol (100%) rename test/{ => core}/integration/fuzz/lockup/withdraw.t.sol (99%) rename test/{ => core}/integration/fuzz/lockup/withdrawMax.t.sol (98%) rename test/{ => core}/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol (100%) rename test/{ => core}/integration/fuzz/lockup/withdrawMultiple.t.sol (98%) rename test/{ => core}/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol (100%) rename test/{ => core}/integration/shared/lockup-dynamic/LockupDynamic.t.sol (99%) rename test/{ => core}/integration/shared/lockup-linear/LockupLinear.t.sol (98%) rename test/{ => core}/integration/shared/lockup-tranched/LockupTranched.t.sol (99%) rename test/{ => core}/integration/shared/lockup/Lockup.t.sol (95%) rename test/{ => core}/integration/shared/lockup/cancel.t.sol (100%) rename test/{ => core}/integration/shared/lockup/cancelMultiple.t.sol (100%) rename test/{ => core}/integration/shared/lockup/createWithDurations.t.sol (100%) rename test/{ => core}/integration/shared/lockup/createWithTimestamps.t.sol (100%) rename test/{ => core}/integration/shared/lockup/getWithdrawnAmount.t.sol (100%) rename test/{ => core}/integration/shared/lockup/streamedAmountOf.t.sol (100%) rename test/{ => core}/integration/shared/lockup/withdraw.t.sol (100%) rename test/{ => core}/integration/shared/lockup/withdrawMax.t.sol (100%) rename test/{ => core}/integration/shared/lockup/withdrawMaxAndTransfer.t.sol (100%) rename test/{ => core}/integration/shared/lockup/withdrawMultiple.t.sol (100%) rename test/{ => core}/integration/shared/lockup/withdrawableAmountOf.t.sol (100%) rename test/{ => core}/integration/shared/nft-descriptor/NFTDescriptor.t.sol (100%) rename test/{ => core}/invariant/Invariant.t.sol (100%) rename test/{ => core}/invariant/Lockup.t.sol (99%) rename test/{ => core}/invariant/LockupDynamic.t.sol (98%) rename test/{ => core}/invariant/LockupLinear.t.sol (98%) rename test/{ => core}/invariant/LockupTranched.t.sol (98%) rename test/{ => core}/invariant/handlers/BaseHandler.sol (100%) rename test/{ => core}/invariant/handlers/LockupDynamicCreateHandler.sol (97%) rename test/{ => core}/invariant/handlers/LockupDynamicHandler.sol (89%) rename test/{ => core}/invariant/handlers/LockupHandler.sol (98%) rename test/{ => core}/invariant/handlers/LockupLinearCreateHandler.sol (97%) rename test/{ => core}/invariant/handlers/LockupLinearHandler.sol (89%) rename test/{ => core}/invariant/handlers/LockupTranchedCreateHandler.sol (97%) rename test/{ => core}/invariant/handlers/LockupTranchedHandler.sol (89%) rename test/{ => core}/invariant/stores/LockupStore.sol (97%) rename test/{ => core}/mocks/AdminableMock.sol (65%) rename test/{ => core}/mocks/Hooks.sol (96%) rename test/{ => core}/mocks/NFTDescriptorMock.sol (92%) rename test/{ => core}/mocks/Noop.sol (100%) rename test/{ => core}/mocks/erc20/ERC20Bytes32.sol (100%) rename test/{ => core}/mocks/erc20/ERC20MissingReturn.sol (100%) rename test/{ => core}/mocks/erc20/ERC20Mock.sol (100%) rename test/{ => core}/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol (97%) rename test/{ => core}/unit/concrete/adminable/transfer-admin/transferAdmin.tree (100%) rename test/{ => core}/unit/concrete/nft-descriptor/NFTDescriptor.t.sol (92%) rename test/{ => core}/unit/concrete/nft-descriptor/abbreviateAmount.t.sol (98%) rename test/{ => core}/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol (97%) rename test/{ => core}/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/generateAttributes.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/generateDescription.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/generateName.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/generateSVG.t.sol (99%) rename test/{ => core}/unit/concrete/nft-descriptor/hourglass.t.sol (96%) rename test/{ => core}/unit/concrete/nft-descriptor/stringifyCardType.t.sol (91%) rename test/{ => core}/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/stringifyPercentage.t.sol (100%) rename test/{ => core}/unit/concrete/nft-descriptor/stringifyStatus.t.sol (94%) rename test/{ => core}/unit/fuzz/transferAdmin.t.sol (96%) rename test/{ => core}/unit/shared/Adminable.t.sol (100%) rename test/{ => core}/utils/.npmignore (100%) rename test/{ => core}/utils/Assertions.sol (99%) rename test/{ => core}/utils/BaseScript.t.sol (100%) rename test/{ => core}/utils/Calculations.sol (98%) rename test/{ => core}/utils/Constants.sol (100%) rename test/{ => core}/utils/Defaults.sol (99%) rename test/{ => core}/utils/DeployOptimized.sol (88%) rename test/{ => core}/utils/Events.sol (96%) rename test/{ => core}/utils/Fuzzers.sol (99%) rename test/{ => core}/utils/Precompiles.t.sol (93%) rename test/{ => core}/utils/Types.sol (100%) rename test/{ => core}/utils/Utils.sol (97%) create mode 100644 test/periphery/Base.t.sol create mode 100644 test/periphery/fork/Fork.t.sol create mode 100644 test/periphery/fork/assets/USDC.t.sol create mode 100644 test/periphery/fork/assets/USDT.t.sol create mode 100644 test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol create mode 100644 test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol create mode 100644 test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol create mode 100644 test/periphery/fork/merkle-lockup/MerkleLL.t.sol create mode 100644 test/periphery/fork/merkle-lockup/MerkleLT.t.sol create mode 100644 test/periphery/integration/Integration.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.tree create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.tree create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.tree create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.tree create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.tree create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol create mode 100644 test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.tree create mode 100644 test/periphery/integration/merkle-lockup/MerkleLockup.t.sol create mode 100644 test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol create mode 100644 test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree create mode 100644 test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol create mode 100644 test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree create mode 100644 test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol create mode 100644 test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree create mode 100644 test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/claim/claim.tree create mode 100644 test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree create mode 100644 test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree create mode 100644 test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree create mode 100644 test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol create mode 100644 test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree create mode 100644 test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/claim/claim.tree create mode 100644 test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree create mode 100644 test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree create mode 100644 test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree create mode 100644 test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol create mode 100644 test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree create mode 100644 test/periphery/mocks/erc20/ERC20Mock.sol create mode 100644 test/periphery/utils/.npmignore create mode 100644 test/periphery/utils/ArrayBuilder.sol create mode 100644 test/periphery/utils/Assertions.sol create mode 100644 test/periphery/utils/BaseScript.t.sol create mode 100644 test/periphery/utils/BatchLockupBuilder.sol create mode 100644 test/periphery/utils/Defaults.sol create mode 100644 test/periphery/utils/DeployOptimized.sol create mode 100644 test/periphery/utils/Events.sol create mode 100644 test/periphery/utils/MerkleBuilder.sol create mode 100644 test/periphery/utils/MerkleBuilder.t.sol create mode 100644 test/periphery/utils/Murky.sol create mode 100644 test/periphery/utils/Precompiles.t.sol create mode 100644 test/periphery/utils/Types.sol diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index a2fea12b5..fa82c23d9 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -2,11 +2,14 @@ // solhint-disable max-line-length,no-inline-assembly,reason-string pragma solidity >=0.8.22; -import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "../src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; + +import { ISablierV2BatchLockup } from "../src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLockupFactory } from "../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; /// @notice This is useful for external integrations seeking to test against the exact deployed bytecode, as recompiling /// with via IR enabled would be time-consuming. @@ -22,7 +25,7 @@ contract Precompiles { uint256 public constant MAX_TRANCHE_COUNT = 500; /*////////////////////////////////////////////////////////////////////////// - BYTECODES + CORE //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_LOCKUP_DYNAMIC = @@ -34,10 +37,6 @@ contract Precompiles { bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615eaf908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a60646105438188066158b3565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906159b4565b60b76106ed5f615ca7565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615ca7565b98601b6028610a1a8c615db2565b610a2384615e2a565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615ca7565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615ca7565b9660b7610ac189615db2565b610aca8b615e2a565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615979565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615979565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615979565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615979565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bf8565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bf8565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c62565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c62565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b916158b3565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615889575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161585e575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615833575b8415615809575b508315615801575b5082156157f9575b5081156157f1575b50156157ea57600101615715565b5050505f90565b90505f6157dc565b91505f6157d4565b92505f6157cc565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6157c4565b7f7a0000000000000000000000000000000000000000000000000000000000000081111593506157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b806158c757506040516156cc602082614713565b600a81101561592d576158d990615408565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b81010301601f198101835282614713565b61593690615408565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b60405190615988604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615be8576159c2615979565b9061271003906127108211614b1157602e60619160506159e461482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a71815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615af882518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b59825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615c1b88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c5182518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c8588945180928580880191016146cd565b830164010714051160dd1b83820152615c5182518093856025850191016146cd565b6004811015614dc75780615cf15750604051615cc4604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d355750604051615d08604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d7757604051615d4a604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d85604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157ea5790600d915f925f925b828410615dd85750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e0c88856156ff565b511614615e22575b820194600101929190615dc5565b859450615e14565b5f90805180156157ea57906010915f925f925b828410615e50575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e8488856156ff565b511614615e9a575b820194600101929190615e3d565b859450615e8c56fea164736f6c634300081a000a"; - /*////////////////////////////////////////////////////////////////////////// - DEPLOYERS - //////////////////////////////////////////////////////////////////////////*/ - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode, passing a default value for the /// `maxSegmentCount` parameter. /// @dev Notes: @@ -197,4 +196,73 @@ contract Precompiles { lockupLinear = deployLockupLinear(initialAdmin); lockupTranched = deployLockupTranched(initialAdmin); } + + /*////////////////////////////////////////////////////////////////////////// + PERIPHERY + //////////////////////////////////////////////////////////////////////////*/ + + bytes public constant BYTECODE_BATCH_LOCKUP = + hex"60808060405234601557611e0a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd3146111a357806349a32c4014610e3e578063606ef87514610b025780639e743f29146107a6578063a514f83e1461040c5763f7ca34eb1461005b575f80fd5b3461033c5761006936611512565b91909282156103e4575f905f5b8481106103b057506001600160a01b036100939116918383611a7a565b61009c83611758565b926001600160a01b035f9316925b8181106100c357604051806100bf8782611587565b0390f35b6100ce818388611a17565b6100d7906117a7565b90826100e482828a611a17565b6020016100f0906117a7565b6100fb83838b611a17565b60400161010790611643565b9389610114858583611a17565b606001610120906117bb565b61012b868684611a17565b608001610137906117bb565b610142878785611a17565b60a00161014e90611a57565b918761015b818987611a17565b60c0810161016891611926565b98610174929196611a17565b60e0019360405195610185876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101ec9261197a565b9360e08601948552366101fe916118c8565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610353575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610312575b6001925061030b8288611901565b52016100aa565b506020823d8211610340575b8161032b602093836116ff565b8101031261033c57600191516102fd565b5f80fd5b3d915061031e565b6040513d5f823e3d90fd5b919493509160206060826103a1600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102be565b916001906fffffffffffffffffffffffffffffffff6103db60406103d5878a8c611a17565b01611643565b16019201610076565b7ff8bf106c000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c576104436115c0565b61044b6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610140870201011161033c5783156103e45790915f9190825b85811061077457506001600160a01b036104be9116928484611a7a565b6104c784611758565b926001600160a01b03165f5b8581106104e857604051806100bf8782611587565b6104fb6104f6828886611a69565b6117a7565b90610512602061050c838a88611a69565b016117a7565b878561052460406103d5868585611a69565b61053a6060610534878686611a69565b016117bb565b906101006105648761055d8188610557608061053484848d611a69565b98611a69565b968c611a69565b01906001600160a01b036040519861057b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c57604051956105fa876116e3565b61060660a08201611839565b875261061460c08201611839565b602088015260e00161062590611839565b604087015260c089019586523661063b916118c8565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff1661010484015251610124830161071291602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610348575f90610742575b6001925061073b8288611901565b52016104d3565b506020823d821161076c575b8161075b602093836116ff565b8101031261033c576001915161072d565b3d915061074e565b93926001906fffffffffffffffffffffffffffffffff61079a60406103d5898b89611a69565b160194019392936104a1565b3461033c576107b436611512565b91909282156103e4575f905f5b848110610ad457506001600160a01b036107de9116918383611a7a565b6107e783611758565b926001600160a01b035f9316925b81811061080a57604051806100bf8782611587565b610815818388611a17565b61081e906117a7565b908261082b82828a611a17565b602001610837906117a7565b61084283838b611a17565b60400161084e90611643565b938961085b858583611a17565b606001610867906117bb565b610872868684611a17565b60800161087e906117bb565b610889878785611a17565b60a00161089590611a57565b91876108a2818987611a17565b60c081016108af916117c8565b986108bb929196611a17565b60e00193604051956108cc876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906109339261184b565b9360e0860194855236610945916118c8565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610a8b575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610a59575b60019250610a528288611901565b52016107f5565b506020823d8211610a83575b81610a72602093836116ff565b8101031261033c5760019151610a44565b3d9150610a65565b91949350916020604082610ac5600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291610a05565b916001906fffffffffffffffffffffffffffffffff610af960406103d5878a8c611a17565b160192016107c1565b3461033c57610b1036611512565b91909282156103e4575f905f5b848110610e1057506001600160a01b03610b3a9116918383611a7a565b610b4383611758565b926001600160a01b035f9316925b818110610b6657604051806100bf8782611587565b610b718183886115d6565b610b7a906117a7565b9082610b8782828a6115d6565b602001610b93906117a7565b610b9e83838b6115d6565b604001610baa90611643565b9389610bb78585836115d6565b606001610bc3906117bb565b610bce8686846115d6565b608001610bda906117bb565b9086610be78188866115d6565b60a08101610bf491611926565b97610c009291956115d6565b60c0019260405194610c1186611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a0860193151584523690610c6a9261197a565b9260c0850193845236610c7c916118c8565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610db3575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90610d81575b60019250610d7a8288611901565b5201610b51565b506020823d8211610dab575b81610d9a602093836116ff565b8101031261033c5760019151610d6c565b3d9150610d8d565b91949350916020606082610e01600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610d2d565b916001906fffffffffffffffffffffffffffffffff610e3560406103d5878a8c6115d6565b16019201610b1d565b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c57610e756115c0565b610e7d6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610120870201011161033c5783156103e45790915f9190825b85811061117157506001600160a01b03610ef09116928484611a7a565b610ef984611758565b926001600160a01b03165f5b858110610f1a57604051806100bf8782611587565b610f286104f6828886611915565b90610f39602061050c838a88611915565b8785610f4b60406103d5868585611915565b610f5b6060610534878686611915565b9060e0610f8487610f7d8188610f77608061053484848d611915565b98611915565b968c611915565b01906001600160a01b0360405198610f9b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c576040519561101a876116aa565b61102660a08201611839565b875260c00161103490611839565b602087015260c089019586523661104a916118c8565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e484015251610104830161110f91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610348575f9061113f575b600192506111388288611901565b5201610f05565b506020823d8211611169575b81611158602093836116ff565b8101031261033c576001915161112a565b3d915061114b565b93926001906fffffffffffffffffffffffffffffffff61119760406103d5898b89611915565b16019401939293610ed3565b3461033c576111b136611512565b91909282156103e4575f905f5b84811061149d57506001600160a01b036111db9116918383611a7a565b6111e483611758565b926001600160a01b035f9316925b81811061120757604051806100bf8782611587565b6112128183886115d6565b61121b906117a7565b908261122882828a6115d6565b602001611234906117a7565b61123f83838b6115d6565b60400161124b90611643565b93896112588585836115d6565b606001611264906117bb565b61126f8686846115d6565b60800161127b906117bb565b90866112888188866115d6565b60a08101611295916117c8565b976112a19291956115d6565b60c00192604051946112b286611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a086019315158452369061130b9261184b565b9260c085019384523661131d916118c8565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611454575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90611422575b6001925061141b8288611901565b52016111f2565b506020823d821161144c575b8161143b602093836116ff565b8101031261033c576001915161140d565b3d915061142e565b9194935091602060408261148e600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b019501920186939492916113ce565b916001906fffffffffffffffffffffffffffffffff6114c260406103d5878a8c6115d6565b160192016111be565b602435906001600160a01b038216820361033c57565b9181601f8401121561033c5782359167ffffffffffffffff831161033c576020808501948460051b01011161033c57565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261033c576004356001600160a01b038116810361033c57916024356001600160a01b038116810361033c57916044359067ffffffffffffffff821161033c57611583916004016114e1565b9091565b60206040818301928281528451809452019201905f5b8181106115aa5750505090565b825184526020938401939092019160010161159d565b600435906001600160a01b038216820361033c57565b91908110156116165760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018136030182121561033c570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356fffffffffffffffffffffffffffffffff8116810361033c5790565b610100810190811067ffffffffffffffff82111761167d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761167d57604052565b610120810190811067ffffffffffffffff82111761167d57604052565b6060810190811067ffffffffffffffff82111761167d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761167d57604052565b67ffffffffffffffff811161167d5760051b60200190565b9061176282611740565b61176f60405191826116ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061179d8294611740565b0190602036910137565b356001600160a01b038116810361033c5790565b35801515810361033c5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c57602001918160061b3603831361033c57565b35906fffffffffffffffffffffffffffffffff8216820361033c57565b359064ffffffffff8216820361033c57565b92919261185782611740565b9361186560405195866116ff565b602085848152019260061b82019181831161033c57925b8284106118895750505050565b60408483031261033c57602060409182516118a3816116aa565b6118ac8761181c565b81526118b9838801611839565b8382015281520193019261187c565b919082604091031261033c576040516118e0816116aa565b809280356001600160a01b038116810361033c578252602090810135910152565b80518210156116165760209160051b010190565b919081101561161657610120020190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c5760200191606082023603831361033c57565b92919261198682611740565b9361199460405195866116ff565b606060208685815201930282019181831161033c57925b8284106119b85750505050565b60608483031261033c57604051906119cf826116e3565b6119d88561181c565b825260208501359067ffffffffffffffff8216820361033c5782602092836060950152611a0760408801611839565b60408201528152019301926119ab565b91908110156116165760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18136030182121561033c570190565b3564ffffffffff8116810361033c5790565b919081101561161657610140020190565b9190611acf6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015233602482015230604482015283606482015260648152611ac96084826116ff565b82611c8f565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103485784915f91611c42575b5010611b3b575b50505050565b5f806040519460208601907f095ea7b3000000000000000000000000000000000000000000000000000000008252876024880152604487015260448652611b836064876116ff565b85519082855af190611b93611d14565b82611c10575b5081611c05575b5015611bad575b80611b35565b611bf8611bfd93604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152611ac96064826116ff565b611c8f565b5f8080611ba7565b90503b15155f611ba0565b80519192508115918215611c28575b5050905f611b99565b611c3b9250602080918301019101611c77565b5f80611c1f565b9150506020813d602011611c6f575b81611c5e602093836116ff565b8101031261033c578390515f611b2e565b3d9150611c51565b9081602091031261033c5751801515810361033c5790565b5f806001600160a01b03611cb893169360208151910182865af1611cb1611d14565b9083611d71565b8051908115159182611cf9575b5050611cce5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611d0c9250602080918301019101611c77565b155f80611cc5565b3d15611d6c573d9067ffffffffffffffff821161167d5760405191611d6160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846116ff565b82523d5f602084013e565b606090565b90611dae5750805115611d8657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611df4575b611dbf575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611db756fea164736f6c634300081a000a"; + bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = + hex"608080604052346015576141d4908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e323876146105285780634d7c0f111461041e5763769bed201461003a575f80fd5b3461041a5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610089903690600401610a26565b6024359073ffffffffffffffffffffffffffffffffffffffff82169182810361041a5760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36011261041a57604051906100e382610972565b60443564ffffffffff8116810361041a57825260643564ffffffffff8116810361041a57602083015282519060208401511515836040860151926060870151608088015191604051806020810194602086526040820161014291610b48565b03601f1981018252610154908261098e565b60a08a01519360c08b015160405181819251908160208401916020019161017a92610b27565b81010380825261018d906020018261098e565b61019690610b6d565b9060e08c0151151592604051956020870198896101c59164ffffffffff60208092828151168552015116910152565b604087526101d460608861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161027c92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016102cb92610b27565b0160620103605501601f19810182526102e4908261098e565b51902060405161174880820182811067ffffffffffffffff8211176103ed578291610c9f83396080815261034160406103206080840189610bfe565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103e2576103a56103c7937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb89273ffffffffffffffffffffffffffffffffffffffff6020971695869560405194859460c0865260c0860190610bfe565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80fd5b3461041a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a573660238201121561041a5780600401359067ffffffffffffffff821161041a573660248360061b8301011161041a575f90815b838310156105095760248360061b830101359067ffffffffffffffff821680920361041a5767ffffffffffffffff160167ffffffffffffffff81116104dc57600190920191610492565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461041a5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610577903690600401610a26565b60243573ffffffffffffffffffffffffffffffffffffffff81169081810361041a576044359067ffffffffffffffff821161041a573660238301121561041a57816004013567ffffffffffffffff81116103ed57604051926105df60208360051b018561098e565b8184526024602085019260061b8201019036821161041a57602401915b818310610925575050505f9082515f905b8082106108cd5750508451906020860151151584604088015192606089015160808a015191604051806020810194602086526040820161064c91610b48565b03601f198101825261065e908261098e565b8b60a08101519460c082015160405181819251908160208401916020019161068592610b27565b810103808252610698906020018261098e565b6106a190610b6d565b9160e001511515926040519586602081019960208b52604082016106c491610bae565b03601f19810188526106d6908861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161077e92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016107cd92610b27565b0160620103605501601f19810182526107e6908261098e565b519020604051611de18082019082821067ffffffffffffffff8311176103ed578291610837916123e7843960608152610822606082018a610bfe565b90886020820152604081830391015286610bae565b03905ff580156103e2576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926108ac73ffffffffffffffffffffffffffffffffffffffff61089a941696879660405195869560c0875260c0870190610bfe565b918a8601528482036040860152610bae565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156108f85760019064ffffffffff6020808760051b890101510151160193019061060d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60408336031261041a576040519061093c82610972565b83359067ffffffffffffffff8216820361041a5782602092604094526109638387016109be565b838201528152019201916105fc565b6040810190811067ffffffffffffffff8211176103ed57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ed57604052565b3590811515820361041a57565b359064ffffffffff8216820361041a57565b81601f8201121561041a5780359067ffffffffffffffff82116103ed5760405192610a056020601f19601f860116018561098e565b8284526020838301011161041a57815f926020809301838601378301015290565b9190916101008184031261041a5760405190610100820182811067ffffffffffffffff8211176103ed576040528193813573ffffffffffffffffffffffffffffffffffffffff8116810361041a578352610a82602083016109b1565b6020840152610a93604083016109be565b6040840152606082013573ffffffffffffffffffffffffffffffffffffffff8116810361041a576060840152608082013567ffffffffffffffff811161041a5781610adf9184016109d0565b608084015260a082013560a084015260c08201359067ffffffffffffffff821161041a5782610b1760e09492610b22948694016109d0565b60c0860152016109b1565b910152565b5f5b838110610b385750505f910152565b8181015183820152602001610b29565b90601f19601f602093610b6681518092818752878088019101610b27565b0116010190565b602081519101519060208110610b81575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90602080835192838152019201905f5b818110610bcb5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610bbe565b9073ffffffffffffffffffffffffffffffffffffffff825116815260208201511515602082015264ffffffffff604083015116604082015273ffffffffffffffffffffffffffffffffffffffff606083015116606082015260e080610c93610c7760808601516101006080870152610100860190610b48565b60a086015160a086015260c086015185820360c0870152610b48565b93015115159101529056fe610160806040523461042857611748803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b60405161102490816107248239608051818181610481015281816106d60152610c20015260a0518181816107140152610b11015260c05181818161015f01528181610a6801528181610d8a0152610f49015260e0518181816102d3015261062201526101005181610e2801526101205181818161073e0152610ad50152610140518181816101af01526108870152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b63a52d539b60e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e12575080631686c90914610b3657806316c3549d14610afa5780631bfd681414610abe5780633bfe03a814610a905780633f31ae3f146104a55780634800d97f1461045557806349fc73dd1461031a5780634e390d3e146102f657806351e75e8b146102bc57806375829def146101ed57806390e64d13146101d35780639e93e57714610183578063bb4b573414610142578063ce516507146101025763f851a440146100cc575f80fd5b346100fe575f6003193601126100fe57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b346100fe5760206003193601126100fe57602061013860043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fe575f6003193601126100fe57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe576020610138610f41565b346100fe5760206003193601126100fe57610206610ec1565b5f5473ffffffffffffffffffffffffffffffffffffffff811633810361028d575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fe575f6003193601126100fe5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fe575f6003193601126100fe57602064ffffffffff60035416604051908152f35b346100fe575f6003193601126100fe576040515f6001548060011c9060018116801561044b575b60208310811461041e578285529081156103dc575060011461037e575b61037a8361036e81850382610f00565b60405191829182610e5b565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106103c25750909150810160200161036e61035e565b9192600181602092548385880101520191019092916103aa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b8401909101915061036e905061035e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610341565b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe5760806003193601126100fe5760043560243573ffffffffffffffffffffffffffffffffffffffff81168091036100fe57604435916fffffffffffffffffffffffffffffffff83168093036100fe576064359067ffffffffffffffff82116100fe57366023830112156100fe57816004013567ffffffffffffffff81116100fe578060051b92602484820101903682116100fe57604051602081019085825287604082015288606082015260608152610563608082610f00565b519020604051602081019182526020815261057f604082610f00565b5190209261058b610f41565b610a39576105b08560ff6001918060081c5f526002602052161b60405f205416151590565b610a0d576105c46020604051970187610f00565b8552602401602085015b8282106109fd57505050935f945b835186101561061e5760208660051b85010151908181105f1461060d575f52602052600160405f205b9501946105dc565b905f52602052600160405f20610605565b84907f0000000000000000000000000000000000000000000000000000000000000000036109d55760035464ffffffffff8116156109a1575b508260081c5f52600260205260405f20600160ff85161b815417905573ffffffffffffffffffffffffffffffffffffffff5f54169160405161069881610ee4565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176109745760405284526020840183815260408501838152606086017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f0000000000000000000000000000000000000000000000000000000000000000151584526040519461076e86610ee4565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b525173ffffffffffffffffffffffffffffffffffffffff1660048b01525173ffffffffffffffffffffffffffffffffffffffff1660248a0152516fffffffffffffffffffffffffffffffff1660448901525173ffffffffffffffffffffffffffffffffffffffff166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e485015251805173ffffffffffffffffffffffffffffffffffffffff166101048501526020015161012484015282807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165a925f61014492602095f1928315610969575f93610911575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610961575b8161092e60209383610f00565b810103126100fe5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6108d5565b3d9150610921565b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff161760035583610657565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016105ce565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100fe575f6003193601126100fe57604060045464ffffffffff825191818116835260281c166020820152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe5760406003193601126100fe57610b4f610ec1565b6024356fffffffffffffffffffffffffffffffff81168091036100fe5773ffffffffffffffffffffffffffffffffffffffff5f541633810361028d575064ffffffffff6003541680151580610dc4575b80610db5575b610d5b57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610c09606485610f00565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d4f573d67ffffffffffffffff811161097457610ca79160405191610c9760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f00565b82523d5f602084013e5b83610f7e565b8051908115159182610d2b575b5050610d0057507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fe57602001518015908115036100fe578480610cb4565b610ca790606090610ca1565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610dbe610f41565b15610ba5565b5062093a80810164ffffffffff8111610de55764ffffffffff164211610b9f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b346100fe575f6003193601126100fe5761037a907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036e604082610f00565b919091602081528251928360208301525f5b848110610eab5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201610e6d565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100fe57565b6040810190811067ffffffffffffffff82111761097457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761097457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f76575090565b905042101590565b90610fbb5750805115610f9357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061100e575b610fcc575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610fc456fea164736f6c634300081a000a610180806040523461044857611de1803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b60405161155e908161088382396080518181816105d10152818161095d0152611061015260a0518181816109870152610f52015260c0518181816102bb01528181610eac015281816111cb015261135d015260e05181818161042301526107b40152610100518161123c0152610120518181816109c20152610f160152610140518181816101390152610ac20152610160518181816102ff01526106980152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b63a52d539b60e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611226575080631686c90914610f7757806316c3549d14610f3b5780631bfd681414610eff5780633f31ae3f146105f55780634800d97f146105a557806349fc73dd1461046a5780634e390d3e1461044657806351e75e8b1461040c57806375829def1461033d57806390e64d1314610323578063936c63d9146102df578063bb4b57341461029e578063bf4ed03f1461019d578063ce5165071461015d578063da7924681461010d5763f851a440146100d7575f80fd5b34610109575f60031936011261010957602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461010957602060031936011261010957602061019360043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610109575f600319360112610109576004546101b981611392565b906101c76040519283611314565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610261578486604051918291602083019060208452518091526040830191905f5b81811061022b575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff16818601528695506040909401939092019160010161021d565b600160208192604051610273816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101f9565b34610109575f60031936011261010957602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f60031936011261010957602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f600319360112610109576020610193611355565b34610109576020600319360112610109576103566112d5565b5f5473ffffffffffffffffffffffffffffffffffffffff81163381036103dd575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610109575f6003193601126101095760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610109575f60031936011261010957602064ffffffffff60035416604051908152f35b34610109575f600319360112610109576040515f6001548060011c9060018116801561059b575b60208310811461056e5782855290811561052c57506001146104ce575b6104ca836104be81850382611314565b6040519182918261126f565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610512575090915081016020016104be6104ae565b9192600181602092548385880101520191019092916104fa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506104be90506104ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610491565b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109576080600319360112610109576004356024359073ffffffffffffffffffffffffffffffffffffffff821680920361010957604435916fffffffffffffffffffffffffffffffff831691828403610109576064359367ffffffffffffffff851161010957366023860112156101095784600401359467ffffffffffffffff86116101095760248660051b8201013681116101095767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ed457506040516020810190858252866040820152876060820152606081526106ee608082611314565b519020604051602081019182526020815261070a604082611314565b51902091610716611355565b610e7d5761073b8560ff6001918060081c5f526002602052161b60405f205416151590565b610e515761074888611392565b97610756604051998a611314565b8852602401602088015b828210610e4157505050925f935b86518510156107b05761078185886113aa565b51908181101561079f575f52602052600160405f205b94019361076e565b905f52602052600160405f20610797565b85907f000000000000000000000000000000000000000000000000000000000000000003610e195760035464ffffffffff811615610de5575b50600454926107f784611392565b936108056040519586611314565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610da857505050505f845161084b81611392565b956108596040519788611314565b8187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061088683611392565b015f5b818110610d855750505f905b828210610c7c5750506fffffffffffffffffffffffffffffffff8216848111610c4f578411610bfc575b5050508360081c5f52600260205260405f20600160ff86161b815417905573ffffffffffffffffffffffffffffffffffffffff5f541692604051610902816112f8565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610bcf5773ffffffffffffffffffffffffffffffffffffffff9660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526fffffffffffffffffffffffffffffffff60a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610b91575050508190602080945173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015203815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610b86575f93610b2e575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610b7e575b81610b4b60209383611314565b810103126101095792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af2565b3d9150610b3e565b6040513d5f823e3d90fd5b825180516fffffffffffffffffffffffffffffffff16855260209081015164ffffffffff168186015289955060409094019390920191600101610a71565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6fffffffffffffffffffffffffffffffff91610c3b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff849301886113aa565b5193031681835116011690528480806108bf565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b9092610c9d67ffffffffffffffff610c9486856113aa565b515116876113eb565b6fffffffffffffffffffffffffffffffff8111610d5a576fffffffffffffffffffffffffffffffff8091169164ffffffffff6020610cdb88876113aa565b5101511660405190610cec826112f8565b8482526020820152610cfe878c6113aa565b52610d09868b6113aa565b5016016fffffffffffffffffffffffffffffffff8111610d2d579260010190610895565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610d94816112f8565b5f81525f8382015282828c01015201610889565b600160208192604051610dba816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c1683820152815201920192019190610834565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff1617600355846107e9565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610760565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f4557880f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461010957604060031936011261010957610f906112d5565b6024356fffffffffffffffffffffffffffffffff81168091036101095773ffffffffffffffffffffffffffffffffffffffff5f54163381036103dd575064ffffffffff6003541680151580611205575b806111f6575b61119c57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb00000000000000000000000000000000000000000000000000000000875216948560248501528460448501526044845261104a606485611314565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15611190573d67ffffffffffffffff8111610bcf576110e891604051916110d860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611314565b82523d5f602084013e5b836114b8565b805190811515918261116c575b505061114157507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b819250906020918101031261010957602001518015908115036101095784806110f5565b6110e8906060906110e2565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506111ff611355565b15610fe6565b5062093a80810164ffffffffff8111610d2d5764ffffffffff164211610fe0565b34610109575f600319360112610109576104ca907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104be604082611314565b919091602081528251928360208301525f5b8481106112bf5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201611281565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361010957565b6040810190811067ffffffffffffffff821117610bcf57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bcf57604052565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161138a575090565b905042101590565b67ffffffffffffffff8111610bcf5760051b60200190565b80518210156113be5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146114a757670de0b6b3a7640000821015611477577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906114f557508051156114cd57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611548575b611506575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156114fe56fea164736f6c634300081a000aa164736f6c634300081a000a"; + + /// @notice Deploys {SablierV2BatchLockup} from precompiled bytecode. + function deployBatchLockup() public returns (ISablierV2BatchLockup batchLockup) { + bytes memory creationBytecode = BYTECODE_BATCH_LOCKUP; + assembly { + batchLockup := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require( + address(batchLockup) != address(0), "Sablier V2 Precompiles: deployment failed for BatchLockup contract" + ); + } + + /// @notice Deploys {SablierV2MerkleLockupFactory} from precompiled bytecode. + function deployMerkleLockupFactory() public returns (ISablierV2MerkleLockupFactory factory) { + bytes memory creationBytecode = BYTECODE_MERKLE_LOCKUP_FACTORY; + assembly { + factory := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) + } + require( + address(factory) != address(0), "Sablier V2 Precompiles: deployment failed for MerkleLockupFactory contract" + ); + } + + /// @notice Deploys all V2 Periphery contracts in the following order: + /// + /// 1. {SablierV2BatchLockup} + /// 2. {SablierV2MerkleLockupFactory} + function deployPeriphery() + public + returns (ISablierV2BatchLockup batchLockup, ISablierV2MerkleLockupFactory merkleLockupFactory) + { + batchLockup = deployBatchLockup(); + merkleLockupFactory = deployMerkleLockupFactory(); + } + + /// @notice Deploys the entire Sablier V2 Protocol from precompiled bytecode. + /// + /// 1. {SablierV2NFTDescriptor} + /// 2. {SablierV2LockupDynamic} + /// 3. {SablierV2LockupLinear} + /// 4. {SablierV2LockupTranched} + /// 5. {SablierV2BatchLockup} + /// 6. {SablierV2MerkleLockupFactory} + function deployProtocol(address initialAdmin) + public + returns ( + ISablierV2LockupDynamic lockupDynamic, + ISablierV2LockupLinear lockupLinear, + ISablierV2LockupTranched lockupTranched, + ISablierV2NFTDescriptor nftDescriptor, + ISablierV2BatchLockup batchLockup, + ISablierV2MerkleLockupFactory merkleLockupFactory + ) + { + // Deploy V2 Core. + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = deployCore(initialAdmin); + + // Deploy V2 Periphery. + (batchLockup, merkleLockupFactory) = deployPeriphery(); + } } diff --git a/remappings.txt b/remappings.txt index 8f1a7a740..b384a1744 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,5 +1,7 @@ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @prb/math/=node_modules/@prb/math/ +core/=src/core/ forge-std/=node_modules/forge-std/ +periphery/=src/periphery/ solady/=node_modules/solady/ -solarray/=node_modules/solarray/ +solarray/=node_modules/solarray/ \ No newline at end of file diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index 008db274a..a50926ead 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -12,9 +12,11 @@ set -euo pipefail FOUNDRY_PROFILE=optimized forge build # Retrieve the raw bytecodes, removing the "0x" prefix +batch_lockup=$(cat out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json | jq -r '.bytecode.object' | cut -c 3-) lockup_dynamic=$(cat out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) +merkle_lockup_factory=$(cat out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json | jq -r '.bytecode.object' | cut -c 3-) nft_descriptor=$(cat out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) precompiles_path="precompiles/Precompiles.sol" @@ -24,9 +26,11 @@ if [ ! -f $precompiles_path ]; then fi # Replace the current bytecodes +sd "(BYTECODE_BATCH_LOCKUP =)[^;]+;" "\$1 hex\"$batch_lockup\";" $precompiles_path sd "(BYTECODE_LOCKUP_DYNAMIC =)[^;]+;" "\$1 hex\"$lockup_dynamic\";" $precompiles_path sd "(BYTECODE_LOCKUP_LINEAR =)[^;]+;" "\$1 hex\"$lockup_linear\";" $precompiles_path sd "(BYTECODE_LOCKUP_TRANCHED =)[^;]+;" "\$1 hex\"$lockup_tranched\";" $precompiles_path +sd "(BYTECODE_MERKLE_LOCKUP_FACTORY =)[^;]+;" "\$1 hex\"$merkle_lockup_factory\";" $precompiles_path sd "(BYTECODE_NFT_DESCRIPTOR =)[^;]+;" "\$1 hex\"$nft_descriptor\";" $precompiles_path # Reformat the code with Forge diff --git a/test/Base.t.sol b/test/core/Base.t.sol similarity index 91% rename from test/Base.t.sol rename to test/core/Base.t.sol index f11fc8ca3..4e22a7d83 100644 --- a/test/Base.t.sol +++ b/test/core/Base.t.sol @@ -3,14 +3,14 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/SablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; diff --git a/test/fork/Fork.t.sol b/test/core/fork/Fork.t.sol similarity index 100% rename from test/fork/Fork.t.sol rename to test/core/fork/Fork.t.sol diff --git a/test/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol similarity index 99% rename from test/fork/LockupDynamic.t.sol rename to test/core/fork/LockupDynamic.t.sol index eab25f210..d325a520b 100644 --- a/test/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol similarity index 99% rename from test/fork/LockupLinear.t.sol rename to test/core/fork/LockupLinear.t.sol index f10fde71c..5fb558779 100644 --- a/test/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -5,7 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol similarity index 99% rename from test/fork/LockupTranched.t.sol rename to test/core/fork/LockupTranched.t.sol index e07a0c7e2..9d2d637c0 100644 --- a/test/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/fork/NFTDescriptor.t.sol b/test/core/fork/NFTDescriptor.t.sol similarity index 97% rename from test/fork/NFTDescriptor.t.sol rename to test/core/fork/NFTDescriptor.t.sol index 89912d632..c0c5dd374 100644 --- a/test/fork/NFTDescriptor.t.sol +++ b/test/core/fork/NFTDescriptor.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/fork/assets/DAI.t.sol b/test/core/fork/assets/DAI.t.sol similarity index 100% rename from test/fork/assets/DAI.t.sol rename to test/core/fork/assets/DAI.t.sol diff --git a/test/fork/assets/EURS.t.sol b/test/core/fork/assets/EURS.t.sol similarity index 100% rename from test/fork/assets/EURS.t.sol rename to test/core/fork/assets/EURS.t.sol diff --git a/test/fork/assets/SHIB.t.sol b/test/core/fork/assets/SHIB.t.sol similarity index 100% rename from test/fork/assets/SHIB.t.sol rename to test/core/fork/assets/SHIB.t.sol diff --git a/test/fork/assets/USDC.t.sol b/test/core/fork/assets/USDC.t.sol similarity index 100% rename from test/fork/assets/USDC.t.sol rename to test/core/fork/assets/USDC.t.sol diff --git a/test/fork/assets/USDT.t.sol b/test/core/fork/assets/USDT.t.sol similarity index 100% rename from test/fork/assets/USDT.t.sol rename to test/core/fork/assets/USDT.t.sol diff --git a/test/integration/Integration.t.sol b/test/core/integration/Integration.t.sol similarity index 98% rename from test/integration/Integration.t.sol rename to test/core/integration/Integration.t.sol index 316657fef..873211cd5 100644 --- a/test/integration/Integration.t.sol +++ b/test/core/integration/Integration.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Base_Test } from "../Base.t.sol"; import { diff --git a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol similarity index 99% rename from test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol rename to test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index cca53bda0..7adc4ccb2 100644 --- a/test/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/constructor.t.sol b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol similarity index 96% rename from test/integration/concrete/lockup-dynamic/constructor.t.sol rename to test/core/integration/concrete/lockup-dynamic/constructor.t.sol index 89bb8c07f..3f9742355 100644 --- a/test/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupDynamic } from "src/SablierV2LockupDynamic.sol"; +import { SablierV2LockupDynamic } from "core/SablierV2LockupDynamic.sol"; import { LockupDynamic_Integration_Concrete_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol similarity index 97% rename from test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 4edb555f3..3fe80fedd 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol similarity index 98% rename from test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index c804413cf..069a2b8a1 100644 --- a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -7,9 +7,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree diff --git a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol similarity index 89% rename from test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol rename to test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol index b94535d00..47026fad5 100644 --- a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupDynamic } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/get-segments/getSegments.tree rename to test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree diff --git a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol similarity index 93% rename from test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol rename to test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol index c079a3a0e..68b77c6bf 100644 --- a/test/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupDynamic } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-stream/getStream.tree b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/get-stream/getStream.tree rename to test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree diff --git a/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol similarity index 89% rename from test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol rename to test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol index 889c0cf50..1f3f1df3b 100644 --- a/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupDynamic } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree rename to test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree diff --git a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol similarity index 98% rename from test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol rename to test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol index 8682ce12b..dd9affc2f 100644 --- a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupDynamic } from "src/types/DataTypes.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; diff --git a/test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree rename to test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree diff --git a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol similarity index 100% rename from test/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol rename to test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol diff --git a/test/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree rename to test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree diff --git a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol similarity index 100% rename from test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol rename to test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol diff --git a/test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree rename to test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree diff --git a/test/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol similarity index 99% rename from test/integration/concrete/lockup-linear/LockupLinear.t.sol rename to test/core/integration/concrete/lockup-linear/LockupLinear.t.sol index 5f6a3b246..895121535 100644 --- a/test/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup-linear/constructor.t.sol b/test/core/integration/concrete/lockup-linear/constructor.t.sol similarity index 96% rename from test/integration/concrete/lockup-linear/constructor.t.sol rename to test/core/integration/concrete/lockup-linear/constructor.t.sol index 323f5fb60..eec4dcad9 100644 --- a/test/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/core/integration/concrete/lockup-linear/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupLinear } from "src/SablierV2LockupLinear.sol"; +import { SablierV2LockupLinear } from "core/SablierV2LockupLinear.sol"; import { LockupLinear_Integration_Concrete_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol similarity index 96% rename from test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 38fd9daae..e7e0139de 100644 --- a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree similarity index 100% rename from test/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol similarity index 98% rename from test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 5ce293a85..a4a409680 100644 --- a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -6,9 +6,9 @@ import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093 import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree diff --git a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol similarity index 94% rename from test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol rename to test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol index 3207a55f2..ee13ca50e 100644 --- a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree similarity index 100% rename from test/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree rename to test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol similarity index 93% rename from test/integration/concrete/lockup-linear/get-stream/getStream.t.sol rename to test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol index 6c4b0a5fb..62e1034ad 100644 --- a/test/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupLinear } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupLinear } from "core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/get-stream/getStream.tree b/test/core/integration/concrete/lockup-linear/get-stream/getStream.tree similarity index 100% rename from test/integration/concrete/lockup-linear/get-stream/getStream.tree rename to test/core/integration/concrete/lockup-linear/get-stream/getStream.tree diff --git a/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol similarity index 89% rename from test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol rename to test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol index a0de39a5e..26f400997 100644 --- a/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupLinear } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupLinear } from "core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree rename to test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol similarity index 97% rename from test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol rename to test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index beda0bc05..69d3eff06 100644 --- a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "src/types/DataTypes.sol"; +import { LockupLinear } from "core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; diff --git a/test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree rename to test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol similarity index 100% rename from test/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol rename to test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol diff --git a/test/integration/concrete/lockup-linear/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree similarity index 100% rename from test/integration/concrete/lockup-linear/token-uri/tokenURI.tree rename to test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree diff --git a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol similarity index 100% rename from test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol rename to test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol diff --git a/test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree rename to test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree diff --git a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol similarity index 99% rename from test/integration/concrete/lockup-tranched/LockupTranched.t.sol rename to test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol index b19b02ffc..463c8d176 100644 --- a/test/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/constructor.t.sol b/test/core/integration/concrete/lockup-tranched/constructor.t.sol similarity index 96% rename from test/integration/concrete/lockup-tranched/constructor.t.sol rename to test/core/integration/concrete/lockup-tranched/constructor.t.sol index 5bf824fb5..668ac7883 100644 --- a/test/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/core/integration/concrete/lockup-tranched/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupTranched } from "src/SablierV2LockupTranched.sol"; +import { SablierV2LockupTranched } from "core/SablierV2LockupTranched.sol"; import { LockupTranched_Integration_Concrete_Test } from "./LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol similarity index 97% rename from test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 9db841bb2..f5c990fd5 100644 --- a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol similarity index 98% rename from test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index cb1ce9a56..2e10b625b 100644 --- a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -7,9 +7,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol similarity index 93% rename from test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol rename to test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol index 3c9870943..18eea60ed 100644 --- a/test/integration/concrete/lockup-tranched/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupTranched } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupTranched } from "core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/get-stream/getStream.tree b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/get-stream/getStream.tree rename to test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree diff --git a/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol similarity index 89% rename from test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol rename to test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol index 3205fd3ed..246d9d138 100644 --- a/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupTranched } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupTranched } from "core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree rename to test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree diff --git a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol similarity index 89% rename from test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol rename to test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol index eaad2a69b..999b7572c 100644 --- a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { LockupTranched } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { LockupTranched } from "core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/get-tranches/getTranches.tree rename to test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree diff --git a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol similarity index 100% rename from test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol rename to test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol diff --git a/test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree rename to test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol similarity index 100% rename from test/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol rename to test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol diff --git a/test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/token-uri/tokenURI.tree rename to test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree diff --git a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol similarity index 100% rename from test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol rename to test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol diff --git a/test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree rename to test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree diff --git a/test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol similarity index 98% rename from test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol rename to test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol index c30daca79..fe3277531 100644 --- a/test/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol +++ b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/allow-to-hook/allowToHook.tree b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.tree similarity index 100% rename from test/integration/concrete/lockup/allow-to-hook/allowToHook.tree rename to test/core/integration/concrete/lockup/allow-to-hook/allowToHook.tree diff --git a/test/integration/concrete/lockup/burn/burn.t.sol b/test/core/integration/concrete/lockup/burn/burn.t.sol similarity index 98% rename from test/integration/concrete/lockup/burn/burn.t.sol rename to test/core/integration/concrete/lockup/burn/burn.t.sol index f16ffa248..3b088a575 100644 --- a/test/integration/concrete/lockup/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup/burn/burn.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/burn/burn.tree b/test/core/integration/concrete/lockup/burn/burn.tree similarity index 100% rename from test/integration/concrete/lockup/burn/burn.tree rename to test/core/integration/concrete/lockup/burn/burn.tree diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol similarity index 98% rename from test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol rename to test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index e0f601a1d..4d4070fb9 100644 --- a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; import { CancelMultiple_Integration_Shared_Test } from "../../../shared/lockup/cancelMultiple.t.sol"; diff --git a/test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree similarity index 100% rename from test/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree rename to test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree diff --git a/test/integration/concrete/lockup/cancel/cancel.t.sol b/test/core/integration/concrete/lockup/cancel/cancel.t.sol similarity index 97% rename from test/integration/concrete/lockup/cancel/cancel.t.sol rename to test/core/integration/concrete/lockup/cancel/cancel.t.sol index cca169686..d9ceab13d 100644 --- a/test/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup/cancel/cancel.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Cancel_Integration_Shared_Test } from "../../../shared/lockup/cancel.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/cancel/cancel.tree b/test/core/integration/concrete/lockup/cancel/cancel.tree similarity index 100% rename from test/integration/concrete/lockup/cancel/cancel.tree rename to test/core/integration/concrete/lockup/cancel/cancel.tree diff --git a/test/integration/concrete/lockup/get-asset/getAsset.t.sol b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol similarity index 95% rename from test/integration/concrete/lockup/get-asset/getAsset.t.sol rename to test/core/integration/concrete/lockup/get-asset/getAsset.t.sol index 082560891..493415714 100644 --- a/test/integration/concrete/lockup/get-asset/getAsset.t.sol +++ b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-asset/getAsset.tree b/test/core/integration/concrete/lockup/get-asset/getAsset.tree similarity index 100% rename from test/integration/concrete/lockup/get-asset/getAsset.tree rename to test/core/integration/concrete/lockup/get-asset/getAsset.tree diff --git a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol similarity index 95% rename from test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol rename to test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol index e418e69db..4bca8251c 100644 --- a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree similarity index 100% rename from test/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree rename to test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree diff --git a/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol similarity index 95% rename from test/integration/concrete/lockup/get-end-time/getEndTime.t.sol rename to test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol index ed3575642..7667d95e2 100644 --- a/test/integration/concrete/lockup/get-end-time/getEndTime.t.sol +++ b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-end-time/getEndTime.tree b/test/core/integration/concrete/lockup/get-end-time/getEndTime.tree similarity index 100% rename from test/integration/concrete/lockup/get-end-time/getEndTime.tree rename to test/core/integration/concrete/lockup/get-end-time/getEndTime.tree diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol similarity index 100% rename from test/integration/concrete/lockup/get-recipient/getRecipient.t.sol rename to test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol diff --git a/test/integration/concrete/lockup/get-recipient/getRecipient.tree b/test/core/integration/concrete/lockup/get-recipient/getRecipient.tree similarity index 100% rename from test/integration/concrete/lockup/get-recipient/getRecipient.tree rename to test/core/integration/concrete/lockup/get-recipient/getRecipient.tree diff --git a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol similarity index 98% rename from test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol rename to test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index c35abea37..1b023fe19 100644 --- a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree similarity index 100% rename from test/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree rename to test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree diff --git a/test/integration/concrete/lockup/get-sender/getSender.t.sol b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol similarity index 95% rename from test/integration/concrete/lockup/get-sender/getSender.t.sol rename to test/core/integration/concrete/lockup/get-sender/getSender.t.sol index 713c4f1eb..f38bf95bc 100644 --- a/test/integration/concrete/lockup/get-sender/getSender.t.sol +++ b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-sender/getSender.tree b/test/core/integration/concrete/lockup/get-sender/getSender.tree similarity index 100% rename from test/integration/concrete/lockup/get-sender/getSender.tree rename to test/core/integration/concrete/lockup/get-sender/getSender.tree diff --git a/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol similarity index 95% rename from test/integration/concrete/lockup/get-start-time/getStartTime.t.sol rename to test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol index e31b8d734..ebb36a2cc 100644 --- a/test/integration/concrete/lockup/get-start-time/getStartTime.t.sol +++ b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-start-time/getStartTime.tree b/test/core/integration/concrete/lockup/get-start-time/getStartTime.tree similarity index 100% rename from test/integration/concrete/lockup/get-start-time/getStartTime.tree rename to test/core/integration/concrete/lockup/get-start-time/getStartTime.tree diff --git a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol similarity index 97% rename from test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol rename to test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index d7cc37828..8a577c704 100644 --- a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { GetWithdrawnAmount_Integration_Shared_Test } from "../../../shared/lockup/getWithdrawnAmount.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree similarity index 100% rename from test/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree rename to test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree diff --git a/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol b/test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol similarity index 100% rename from test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol rename to test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol diff --git a/test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree b/test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree similarity index 100% rename from test/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree rename to test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree diff --git a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol similarity index 96% rename from test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol rename to test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol index 5f0bf9c48..746d469d1 100644 --- a/test/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-cancelable/isCancelable.tree b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.tree similarity index 100% rename from test/integration/concrete/lockup/is-cancelable/isCancelable.tree rename to test/core/integration/concrete/lockup/is-cancelable/isCancelable.tree diff --git a/test/integration/concrete/lockup/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol similarity index 97% rename from test/integration/concrete/lockup/is-cold/isCold.t.sol rename to test/core/integration/concrete/lockup/is-cold/isCold.t.sol index ebb99badb..9d7c5e4dd 100644 --- a/test/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-cold/isCold.tree b/test/core/integration/concrete/lockup/is-cold/isCold.tree similarity index 100% rename from test/integration/concrete/lockup/is-cold/isCold.tree rename to test/core/integration/concrete/lockup/is-cold/isCold.tree diff --git a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol similarity index 96% rename from test/integration/concrete/lockup/is-depleted/isDepleted.t.sol rename to test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 0ba5d78c6..2ebf0d1b0 100644 --- a/test/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-depleted/isDepleted.tree b/test/core/integration/concrete/lockup/is-depleted/isDepleted.tree similarity index 100% rename from test/integration/concrete/lockup/is-depleted/isDepleted.tree rename to test/core/integration/concrete/lockup/is-depleted/isDepleted.tree diff --git a/test/integration/concrete/lockup/is-stream/isStream.t.sol b/test/core/integration/concrete/lockup/is-stream/isStream.t.sol similarity index 100% rename from test/integration/concrete/lockup/is-stream/isStream.t.sol rename to test/core/integration/concrete/lockup/is-stream/isStream.t.sol diff --git a/test/integration/concrete/lockup/is-stream/isStream.tree b/test/core/integration/concrete/lockup/is-stream/isStream.tree similarity index 100% rename from test/integration/concrete/lockup/is-stream/isStream.tree rename to test/core/integration/concrete/lockup/is-stream/isStream.tree diff --git a/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol similarity index 96% rename from test/integration/concrete/lockup/is-transferable/isTransferable.t.sol rename to test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol index e32d1f0f9..edd6344f5 100644 --- a/test/integration/concrete/lockup/is-transferable/isTransferable.t.sol +++ b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-transferable/isTransferable.tree b/test/core/integration/concrete/lockup/is-transferable/isTransferable.tree similarity index 100% rename from test/integration/concrete/lockup/is-transferable/isTransferable.tree rename to test/core/integration/concrete/lockup/is-transferable/isTransferable.tree diff --git a/test/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol similarity index 97% rename from test/integration/concrete/lockup/is-warm/isWarm.t.sol rename to test/core/integration/concrete/lockup/is-warm/isWarm.t.sol index e784adc4c..cf7576c4c 100644 --- a/test/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/is-warm/isWarm.tree b/test/core/integration/concrete/lockup/is-warm/isWarm.tree similarity index 100% rename from test/integration/concrete/lockup/is-warm/isWarm.tree rename to test/core/integration/concrete/lockup/is-warm/isWarm.tree diff --git a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol similarity index 98% rename from test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol rename to test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index 698e03894..402d8e97e 100644 --- a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree rename to test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree diff --git a/test/integration/concrete/lockup/renounce/renounce.t.sol b/test/core/integration/concrete/lockup/renounce/renounce.t.sol similarity index 97% rename from test/integration/concrete/lockup/renounce/renounce.t.sol rename to test/core/integration/concrete/lockup/renounce/renounce.t.sol index b6b91fed1..024cb3d71 100644 --- a/test/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup/renounce/renounce.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/renounce/renounce.tree b/test/core/integration/concrete/lockup/renounce/renounce.tree similarity index 100% rename from test/integration/concrete/lockup/renounce/renounce.tree rename to test/core/integration/concrete/lockup/renounce/renounce.tree diff --git a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol similarity index 92% rename from test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol rename to test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol index 2b1c52cf6..d15459774 100644 --- a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { SablierV2NFTDescriptor } from "src/SablierV2NFTDescriptor.sol"; +import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree similarity index 100% rename from test/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree rename to test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree diff --git a/test/integration/concrete/lockup/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol similarity index 96% rename from test/integration/concrete/lockup/status-of/statusOf.t.sol rename to test/core/integration/concrete/lockup/status-of/statusOf.t.sol index 43b275e39..f24d64701 100644 --- a/test/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/status-of/statusOf.tree b/test/core/integration/concrete/lockup/status-of/statusOf.tree similarity index 100% rename from test/integration/concrete/lockup/status-of/statusOf.tree rename to test/core/integration/concrete/lockup/status-of/statusOf.tree diff --git a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol similarity index 98% rename from test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol rename to test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index acf7d0f17..b431e8afe 100644 --- a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../../shared/lockup/streamedAmountOf.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree rename to test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree diff --git a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol similarity index 97% rename from test/integration/concrete/lockup/transfer-from/transferFrom.t.sol rename to test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 31987fd0d..699aa0573 100644 --- a/test/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/transfer-from/transferFrom.tree b/test/core/integration/concrete/lockup/transfer-from/transferFrom.tree similarity index 100% rename from test/integration/concrete/lockup/transfer-from/transferFrom.tree rename to test/core/integration/concrete/lockup/transfer-from/transferFrom.tree diff --git a/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol similarity index 96% rename from test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol rename to test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol index fb532ea8b..6d4abfd1d 100644 --- a/test/integration/concrete/lockup/was-canceled/wasCanceled.t.sol +++ b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/was-canceled/wasCanceled.tree b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.tree similarity index 100% rename from test/integration/concrete/lockup/was-canceled/wasCanceled.tree rename to test/core/integration/concrete/lockup/was-canceled/wasCanceled.tree diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol similarity index 98% rename from test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol rename to test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol index a89bc2c07..6f31b4a3d 100644 --- a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; +import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; import { Integration_Test } from "../../../Integration.t.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; diff --git a/test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree similarity index 100% rename from test/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree rename to test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol similarity index 97% rename from test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol rename to test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 98f62a5b4..27f0179a7 100644 --- a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { WithdrawMaxAndTransfer_Integration_Shared_Test } from "../../../shared/lockup/withdrawMaxAndTransfer.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree similarity index 100% rename from test/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree rename to test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol similarity index 98% rename from test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol rename to test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index e0f6eab91..4f730f28c 100644 --- a/test/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { WithdrawMax_Integration_Shared_Test } from "../../../shared/lockup/withdrawMax.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/withdraw-max/withdrawMax.tree b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.tree similarity index 100% rename from test/integration/concrete/lockup/withdraw-max/withdrawMax.tree rename to test/core/integration/concrete/lockup/withdraw-max/withdrawMax.tree diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol similarity index 98% rename from test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol rename to test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index fdc0347de..0ceff35f7 100644 --- a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { WithdrawMultiple_Integration_Shared_Test } from "../../../shared/lockup/withdrawMultiple.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree similarity index 100% rename from test/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree rename to test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree diff --git a/test/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol similarity index 98% rename from test/integration/concrete/lockup/withdraw/withdraw.t.sol rename to test/core/integration/concrete/lockup/withdraw/withdraw.t.sol index 66815be10..4acd47016 100644 --- a/test/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "src/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "core/libraries/Errors.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/withdraw/withdraw.tree b/test/core/integration/concrete/lockup/withdraw/withdraw.tree similarity index 100% rename from test/integration/concrete/lockup/withdraw/withdraw.tree rename to test/core/integration/concrete/lockup/withdraw/withdraw.tree diff --git a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol similarity index 98% rename from test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol rename to test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index 7677fd2b2..3b426e740 100644 --- a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../../shared/lockup/withdrawableAmountOf.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree similarity index 100% rename from test/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree rename to test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree diff --git a/test/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol similarity index 100% rename from test/integration/concrete/nft-descriptor/generateAccentColor.t.sol rename to test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol diff --git a/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol b/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol similarity index 100% rename from test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol rename to test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol diff --git a/test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree b/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree similarity index 100% rename from test/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree rename to test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.tree diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol similarity index 97% rename from test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol rename to test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index e023c8e6b..1c4cda800 100644 --- a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import { MockERC721 } from "forge-std/src/mocks/MockERC721.sol"; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; diff --git a/test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree similarity index 100% rename from test/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree rename to test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree diff --git a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol similarity index 100% rename from test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol rename to test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol diff --git a/test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree b/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree similarity index 100% rename from test/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree rename to test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.tree diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol similarity index 100% rename from test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol rename to test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol diff --git a/test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree b/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree similarity index 100% rename from test/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree rename to test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.tree diff --git a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol similarity index 98% rename from test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol rename to test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index b699733fc..e9ad097f4 100644 --- a/test/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol similarity index 98% rename from test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 4bf6242b4..748c86951 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol similarity index 98% rename from test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 6b55b5d07..be9cf8c4e 100644 --- a/test/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol similarity index 99% rename from test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol rename to test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 0e1cc38ee..903c2a1de 100644 --- a/test/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic } from "src/types/DataTypes.sol"; +import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol similarity index 98% rename from test/integration/fuzz/lockup-dynamic/withdraw.t.sol rename to test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index 10d3fc893..ad9fe96b9 100644 --- a/test/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; diff --git a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol similarity index 98% rename from test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol rename to test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 27751e524..75e072380 100644 --- a/test/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic } from "src/types/DataTypes.sol"; +import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; diff --git a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol similarity index 98% rename from test/integration/fuzz/lockup-linear/LockupLinear.t.sol rename to test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol index 0d47251ed..4fd89a475 100644 --- a/test/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol similarity index 97% rename from test/integration/fuzz/lockup-linear/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol index 9fa96dd32..99110ea36 100644 --- a/test/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; -import { Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol similarity index 98% rename from test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index d59318ec1..ed21c874c 100644 --- a/test/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol similarity index 98% rename from test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol rename to test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 16fc0b538..dfbebb5f7 100644 --- a/test/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupLinear } from "src/types/DataTypes.sol"; +import { Broker, LockupLinear } from "core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; diff --git a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol similarity index 98% rename from test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol rename to test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 7bb8d459b..bd2215173 100644 --- a/test/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupLinear } from "src/types/DataTypes.sol"; +import { Broker, LockupLinear } from "core/types/DataTypes.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/LockupTranched.t.sol rename to test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol index a07b20380..2d382dc05 100644 --- a/test/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 10bb043d1..0e4c32ad5 100644 --- a/test/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 31d7a2122..93b378073 100644 --- a/test/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { Errors } from "src/libraries/Errors.sol"; -import { Broker, Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { Errors } from "core/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol rename to test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 29c105b53..c098248b7 100644 --- a/test/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "src/types/DataTypes.sol"; +import { Broker, LockupTranched } from "core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/withdraw.t.sol rename to test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 7a73f5df6..0e365247b 100644 --- a/test/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; diff --git a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol similarity index 98% rename from test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol rename to test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 407414ba6..c29fbfded 100644 --- a/test/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "src/types/DataTypes.sol"; +import { Broker, LockupTranched } from "core/types/DataTypes.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; diff --git a/test/integration/fuzz/lockup/cancel.t.sol b/test/core/integration/fuzz/lockup/cancel.t.sol similarity index 98% rename from test/integration/fuzz/lockup/cancel.t.sol rename to test/core/integration/fuzz/lockup/cancel.t.sol index 532e47b6d..dd3bfbac3 100644 --- a/test/integration/fuzz/lockup/cancel.t.sol +++ b/test/core/integration/fuzz/lockup/cancel.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Cancel_Integration_Shared_Test } from "../../shared/lockup/cancel.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/cancelMultiple.t.sol b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol similarity index 98% rename from test/integration/fuzz/lockup/cancelMultiple.t.sol rename to test/core/integration/fuzz/lockup/cancelMultiple.t.sol index eac94ed5c..e48874d9c 100644 --- a/test/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; import { CancelMultiple_Integration_Shared_Test } from "../../shared/lockup/cancelMultiple.t.sol"; diff --git a/test/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol similarity index 100% rename from test/integration/fuzz/lockup/getWithdrawnAmount.t.sol rename to test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol diff --git a/test/integration/fuzz/lockup/refundableAmountOf.t.sol b/test/core/integration/fuzz/lockup/refundableAmountOf.t.sol similarity index 100% rename from test/integration/fuzz/lockup/refundableAmountOf.t.sol rename to test/core/integration/fuzz/lockup/refundableAmountOf.t.sol diff --git a/test/integration/fuzz/lockup/withdraw.t.sol b/test/core/integration/fuzz/lockup/withdraw.t.sol similarity index 99% rename from test/integration/fuzz/lockup/withdraw.t.sol rename to test/core/integration/fuzz/lockup/withdraw.t.sol index a5b6d5618..3f2936013 100644 --- a/test/integration/fuzz/lockup/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Withdraw_Integration_Shared_Test } from "../../shared/lockup/withdraw.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/withdrawMax.t.sol b/test/core/integration/fuzz/lockup/withdrawMax.t.sol similarity index 98% rename from test/integration/fuzz/lockup/withdrawMax.t.sol rename to test/core/integration/fuzz/lockup/withdrawMax.t.sol index b15c2fb4a..b65902e2c 100644 --- a/test/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { WithdrawMax_Integration_Shared_Test } from "../../shared/lockup/withdrawMax.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol similarity index 100% rename from test/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol rename to test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol diff --git a/test/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol similarity index 98% rename from test/integration/fuzz/lockup/withdrawMultiple.t.sol rename to test/core/integration/fuzz/lockup/withdrawMultiple.t.sol index fae6c0e43..f26f14bb5 100644 --- a/test/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { WithdrawMultiple_Integration_Shared_Test } from "../../shared/lockup/withdrawMultiple.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol b/test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol similarity index 100% rename from test/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol rename to test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol diff --git a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol similarity index 99% rename from test/integration/shared/lockup-dynamic/LockupDynamic.t.sol rename to test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 941620ada..f8e0d9cc4 100644 --- a/test/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupDynamic } from "src/types/DataTypes.sol"; +import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; diff --git a/test/integration/shared/lockup-linear/LockupLinear.t.sol b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol similarity index 98% rename from test/integration/shared/lockup-linear/LockupLinear.t.sol rename to test/core/integration/shared/lockup-linear/LockupLinear.t.sol index c7344ac45..ea7972452 100644 --- a/test/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupLinear } from "src/types/DataTypes.sol"; +import { Broker, LockupLinear } from "core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; diff --git a/test/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol similarity index 99% rename from test/integration/shared/lockup-tranched/LockupTranched.t.sol rename to test/core/integration/shared/lockup-tranched/LockupTranched.t.sol index 97a39415f..b89a1d766 100644 --- a/test/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupTranched } from "src/types/DataTypes.sol"; +import { Broker, LockupTranched } from "core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; diff --git a/test/integration/shared/lockup/Lockup.t.sol b/test/core/integration/shared/lockup/Lockup.t.sol similarity index 95% rename from test/integration/shared/lockup/Lockup.t.sol rename to test/core/integration/shared/lockup/Lockup.t.sol index b7da0ea18..52bedf3f9 100644 --- a/test/integration/shared/lockup/Lockup.t.sol +++ b/test/core/integration/shared/lockup/Lockup.t.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Broker } from "src/types/DataTypes.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Broker } from "core/types/DataTypes.sol"; -import { Base_Test } from "test/Base.t.sol"; +import { Base_Test } from "test/core/Base.t.sol"; /// @dev This contracts avoids duplicating test logic for {SablierV2LockupLinear} and {SablierV2LockupDynamic}; /// both of these contracts inherit from {SablierV2Lockup}. diff --git a/test/integration/shared/lockup/cancel.t.sol b/test/core/integration/shared/lockup/cancel.t.sol similarity index 100% rename from test/integration/shared/lockup/cancel.t.sol rename to test/core/integration/shared/lockup/cancel.t.sol diff --git a/test/integration/shared/lockup/cancelMultiple.t.sol b/test/core/integration/shared/lockup/cancelMultiple.t.sol similarity index 100% rename from test/integration/shared/lockup/cancelMultiple.t.sol rename to test/core/integration/shared/lockup/cancelMultiple.t.sol diff --git a/test/integration/shared/lockup/createWithDurations.t.sol b/test/core/integration/shared/lockup/createWithDurations.t.sol similarity index 100% rename from test/integration/shared/lockup/createWithDurations.t.sol rename to test/core/integration/shared/lockup/createWithDurations.t.sol diff --git a/test/integration/shared/lockup/createWithTimestamps.t.sol b/test/core/integration/shared/lockup/createWithTimestamps.t.sol similarity index 100% rename from test/integration/shared/lockup/createWithTimestamps.t.sol rename to test/core/integration/shared/lockup/createWithTimestamps.t.sol diff --git a/test/integration/shared/lockup/getWithdrawnAmount.t.sol b/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol similarity index 100% rename from test/integration/shared/lockup/getWithdrawnAmount.t.sol rename to test/core/integration/shared/lockup/getWithdrawnAmount.t.sol diff --git a/test/integration/shared/lockup/streamedAmountOf.t.sol b/test/core/integration/shared/lockup/streamedAmountOf.t.sol similarity index 100% rename from test/integration/shared/lockup/streamedAmountOf.t.sol rename to test/core/integration/shared/lockup/streamedAmountOf.t.sol diff --git a/test/integration/shared/lockup/withdraw.t.sol b/test/core/integration/shared/lockup/withdraw.t.sol similarity index 100% rename from test/integration/shared/lockup/withdraw.t.sol rename to test/core/integration/shared/lockup/withdraw.t.sol diff --git a/test/integration/shared/lockup/withdrawMax.t.sol b/test/core/integration/shared/lockup/withdrawMax.t.sol similarity index 100% rename from test/integration/shared/lockup/withdrawMax.t.sol rename to test/core/integration/shared/lockup/withdrawMax.t.sol diff --git a/test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol similarity index 100% rename from test/integration/shared/lockup/withdrawMaxAndTransfer.t.sol rename to test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol diff --git a/test/integration/shared/lockup/withdrawMultiple.t.sol b/test/core/integration/shared/lockup/withdrawMultiple.t.sol similarity index 100% rename from test/integration/shared/lockup/withdrawMultiple.t.sol rename to test/core/integration/shared/lockup/withdrawMultiple.t.sol diff --git a/test/integration/shared/lockup/withdrawableAmountOf.t.sol b/test/core/integration/shared/lockup/withdrawableAmountOf.t.sol similarity index 100% rename from test/integration/shared/lockup/withdrawableAmountOf.t.sol rename to test/core/integration/shared/lockup/withdrawableAmountOf.t.sol diff --git a/test/integration/shared/nft-descriptor/NFTDescriptor.t.sol b/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol similarity index 100% rename from test/integration/shared/nft-descriptor/NFTDescriptor.t.sol rename to test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol diff --git a/test/invariant/Invariant.t.sol b/test/core/invariant/Invariant.t.sol similarity index 100% rename from test/invariant/Invariant.t.sol rename to test/core/invariant/Invariant.t.sol diff --git a/test/invariant/Lockup.t.sol b/test/core/invariant/Lockup.t.sol similarity index 99% rename from test/invariant/Lockup.t.sol rename to test/core/invariant/Lockup.t.sol index bccc95c92..494b4087e 100644 --- a/test/invariant/Lockup.t.sol +++ b/test/core/invariant/Lockup.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Invariant_Test } from "./Invariant.t.sol"; import { LockupHandler } from "./handlers/LockupHandler.sol"; diff --git a/test/invariant/LockupDynamic.t.sol b/test/core/invariant/LockupDynamic.t.sol similarity index 98% rename from test/invariant/LockupDynamic.t.sol rename to test/core/invariant/LockupDynamic.t.sol index 60c7d2989..0f26354db 100644 --- a/test/invariant/LockupDynamic.t.sol +++ b/test/core/invariant/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "src/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupDynamicCreateHandler } from "./handlers/LockupDynamicCreateHandler.sol"; diff --git a/test/invariant/LockupLinear.t.sol b/test/core/invariant/LockupLinear.t.sol similarity index 98% rename from test/invariant/LockupLinear.t.sol rename to test/core/invariant/LockupLinear.t.sol index d1060ef50..edc236569 100644 --- a/test/invariant/LockupLinear.t.sol +++ b/test/core/invariant/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupLinearHandler } from "./handlers/LockupLinearHandler.sol"; diff --git a/test/invariant/LockupTranched.t.sol b/test/core/invariant/LockupTranched.t.sol similarity index 98% rename from test/invariant/LockupTranched.t.sol rename to test/core/invariant/LockupTranched.t.sol index f60414f99..ed1ab2b7f 100644 --- a/test/invariant/LockupTranched.t.sol +++ b/test/core/invariant/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "src/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupTranchedCreateHandler } from "./handlers/LockupTranchedCreateHandler.sol"; diff --git a/test/invariant/handlers/BaseHandler.sol b/test/core/invariant/handlers/BaseHandler.sol similarity index 100% rename from test/invariant/handlers/BaseHandler.sol rename to test/core/invariant/handlers/BaseHandler.sol diff --git a/test/invariant/handlers/LockupDynamicCreateHandler.sol b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol similarity index 97% rename from test/invariant/handlers/LockupDynamicCreateHandler.sol rename to test/core/invariant/handlers/LockupDynamicCreateHandler.sol index 02f39c2ac..ff40a6a7b 100644 --- a/test/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { LockupDynamic } from "src/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/invariant/handlers/LockupDynamicHandler.sol b/test/core/invariant/handlers/LockupDynamicHandler.sol similarity index 89% rename from test/invariant/handlers/LockupDynamicHandler.sol rename to test/core/invariant/handlers/LockupDynamicHandler.sol index 34bbf0a4e..19fb1c660 100644 --- a/test/invariant/handlers/LockupDynamicHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/invariant/handlers/LockupHandler.sol b/test/core/invariant/handlers/LockupHandler.sol similarity index 98% rename from test/invariant/handlers/LockupHandler.sol rename to test/core/invariant/handlers/LockupHandler.sol index 5637bd7a5..42b899a61 100644 --- a/test/invariant/handlers/LockupHandler.sol +++ b/test/core/invariant/handlers/LockupHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "src/interfaces/ISablierV2Lockup.sol"; -import { Lockup } from "src/types/DataTypes.sol"; +import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/invariant/handlers/LockupLinearCreateHandler.sol b/test/core/invariant/handlers/LockupLinearCreateHandler.sol similarity index 97% rename from test/invariant/handlers/LockupLinearCreateHandler.sol rename to test/core/invariant/handlers/LockupLinearCreateHandler.sol index fce35e868..1d7330ec6 100644 --- a/test/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/core/invariant/handlers/LockupLinearCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; -import { LockupLinear } from "src/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { LockupLinear } from "core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/invariant/handlers/LockupLinearHandler.sol b/test/core/invariant/handlers/LockupLinearHandler.sol similarity index 89% rename from test/invariant/handlers/LockupLinearHandler.sol rename to test/core/invariant/handlers/LockupLinearHandler.sol index 9e2451660..9c3499bfb 100644 --- a/test/invariant/handlers/LockupLinearHandler.sol +++ b/test/core/invariant/handlers/LockupLinearHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/invariant/handlers/LockupTranchedCreateHandler.sol b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol similarity index 97% rename from test/invariant/handlers/LockupTranchedCreateHandler.sol rename to test/core/invariant/handlers/LockupTranchedCreateHandler.sol index f4de81f15..011cb99aa 100644 --- a/test/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; -import { LockupTranched } from "src/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupTranched } from "core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/invariant/handlers/LockupTranchedHandler.sol b/test/core/invariant/handlers/LockupTranchedHandler.sol similarity index 89% rename from test/invariant/handlers/LockupTranchedHandler.sol rename to test/core/invariant/handlers/LockupTranchedHandler.sol index 25ec40b98..6b7b098f3 100644 --- a/test/invariant/handlers/LockupTranchedHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/invariant/stores/LockupStore.sol b/test/core/invariant/stores/LockupStore.sol similarity index 97% rename from test/invariant/stores/LockupStore.sol rename to test/core/invariant/stores/LockupStore.sol index 0314ac96a..eeff3d3e1 100644 --- a/test/invariant/stores/LockupStore.sol +++ b/test/core/invariant/stores/LockupStore.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; /// @dev Storage variables needed by all lockup handlers. contract LockupStore { diff --git a/test/mocks/AdminableMock.sol b/test/core/mocks/AdminableMock.sol similarity index 65% rename from test/mocks/AdminableMock.sol rename to test/core/mocks/AdminableMock.sol index 0ea10b4b6..70c7633be 100644 --- a/test/mocks/AdminableMock.sol +++ b/test/core/mocks/AdminableMock.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { Adminable } from "../../src/abstracts/Adminable.sol"; -import { IAdminable } from "../../src/interfaces/IAdminable.sol"; +import { Adminable } from "../../../src/core/abstracts/Adminable.sol"; +import { IAdminable } from "../../../src/core/interfaces/IAdminable.sol"; contract AdminableMock is Adminable { constructor(address initialAdmin) { diff --git a/test/mocks/Hooks.sol b/test/core/mocks/Hooks.sol similarity index 96% rename from test/mocks/Hooks.sol rename to test/core/mocks/Hooks.sol index 99d3a7c00..9f9a89917 100644 --- a/test/mocks/Hooks.sol +++ b/test/core/mocks/Hooks.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22; import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import { ISablierLockupRecipient } from "../../src/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "../../src/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockupRecipient } from "../../../src/core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "../../../src/core/interfaces/ISablierV2Lockup.sol"; contract RecipientGood is ISablierLockupRecipient, ERC165 { function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { diff --git a/test/mocks/NFTDescriptorMock.sol b/test/core/mocks/NFTDescriptorMock.sol similarity index 92% rename from test/mocks/NFTDescriptorMock.sol rename to test/core/mocks/NFTDescriptorMock.sol index f0315e156..7b9b6c8c7 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/core/mocks/NFTDescriptorMock.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { NFTSVG } from "../../src/libraries/NFTSVG.sol"; -import { SVGElements } from "../../src/libraries/SVGElements.sol"; -import { Lockup } from "../../src/types/DataTypes.sol"; -import { SablierV2NFTDescriptor } from "../../src/SablierV2NFTDescriptor.sol"; +import { NFTSVG } from "../../../src/core/libraries/NFTSVG.sol"; +import { SVGElements } from "../../../src/core/libraries/SVGElements.sol"; +import { Lockup } from "../../../src/core/types/DataTypes.sol"; +import { SablierV2NFTDescriptor } from "../../../src/core/SablierV2NFTDescriptor.sol"; /// @dev This mock is needed for: /// - Running the tests against the `--via-ir` precompiles diff --git a/test/mocks/Noop.sol b/test/core/mocks/Noop.sol similarity index 100% rename from test/mocks/Noop.sol rename to test/core/mocks/Noop.sol diff --git a/test/mocks/erc20/ERC20Bytes32.sol b/test/core/mocks/erc20/ERC20Bytes32.sol similarity index 100% rename from test/mocks/erc20/ERC20Bytes32.sol rename to test/core/mocks/erc20/ERC20Bytes32.sol diff --git a/test/mocks/erc20/ERC20MissingReturn.sol b/test/core/mocks/erc20/ERC20MissingReturn.sol similarity index 100% rename from test/mocks/erc20/ERC20MissingReturn.sol rename to test/core/mocks/erc20/ERC20MissingReturn.sol diff --git a/test/mocks/erc20/ERC20Mock.sol b/test/core/mocks/erc20/ERC20Mock.sol similarity index 100% rename from test/mocks/erc20/ERC20Mock.sol rename to test/core/mocks/erc20/ERC20Mock.sol diff --git a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol b/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol similarity index 97% rename from test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol rename to test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol index 253915466..f8e66d503 100644 --- a/test/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol +++ b/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Adminable_Unit_Shared_Test } from "../../../shared/Adminable.t.sol"; diff --git a/test/unit/concrete/adminable/transfer-admin/transferAdmin.tree b/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.tree similarity index 100% rename from test/unit/concrete/adminable/transfer-admin/transferAdmin.tree rename to test/core/unit/concrete/adminable/transfer-admin/transferAdmin.tree diff --git a/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol similarity index 92% rename from test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol rename to test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol index f2c26b5ee..fd0481713 100644 --- a/test/unit/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "src/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; import { NFTDescriptorMock } from "../../../mocks/NFTDescriptorMock.sol"; import { Base_Test } from "../../../Base.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol similarity index 98% rename from test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol rename to test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol index 369c95d25..f6fb17bc3 100644 --- a/test/unit/concrete/nft-descriptor/abbreviateAmount.t.sol +++ b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "src/libraries/SVGElements.sol"; +import { SVGElements } from "core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol similarity index 97% rename from test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol rename to test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol index 62cae342b..e121c5563 100644 --- a/test/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol +++ b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "src/libraries/SVGElements.sol"; +import { SVGElements } from "core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol b/test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol rename to test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol diff --git a/test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol b/test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol rename to test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol diff --git a/test/unit/concrete/nft-descriptor/generateAttributes.t.sol b/test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/generateAttributes.t.sol rename to test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol diff --git a/test/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/generateDescription.t.sol rename to test/core/unit/concrete/nft-descriptor/generateDescription.t.sol diff --git a/test/unit/concrete/nft-descriptor/generateName.t.sol b/test/core/unit/concrete/nft-descriptor/generateName.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/generateName.t.sol rename to test/core/unit/concrete/nft-descriptor/generateName.t.sol diff --git a/test/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol similarity index 99% rename from test/unit/concrete/nft-descriptor/generateSVG.t.sol rename to test/core/unit/concrete/nft-descriptor/generateSVG.t.sol index 290a4c802..ae2c4f7f9 100644 --- a/test/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -2,8 +2,8 @@ // solhint-disable max-line-length pragma solidity >=0.8.22 <0.9.0; -import { NFTSVG } from "src/libraries/NFTSVG.sol"; -import { SVGElements } from "src/libraries/SVGElements.sol"; +import { NFTSVG } from "core/libraries/NFTSVG.sol"; +import { SVGElements } from "core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/hourglass.t.sol b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol similarity index 96% rename from test/unit/concrete/nft-descriptor/hourglass.t.sol rename to test/core/unit/concrete/nft-descriptor/hourglass.t.sol index 9841de5a4..9bae9e29d 100644 --- a/test/unit/concrete/nft-descriptor/hourglass.t.sol +++ b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { SVGElements } from "src/libraries/SVGElements.sol"; +import { SVGElements } from "core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol similarity index 91% rename from test/unit/concrete/nft-descriptor/stringifyCardType.t.sol rename to test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol index 109d87399..7fd16f1c4 100644 --- a/test/unit/concrete/nft-descriptor/stringifyCardType.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "src/libraries/SVGElements.sol"; +import { SVGElements } from "core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol rename to test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol diff --git a/test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol similarity index 100% rename from test/unit/concrete/nft-descriptor/stringifyPercentage.t.sol rename to test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol diff --git a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol similarity index 94% rename from test/unit/concrete/nft-descriptor/stringifyStatus.t.sol rename to test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol index a18b115f7..d1ba9eab6 100644 --- a/test/unit/concrete/nft-descriptor/stringifyStatus.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/types/DataTypes.sol"; +import { Lockup } from "core/types/DataTypes.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/unit/fuzz/transferAdmin.t.sol b/test/core/unit/fuzz/transferAdmin.t.sol similarity index 96% rename from test/unit/fuzz/transferAdmin.t.sol rename to test/core/unit/fuzz/transferAdmin.t.sol index dd4412cbc..523e2b99a 100644 --- a/test/unit/fuzz/transferAdmin.t.sol +++ b/test/core/unit/fuzz/transferAdmin.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/libraries/Errors.sol"; +import { Errors } from "core/libraries/Errors.sol"; import { Adminable_Unit_Shared_Test } from "../shared/Adminable.t.sol"; diff --git a/test/unit/shared/Adminable.t.sol b/test/core/unit/shared/Adminable.t.sol similarity index 100% rename from test/unit/shared/Adminable.t.sol rename to test/core/unit/shared/Adminable.t.sol diff --git a/test/utils/.npmignore b/test/core/utils/.npmignore similarity index 100% rename from test/utils/.npmignore rename to test/core/utils/.npmignore diff --git a/test/utils/Assertions.sol b/test/core/utils/Assertions.sol similarity index 99% rename from test/utils/Assertions.sol rename to test/core/utils/Assertions.sol index 492f2f678..6669fcc63 100644 --- a/test/utils/Assertions.sol +++ b/test/core/utils/Assertions.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; -import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; abstract contract Assertions is PRBMathAssertions { /*////////////////////////////////////////////////////////////////////////// diff --git a/test/utils/BaseScript.t.sol b/test/core/utils/BaseScript.t.sol similarity index 100% rename from test/utils/BaseScript.t.sol rename to test/core/utils/BaseScript.t.sol diff --git a/test/utils/Calculations.sol b/test/core/utils/Calculations.sol similarity index 98% rename from test/utils/Calculations.sol rename to test/core/utils/Calculations.sol index 1290e64bf..e18aa9153 100644 --- a/test/utils/Calculations.sol +++ b/test/core/utils/Calculations.sol @@ -6,7 +6,7 @@ import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uin import { SD59x18 } from "@prb/math/src/SD59x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; import { Defaults } from "./Defaults.sol"; diff --git a/test/utils/Constants.sol b/test/core/utils/Constants.sol similarity index 100% rename from test/utils/Constants.sol rename to test/core/utils/Constants.sol diff --git a/test/utils/Defaults.sol b/test/core/utils/Defaults.sol similarity index 99% rename from test/utils/Defaults.sol rename to test/core/utils/Defaults.sol index 279eda4f6..2eb383399 100644 --- a/test/utils/Defaults.sol +++ b/test/core/utils/Defaults.sol @@ -5,7 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; +import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; import { Constants } from "./Constants.sol"; import { Users } from "./Types.sol"; diff --git a/test/utils/DeployOptimized.sol b/test/core/utils/DeployOptimized.sol similarity index 88% rename from test/utils/DeployOptimized.sol rename to test/core/utils/DeployOptimized.sol index 226ac9af6..a6142c21d 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/core/utils/DeployOptimized.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22 <0.9.0; import { StdCheats } from "forge-std/src/StdCheats.sol"; -import { ISablierV2LockupDynamic } from "../../src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "../../../src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../../src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; abstract contract DeployOptimized is StdCheats { /// @dev Deploys {SablierV2LockupDynamic} from an optimized source compiled with `--via-ir`. diff --git a/test/utils/Events.sol b/test/core/utils/Events.sol similarity index 96% rename from test/utils/Events.sol rename to test/core/utils/Events.sol index 05fa6890c..925728c25 100644 --- a/test/utils/Events.sol +++ b/test/core/utils/Events.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2NFTDescriptor } from "../../src/interfaces/ISablierV2NFTDescriptor.sol"; -import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/types/DataTypes.sol"; +import { ISablierV2NFTDescriptor } from "../../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. abstract contract Events { diff --git a/test/utils/Fuzzers.sol b/test/core/utils/Fuzzers.sol similarity index 99% rename from test/utils/Fuzzers.sol rename to test/core/utils/Fuzzers.sol index 8496d4299..d915e459b 100644 --- a/test/utils/Fuzzers.sol +++ b/test/core/utils/Fuzzers.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { UD60x18, ud, uUNIT } from "@prb/math/src/UD60x18.sol"; -import { Lockup, LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; import { Constants } from "./Constants.sol"; import { Defaults } from "./Defaults.sol"; diff --git a/test/utils/Precompiles.t.sol b/test/core/utils/Precompiles.t.sol similarity index 93% rename from test/utils/Precompiles.t.sol rename to test/core/utils/Precompiles.t.sol index 5dcd11e88..8d94f8144 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/core/utils/Precompiles.t.sol @@ -4,10 +4,10 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; import { Precompiles } from "precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "src/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "src/interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; import { Base_Test } from "../Base.t.sol"; diff --git a/test/utils/Types.sol b/test/core/utils/Types.sol similarity index 100% rename from test/utils/Types.sol rename to test/core/utils/Types.sol diff --git a/test/utils/Utils.sol b/test/core/utils/Utils.sol similarity index 97% rename from test/utils/Utils.sol rename to test/core/utils/Utils.sol index 0d7192fb1..bf5099d0e 100644 --- a/test/utils/Utils.sol +++ b/test/core/utils/Utils.sol @@ -5,7 +5,7 @@ import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol"; import { CommonBase } from "forge-std/src/Base.sol"; -import { LockupDynamic, LockupTranched } from "../../src/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; abstract contract Utils is CommonBase, PRBMathUtils { /// @dev Bounds a `uint128` number. diff --git a/test/periphery/Base.t.sol b/test/periphery/Base.t.sol new file mode 100644 index 000000000..1fbd3dbdc --- /dev/null +++ b/test/periphery/Base.t.sol @@ -0,0 +1,397 @@ +// SPDX-License-Identifier: UNLICENSED +// solhint-disable max-states-count +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; + +import { Assertions as V2CoreAssertions } from "../core/utils/Assertions.sol"; +import { Constants as V2CoreConstants } from "../core/utils/Constants.sol"; +import { Utils as V2CoreUtils } from "../core/utils/Utils.sol"; + +import { ISablierV2BatchLockup } from "periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLockupFactory } from "periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { SablierV2BatchLockup } from "periphery/SablierV2BatchLockup.sol"; +import { SablierV2MerkleLL } from "periphery/SablierV2MerkleLL.sol"; +import { SablierV2MerkleLockupFactory } from "periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierV2MerkleLT } from "periphery/SablierV2MerkleLT.sol"; + +import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; +import { Assertions } from "./utils/Assertions.sol"; +import { Defaults } from "./utils/Defaults.sol"; +import { DeployOptimized } from "./utils/DeployOptimized.sol"; +import { Events } from "./utils/Events.sol"; +import { Merkle } from "./utils/Murky.sol"; +import { Users } from "./utils/Types.sol"; + +/// @notice Base test contract with common logic needed by all tests. +abstract contract Base_Test is + Assertions, + DeployOptimized, + Events, + Merkle, + V2CoreConstants, + V2CoreAssertions, + V2CoreUtils +{ + /*////////////////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + Users internal users; + + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + ISablierV2BatchLockup internal batchLockup; + IERC20 internal dai; + Defaults internal defaults; + ISablierV2LockupDynamic internal lockupDynamic; + ISablierV2LockupLinear internal lockupLinear; + ISablierV2LockupTranched internal lockupTranched; + ISablierV2MerkleLockupFactory internal merkleLockupFactory; + ISablierV2MerkleLL internal merkleLL; + ISablierV2MerkleLT internal merkleLT; + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual { + // Deploy the default test asset. + dai = new ERC20Mock("DAI Stablecoin", "DAI"); + + // Create users for testing. + users.alice = createUser("Alice"); + users.admin = createUser("Admin"); + users.broker = createUser("Broker"); + users.eve = createUser("Eve"); + users.recipient0 = createUser("Recipient"); + users.recipient1 = createUser("Recipient1"); + users.recipient2 = createUser("Recipient2"); + users.recipient3 = createUser("Recipient3"); + users.recipient4 = createUser("Recipient4"); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Approve `spender` to spend assets from `from`. + function approveContract(IERC20 asset_, address from, address spender) internal { + resetPrank({ msgSender: from }); + (bool success,) = address(asset_).call(abi.encodeCall(IERC20.approve, (spender, MAX_UINT256))); + success; + } + + /// @dev Generates a user, labels its address, and funds it with ETH. + function createUser(string memory name) internal returns (address payable) { + address user = makeAddr(name); + vm.deal({ account: user, newBalance: 100_000 ether }); + deal({ token: address(dai), to: user, give: 1_000_000e18 }); + return payable(user); + } + + /// @dev Conditionally deploy V2 Periphery normally or from an optimized source compiled with `--via-ir`. + function deployPeripheryConditionally() internal { + if (!isTestOptimizedProfile()) { + batchLockup = new SablierV2BatchLockup(); + merkleLockupFactory = new SablierV2MerkleLockupFactory(); + } else { + (batchLockup, merkleLockupFactory) = deployOptimizedPeriphery(); + } + } + + /// @dev Labels the most relevant contracts. + function labelContracts(IERC20 asset_) internal { + vm.label({ account: address(asset_), newLabel: IERC20Metadata(address(asset_)).symbol() }); + vm.label({ account: address(defaults), newLabel: "Defaults" }); + vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); + vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); + vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); + vm.label({ account: address(merkleLL), newLabel: "MerkleLL" }); + vm.label({ account: address(merkleLockupFactory), newLabel: "MerkleLockupFactory" }); + vm.label({ account: address(merkleLT), newLabel: "MerkleLT" }); + } + + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects a call to {IERC20.transfer}. + function expectCallToTransfer(address to, uint256 amount) internal { + expectCallToTransfer(address(dai), to, amount); + } + + /// @dev Expects a call to {IERC20.transfer}. + function expectCallToTransfer(address asset_, address to, uint256 amount) internal { + vm.expectCall({ callee: asset_, data: abi.encodeCall(IERC20.transfer, (to, amount)) }); + } + + /// @dev Expects a call to {IERC20.transferFrom}. + function expectCallToTransferFrom(address from, address to, uint256 amount) internal { + expectCallToTransferFrom(address(dai), from, to, amount); + } + + /// @dev Expects a call to {IERC20.transferFrom}. + function expectCallToTransferFrom(address asset_, address from, address to, uint256 amount) internal { + vm.expectCall({ callee: asset_, data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLD( + uint64 count, + LockupDynamic.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLL( + uint64 count, + LockupLinear.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierV2LockupLinear.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLT( + uint64 count, + LockupTranched.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLD( + uint64 count, + LockupDynamic.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLL( + uint64 count, + LockupLinear.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLT( + uint64 count, + LockupTranched.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {IERC20.transfer}. + function expectMultipleCallsToTransfer(uint64 count, address to, uint256 amount) internal { + vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, amount)) }); + } + + /// @dev Expects multiple calls to {IERC20.transferFrom}. + function expectMultipleCallsToTransferFrom(uint64 count, address from, address to, uint256 amount) internal { + expectMultipleCallsToTransferFrom(address(dai), count, from, to, amount); + } + + /// @dev Expects multiple calls to {IERC20.transferFrom}. + function expectMultipleCallsToTransferFrom( + address asset_, + uint64 count, + address from, + address to, + uint256 amount + ) + internal + { + vm.expectCall({ callee: asset_, count: count, data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); + } + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + function computeMerkleLLAddress( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + return computeMerkleLLAddress(admin, dai, merkleRoot, expiration); + } + + function computeMerkleLLAddress( + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + bytes32 salt = keccak256( + abi.encodePacked( + users.alice, + address(asset_), + defaults.CANCELABLE(), + expiration, + admin, + abi.encode(defaults.IPFS_CID()), + merkleRoot, + defaults.NAME_BYTES32(), + defaults.TRANSFERABLE(), + lockupLinear, + abi.encode(defaults.durations()) + ) + ); + bytes32 creationBytecodeHash = keccak256(getMerkleLLBytecode(admin, asset_, merkleRoot, expiration)); + return vm.computeCreate2Address({ + salt: salt, + initCodeHash: creationBytecodeHash, + deployer: address(merkleLockupFactory) + }); + } + + function computeMerkleLTAddress( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + return computeMerkleLTAddress(admin, dai, merkleRoot, expiration); + } + + function computeMerkleLTAddress( + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + bytes32 salt = keccak256( + abi.encodePacked( + users.alice, + address(asset_), + defaults.CANCELABLE(), + expiration, + admin, + abi.encode(defaults.IPFS_CID()), + merkleRoot, + defaults.NAME_BYTES32(), + defaults.TRANSFERABLE(), + lockupTranched, + abi.encode(defaults.tranchesWithPercentages()) + ) + ); + bytes32 creationBytecodeHash = keccak256(getMerkleLTBytecode(admin, asset_, merkleRoot, expiration)); + return vm.computeCreate2Address({ + salt: salt, + initCodeHash: creationBytecodeHash, + deployer: address(merkleLockupFactory) + }); + } + + function getMerkleLLBytecode( + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (bytes memory) + { + bytes memory constructorArgs = + abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot), lockupLinear, defaults.durations()); + if (!isTestOptimizedProfile()) { + return bytes.concat(type(SablierV2MerkleLL).creationCode, constructorArgs); + } else { + return + bytes.concat(vm.getCode("out-optimized/SablierV2MerkleLL.sol/SablierV2MerkleLL.json"), constructorArgs); + } + } + + function getMerkleLTBytecode( + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (bytes memory) + { + bytes memory constructorArgs = abi.encode( + defaults.baseParams(admin, asset_, expiration, merkleRoot), + lockupTranched, + defaults.tranchesWithPercentages() + ); + if (!isTestOptimizedProfile()) { + return bytes.concat(type(SablierV2MerkleLT).creationCode, constructorArgs); + } else { + return + bytes.concat(vm.getCode("out-optimized/SablierV2MerkleLT.sol/SablierV2MerkleLT.json"), constructorArgs); + } + } +} diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol new file mode 100644 index 000000000..5209d66c1 --- /dev/null +++ b/test/periphery/fork/Fork.t.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { Precompiles } from "precompiles/Precompiles.sol"; + +import { Fuzzers as V2CoreFuzzers } from "../../core/utils/Fuzzers.sol"; +import { Defaults } from "../utils/Defaults.sol"; +import { Base_Test } from "../Base.t.sol"; + +/// @notice Common logic needed by all fork tests. +abstract contract Fork_Test is Base_Test, V2CoreFuzzers { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + IERC20 internal immutable FORK_ASSET; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor(IERC20 forkAsset) { + FORK_ASSET = forkAsset; + } + + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + // Fork Ethereum Mainnet at a specific block number. + vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); + + // Set up the base test contract. + Base_Test.setUp(); + + // Load the external dependencies. + loadDependencies(); + + // Deploy the defaults contract and allow it to access cheatcodes. + defaults = new Defaults({ users_: users, asset_: FORK_ASSET }); + vm.allowCheatcodes(address(defaults)); + + // Deploy V2 Periphery. + deployPeripheryConditionally(); + + // Label the contracts. + labelContracts(FORK_ASSET); + + // Approve the BatchLockup contract. + approveContract({ asset_: FORK_ASSET, from: users.alice, spender: address(batchLockup) }); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Checks the user assumptions. + function checkUsers(address user, address recipient) internal virtual { + // The protocol does not allow the zero address to interact with it. + vm.assume(user != address(0) && recipient != address(0)); + + // The goal is to not have overlapping users because the asset balance tests would fail otherwise. + vm.assume(user != recipient); + vm.assume(user != address(lockupDynamic) && recipient != address(lockupDynamic)); + vm.assume(user != address(lockupLinear) && recipient != address(lockupLinear)); + vm.assume(user != address(lockupTranched) && recipient != address(lockupTranched)); + + // Avoid users blacklisted by USDC or USDT. + assumeNoBlacklisted(address(FORK_ASSET), user); + assumeNoBlacklisted(address(FORK_ASSET), recipient); + } + + /// @dev Loads all dependencies pre-deployed on Mainnet. + function loadDependencies() private { + lockupDynamic = ISablierV2LockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); + lockupLinear = ISablierV2LockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); + lockupTranched = ISablierV2LockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + } +} diff --git a/test/periphery/fork/assets/USDC.t.sol b/test/periphery/fork/assets/USDC.t.sol new file mode 100644 index 000000000..ca1467e07 --- /dev/null +++ b/test/periphery/fork/assets/USDC.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; +import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; +import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; +import { MerkleLL_Fork_Test } from "../merkle-lockup/MerkleLL.t.sol"; +import { MerkleLT_Fork_Test } from "../merkle-lockup/MerkleLT.t.sol"; + +/// @dev An ERC-20 asset with 6 decimals. +IERC20 constant usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); + +contract USDC_CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test(usdc) +{ } + +contract USDC_CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test(usdc) +{ } + +contract USDC_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdc) +{ } + +contract USDC_MerkleLL_Fork_Test is MerkleLL_Fork_Test(usdc) { } + +contract USDC_MerkleLT_Fork_Test is MerkleLT_Fork_Test(usdc) { } diff --git a/test/periphery/fork/assets/USDT.t.sol b/test/periphery/fork/assets/USDT.t.sol new file mode 100644 index 000000000..bdc5ed85d --- /dev/null +++ b/test/periphery/fork/assets/USDT.t.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; +import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; +import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; +import { MerkleLL_Fork_Test } from "../merkle-lockup/MerkleLL.t.sol"; +import { MerkleLT_Fork_Test } from "../merkle-lockup/MerkleLT.t.sol"; + +/// @dev An ERC-20 asset that suffers from the missing return value bug. +IERC20 constant usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); + +contract USDT_CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test(usdt) +{ } + +contract USDT_CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test(usdt) +{ } + +contract USDT_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is + CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdt) +{ } + +contract USDT_MerkleLL_Fork_Test is MerkleLL_Fork_Test(usdt) { } + +contract USDT_MerkleLT_Fork_Test is MerkleLT_Fork_Test(usdt) { } diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol new file mode 100644 index 000000000..98edbab08 --- /dev/null +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { LockupDynamic } from "core/types/DataTypes.sol"; + +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +/// @dev Runs against multiple fork assets. +abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fork_Test { + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + struct CreateWithTimestampsParams { + uint128 batchSize; + address sender; + address recipient; + uint128 perStreamAmount; + uint40 startTime; + LockupDynamic.Segment[] segments; + } + + function testForkFuzz_CreateWithTimestampsLD(CreateWithTimestampsParams memory params) external { + vm.assume(params.segments.length != 0); + params.batchSize = boundUint128(params.batchSize, 1, 20); + params.startTime = boundUint40(params.startTime, getBlockTimestamp(), getBlockTimestamp() + 24 hours); + fuzzSegmentTimestamps(params.segments, params.startTime); + (params.perStreamAmount,) = fuzzDynamicStreamAmounts({ + upperBound: MAX_UINT128 / params.batchSize, + segments: params.segments, + brokerFee: defaults.BROKER_FEE() + }); + + checkUsers(params.sender, params.recipient); + + uint256 firstStreamId = lockupDynamic.nextStreamId(); + uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; + + deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); + approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); + + LockupDynamic.CreateWithTimestamps memory createWithTimestamps = LockupDynamic.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.perStreamAmount, + asset: FORK_ASSET, + cancelable: true, + transferable: true, + startTime: params.startTime, + segments: params.segments, + broker: defaults.broker() + }); + BatchLockup.CreateWithTimestampsLD[] memory batchParams = + BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); + + expectCallToTransferFrom({ + asset_: address(FORK_ASSET), + from: params.sender, + to: address(batchLockup), + amount: totalTransferAmount + }); + expectMultipleCallsToCreateWithTimestampsLD({ count: uint64(params.batchSize), params: createWithTimestamps }); + expectMultipleCallsToTransferFrom({ + asset_: address(FORK_ASSET), + count: uint64(params.batchSize), + from: address(batchLockup), + to: address(lockupDynamic), + amount: params.perStreamAmount + }); + + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLD(lockupDynamic, FORK_ASSET, batchParams); + uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); + assertEq(actualStreamIds, expectedStreamIds); + } +} diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol new file mode 100644 index 000000000..efe940fb1 --- /dev/null +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol @@ -0,0 +1,81 @@ + // SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { LockupLinear } from "core/types/DataTypes.sol"; + +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +/// @dev Runs against multiple fork assets. +abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is Fork_Test { + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + struct CreateWithTimestampsParams { + uint128 batchSize; + LockupLinear.Timestamps timestamps; + address sender; + address recipient; + uint128 perStreamAmount; + } + + function testForkFuzz_CreateWithTimestampsLL(CreateWithTimestampsParams memory params) external { + params.batchSize = boundUint128(params.batchSize, 1, 20); + params.perStreamAmount = boundUint128(params.perStreamAmount, 1, MAX_UINT128 / params.batchSize); + params.timestamps.start = + boundUint40(params.timestamps.start, getBlockTimestamp(), getBlockTimestamp() + 24 hours); + params.timestamps.cliff = boundUint40( + params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks + ); + params.timestamps.end = + boundUint40(params.timestamps.end, params.timestamps.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); + + checkUsers(params.sender, params.recipient); + + uint256 firstStreamId = lockupLinear.nextStreamId(); + uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; + + deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); + approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); + + LockupLinear.CreateWithTimestamps memory createParams = LockupLinear.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.perStreamAmount, + asset: FORK_ASSET, + cancelable: true, + transferable: true, + timestamps: params.timestamps, + broker: defaults.broker() + }); + BatchLockup.CreateWithTimestampsLL[] memory batchParams = + BatchLockupBuilder.fillBatch(createParams, params.batchSize); + + // Asset flow: sender → batch → Sablier + expectCallToTransferFrom({ + asset_: address(FORK_ASSET), + from: params.sender, + to: address(batchLockup), + amount: totalTransferAmount + }); + expectMultipleCallsToCreateWithTimestampsLL({ count: uint64(params.batchSize), params: createParams }); + expectMultipleCallsToTransferFrom({ + asset_: address(FORK_ASSET), + count: uint64(params.batchSize), + from: address(batchLockup), + to: address(lockupLinear), + amount: params.perStreamAmount + }); + + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLL(lockupLinear, FORK_ASSET, batchParams); + uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); + assertEq(actualStreamIds, expectedStreamIds); + } +} diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol new file mode 100644 index 000000000..edba2be4a --- /dev/null +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { LockupTranched } from "core/types/DataTypes.sol"; + +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +/// @dev Runs against multiple fork assets. +abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is Fork_Test { + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + struct CreateWithTimestampsParams { + uint128 batchSize; + address sender; + address recipient; + uint128 perStreamAmount; + uint40 startTime; + LockupTranched.Tranche[] tranches; + } + + function testForkFuzz_CreateWithTimestampsLT(CreateWithTimestampsParams memory params) external { + vm.assume(params.tranches.length != 0); + params.batchSize = boundUint128(params.batchSize, 1, 20); + params.startTime = boundUint40(params.startTime, getBlockTimestamp(), getBlockTimestamp() + 24 hours); + fuzzTrancheTimestamps(params.tranches, params.startTime); + (params.perStreamAmount,) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128 / params.batchSize, + tranches: params.tranches, + brokerFee: defaults.BROKER_FEE() + }); + + checkUsers(params.sender, params.recipient); + + uint256 firstStreamId = lockupTranched.nextStreamId(); + uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; + + deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); + approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); + + LockupTranched.CreateWithTimestamps memory createWithTimestamps = LockupTranched.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.perStreamAmount, + asset: FORK_ASSET, + cancelable: true, + transferable: true, + startTime: params.startTime, + tranches: params.tranches, + broker: defaults.broker() + }); + BatchLockup.CreateWithTimestampsLT[] memory batchParams = + BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); + + expectCallToTransferFrom({ + asset_: address(FORK_ASSET), + from: params.sender, + to: address(batchLockup), + amount: totalTransferAmount + }); + expectMultipleCallsToCreateWithTimestampsLT({ count: uint64(params.batchSize), params: createWithTimestamps }); + expectMultipleCallsToTransferFrom({ + asset_: address(FORK_ASSET), + count: uint64(params.batchSize), + from: address(batchLockup), + to: address(lockupTranched), + amount: params.perStreamAmount + }); + + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLT(lockupTranched, FORK_ASSET, batchParams); + uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); + assertEq(actualStreamIds, expectedStreamIds); + } +} diff --git a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol new file mode 100644 index 000000000..4f34724db --- /dev/null +++ b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; + +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { MerkleLockup } from "periphery/types/DataTypes.sol"; + +import { MerkleBuilder } from "../../utils/MerkleBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +abstract contract MerkleLL_Fork_Test is Fork_Test { + using MerkleBuilder for uint256[]; + + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + /// @dev Encapsulates the data needed to compute a Merkle tree leaf. + struct LeafData { + uint256 index; + uint256 recipientSeed; + uint128 amount; + } + + struct Params { + address admin; + uint40 expiration; + LeafData[] leafData; + uint256 posBeforeSort; + } + + struct Vars { + LockupLinear.StreamLL actualStream; + uint256 actualStreamId; + uint256 aggregateAmount; + uint128[] amounts; + MerkleLockup.ConstructorParams baseParams; + uint128 clawbackAmount; + address expectedLL; + LockupLinear.StreamLL expectedStream; + uint256 expectedStreamId; + uint256[] indexes; + uint256 leafPos; + uint256 leafToClaim; + ISablierV2MerkleLL merkleLL; + bytes32 merkleRoot; + address[] recipients; + uint256 recipientCount; + } + + // We need the leaves as a storage variable so that we can use OpenZeppelin's {Arrays.findUpperBound}. + uint256[] public leaves; + + function testForkFuzz_MerkleLL(Params memory params) external { + vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.leafData.length > 1); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); + + // The expiration must be either zero or greater than the block timestamp. + if (params.expiration != 0) { + params.expiration = boundUint40(params.expiration, getBlockTimestamp() + 1 seconds, MAX_UNIX_TIMESTAMP); + } + + /*////////////////////////////////////////////////////////////////////////// + CREATE + //////////////////////////////////////////////////////////////////////////*/ + + Vars memory vars; + vars.recipientCount = params.leafData.length; + vars.amounts = new uint128[](vars.recipientCount); + vars.indexes = new uint256[](vars.recipientCount); + vars.recipients = new address[](vars.recipientCount); + for (uint256 i = 0; i < vars.recipientCount; ++i) { + vars.indexes[i] = params.leafData[i].index; + + // Bound each leaf amount so that `aggregateAmount` does not overflow. + vars.amounts[i] = boundUint128(params.leafData[i].amount, 1, uint128(MAX_UINT128 / vars.recipientCount - 1)); + vars.aggregateAmount += vars.amounts[i]; + + // Avoid zero recipient addresses. + uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max); + vars.recipients[i] = address(uint160(boundedRecipientSeed)); + } + + leaves = new uint256[](vars.recipientCount); + leaves = MerkleBuilder.computeLeaves(vars.indexes, vars.recipients, vars.amounts); + + // Sort the leaves in ascending order to match the production environment. + MerkleBuilder.sortLeaves(leaves); + vars.merkleRoot = getRoot(leaves.toBytes32()); + + vars.expectedLL = computeMerkleLLAddress(params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + + vars.baseParams = defaults.baseParams({ + admin: params.admin, + asset_: FORK_ASSET, + merkleRoot: vars.merkleRoot, + expiration: params.expiration + }); + + vm.expectEmit({ emitter: address(merkleLockupFactory) }); + emit CreateMerkleLL({ + merkleLL: ISablierV2MerkleLL(vars.expectedLL), + baseParams: vars.baseParams, + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + vars.merkleLL = merkleLockupFactory.createMerkleLL({ + baseParams: vars.baseParams, + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + // Fund the MerkleLockup contract. + deal({ token: address(FORK_ASSET), to: address(vars.merkleLL), give: vars.aggregateAmount }); + + assertGt(address(vars.merkleLL).code.length, 0, "MerkleLL contract not created"); + assertEq(address(vars.merkleLL), vars.expectedLL, "MerkleLL contract does not match computed address"); + + /*////////////////////////////////////////////////////////////////////////// + CLAIM + //////////////////////////////////////////////////////////////////////////*/ + + assertFalse(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort])); + + vars.leafToClaim = MerkleBuilder.computeLeaf( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort] + ); + vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); + + vars.expectedStreamId = lockupLinear.nextStreamId(); + emit Claim( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort], + vars.expectedStreamId + ); + vars.actualStreamId = vars.merkleLL.claim({ + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: getProof(leaves.toBytes32(), vars.leafPos) + }); + + vars.actualStream = lockupLinear.getStream(vars.actualStreamId); + vars.expectedStream = LockupLinear.StreamLL({ + amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), + asset: FORK_ASSET, + cliffTime: getBlockTimestamp() + defaults.CLIFF_DURATION(), + endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), + isCancelable: defaults.CANCELABLE(), + isDepleted: false, + isStream: true, + isTransferable: defaults.TRANSFERABLE(), + recipient: vars.recipients[params.posBeforeSort], + sender: params.admin, + startTime: getBlockTimestamp(), + wasCanceled: false + }); + + assertTrue(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort])); + assertEq(vars.actualStreamId, vars.expectedStreamId); + assertEq(vars.actualStream, vars.expectedStream); + + /*////////////////////////////////////////////////////////////////////////// + CLAWBACK + //////////////////////////////////////////////////////////////////////////*/ + + if (params.expiration > 0) { + vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLL))); + vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); + + resetPrank({ msgSender: params.admin }); + expectCallToTransfer({ asset_: address(FORK_ASSET), to: params.admin, amount: vars.clawbackAmount }); + vm.expectEmit({ emitter: address(vars.merkleLL) }); + emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); + vars.merkleLL.clawback({ to: params.admin, amount: vars.clawbackAmount }); + } + } +} diff --git a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol new file mode 100644 index 000000000..451fb02d3 --- /dev/null +++ b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; + +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup } from "periphery/types/DataTypes.sol"; + +import { MerkleBuilder } from "../../utils/MerkleBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +abstract contract MerkleLT_Fork_Test is Fork_Test { + using MerkleBuilder for uint256[]; + + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + /// @dev Encapsulates the data needed to compute a Merkle tree leaf. + struct LeafData { + uint256 index; + uint256 recipientSeed; + uint128 amount; + } + + struct Params { + address admin; + uint40 expiration; + LeafData[] leafData; + uint256 posBeforeSort; + } + + struct Vars { + LockupTranched.StreamLT actualStream; + uint256 actualStreamId; + LockupTranched.Tranche[] actualTranches; + uint256 aggregateAmount; + uint128[] amounts; + MerkleLockup.ConstructorParams baseParams; + uint128 clawbackAmount; + address expectedLT; + LockupTranched.StreamLT expectedStream; + uint256 expectedStreamId; + uint256[] indexes; + uint256 leafPos; + uint256 leafToClaim; + ISablierV2MerkleLT merkleLT; + bytes32 merkleRoot; + address[] recipients; + uint256 recipientCount; + } + + // We need the leaves as a storage variable so that we can use OpenZeppelin's {Arrays.findUpperBound}. + uint256[] public leaves; + + function testForkFuzz_MerkleLT(Params memory params) external { + vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.leafData.length > 1); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); + + // The expiration must be either zero or greater than the block timestamp. + if (params.expiration != 0) { + params.expiration = boundUint40(params.expiration, getBlockTimestamp() + 1 seconds, MAX_UNIX_TIMESTAMP); + } + + /*////////////////////////////////////////////////////////////////////////// + CREATE + //////////////////////////////////////////////////////////////////////////*/ + + Vars memory vars; + vars.recipientCount = params.leafData.length; + vars.amounts = new uint128[](vars.recipientCount); + vars.indexes = new uint256[](vars.recipientCount); + vars.recipients = new address[](vars.recipientCount); + for (uint256 i = 0; i < vars.recipientCount; ++i) { + vars.indexes[i] = params.leafData[i].index; + + // Bound each leaf amount so that `aggregateAmount` does not overflow. + vars.amounts[i] = boundUint128(params.leafData[i].amount, 1, uint128(MAX_UINT128 / vars.recipientCount - 1)); + vars.aggregateAmount += vars.amounts[i]; + + // Avoid zero recipient addresses. + uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max); + vars.recipients[i] = address(uint160(boundedRecipientSeed)); + } + + leaves = new uint256[](vars.recipientCount); + leaves = MerkleBuilder.computeLeaves(vars.indexes, vars.recipients, vars.amounts); + + // Sort the leaves in ascending order to match the production environment. + MerkleBuilder.sortLeaves(leaves); + vars.merkleRoot = getRoot(leaves.toBytes32()); + + vars.expectedLT = computeMerkleLTAddress(params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + + vars.baseParams = defaults.baseParams({ + admin: params.admin, + asset_: FORK_ASSET, + merkleRoot: vars.merkleRoot, + expiration: params.expiration + }); + + vm.expectEmit({ emitter: address(merkleLockupFactory) }); + emit CreateMerkleLT({ + merkleLT: ISablierV2MerkleLT(vars.expectedLT), + baseParams: vars.baseParams, + lockupTranched: lockupTranched, + tranchesWithPercentages: defaults.tranchesWithPercentages(), + totalDuration: defaults.TOTAL_DURATION(), + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + vars.merkleLT = merkleLockupFactory.createMerkleLT({ + baseParams: vars.baseParams, + lockupTranched: lockupTranched, + tranchesWithPercentages: defaults.tranchesWithPercentages(), + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + // Fund the MerkleLockup contract. + deal({ token: address(FORK_ASSET), to: address(vars.merkleLT), give: vars.aggregateAmount }); + + assertGt(address(vars.merkleLT).code.length, 0, "MerkleLT contract not created"); + assertEq(address(vars.merkleLT), vars.expectedLT, "MerkleLT contract does not match computed address"); + + /*////////////////////////////////////////////////////////////////////////// + CLAIM + //////////////////////////////////////////////////////////////////////////*/ + + assertFalse(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort])); + + vars.leafToClaim = MerkleBuilder.computeLeaf( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort] + ); + vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); + + vars.expectedStreamId = lockupTranched.nextStreamId(); + emit Claim( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort], + vars.expectedStreamId + ); + vars.actualStreamId = vars.merkleLT.claim({ + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: getProof(leaves.toBytes32(), vars.leafPos) + }); + + vars.actualStream = lockupTranched.getStream(vars.actualStreamId); + vars.expectedStream = LockupTranched.StreamLT({ + amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), + asset: FORK_ASSET, + endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), + isCancelable: defaults.CANCELABLE(), + isDepleted: false, + isStream: true, + isTransferable: defaults.TRANSFERABLE(), + recipient: vars.recipients[params.posBeforeSort], + sender: params.admin, + startTime: getBlockTimestamp(), + tranches: defaults.tranches({ totalAmount: vars.amounts[params.posBeforeSort] }), + wasCanceled: false + }); + + assertTrue(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort])); + assertEq(vars.actualStreamId, vars.expectedStreamId); + assertEq(vars.actualStream, vars.expectedStream); + + /*////////////////////////////////////////////////////////////////////////// + CLAWBACK + //////////////////////////////////////////////////////////////////////////*/ + + if (params.expiration > 0) { + vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLT))); + vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); + + resetPrank({ msgSender: params.admin }); + expectCallToTransfer({ asset_: address(FORK_ASSET), to: params.admin, amount: vars.clawbackAmount }); + vm.expectEmit({ emitter: address(vars.merkleLT) }); + emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); + vars.merkleLT.clawback({ to: params.admin, amount: vars.clawbackAmount }); + } + } +} diff --git a/test/periphery/integration/Integration.t.sol b/test/periphery/integration/Integration.t.sol new file mode 100644 index 000000000..5f96c6ad1 --- /dev/null +++ b/test/periphery/integration/Integration.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Precompiles } from "precompiles/Precompiles.sol"; + +import { Defaults } from "../utils/Defaults.sol"; +import { Base_Test } from "../Base.t.sol"; + +/// @notice Common logic needed by all integration tests. +abstract contract Integration_Test is Base_Test { + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function setUp() public virtual override { + // Set up the base test contract. + Base_Test.setUp(); + + // Deploy the external dependencies. + deployDependencies(); + + // Deploy the defaults contract. + defaults = new Defaults({ users_: users, asset_: dai }); + + // Deploy V2 Periphery. + deployPeripheryConditionally(); + + // Label the contracts. + labelContracts(dai); + + // Approve the BatchLockup contract. + approveContract({ asset_: dai, from: users.alice, spender: address(batchLockup) }); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function deployDependencies() private { + (lockupDynamic, lockupLinear, lockupTranched,) = new Precompiles().deployCore(users.admin); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol new file mode 100644 index 000000000..31d18c04e --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithDurationsLD_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithDurationsLD[] memory batchParams = new BatchLockup.CreateWithDurationsLD[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithDurationsLD(lockupDynamic, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithDurations() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithDurationsLD({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithDurationsLD() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupDynamic), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithDurationsLD(lockupDynamic, dai, defaults.batchCreateWithDurationsLD()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.tree b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.tree new file mode 100644 index 000000000..782763dfe --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.tree @@ -0,0 +1,6 @@ +createWithDurationsLD.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with durations + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol new file mode 100644 index 000000000..e83a9ffa1 --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithDurationsLL_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithDurationsLL[] memory batchParams = new BatchLockup.CreateWithDurationsLL[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithDurationsLL(lockupLinear, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithDurations() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithDurationsLL({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithDurationsLL() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupLinear), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithDurationsLL(lockupLinear, dai, defaults.batchCreateWithDurationsLL()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.tree b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.tree new file mode 100644 index 000000000..c0b50c87c --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.tree @@ -0,0 +1,6 @@ +createWithDurationsLL.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with durations + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol new file mode 100644 index 000000000..bbbb49f71 --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithDurationsLT_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithDurationsLT[] memory batchParams = new BatchLockup.CreateWithDurationsLT[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithDurationsLT(lockupTranched, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithDurations() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithDurationsLT({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithDurationsLT() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupTranched), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithDurationsLT(lockupTranched, dai, defaults.batchCreateWithDurationsLT()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.tree b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.tree new file mode 100644 index 000000000..8e67caf2e --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.tree @@ -0,0 +1,6 @@ +createWithDurationsLT.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with durations + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol new file mode 100644 index 000000000..f8210ea5f --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithTimestampsLD_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithTimestampsLD[] memory batchParams = new BatchLockup.CreateWithTimestampsLD[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithTimestampsLD(lockupDynamic, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithTimestampsLD({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithTimestampsLD() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupDynamic), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithTimestampsLD(lockupDynamic, dai, defaults.batchCreateWithTimestampsLD()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.tree b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.tree new file mode 100644 index 000000000..78d71fbd4 --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.tree @@ -0,0 +1,6 @@ +createWithTimestampsLD.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with timestamps + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol new file mode 100644 index 000000000..c72bf2663 --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithTimestampsLL_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithTimestampsLL[] memory batchParams = new BatchLockup.CreateWithTimestampsLL[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithTimestampsLL(lockupLinear, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithTimestampsLL({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithTimestampsLL() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupLinear), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithTimestampsLL(lockupLinear, dai, defaults.batchCreateWithTimestampsLL()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.tree b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.tree new file mode 100644 index 000000000..e9409127e --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.tree @@ -0,0 +1,6 @@ +createWithTimestampsLL.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with timestamps + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol new file mode 100644 index 000000000..1eca76efb --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { BatchLockup } from "periphery/types/DataTypes.sol"; + +import { Integration_Test } from "../../Integration.t.sol"; + +contract CreateWithTimestampsLT_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + BatchLockup.CreateWithTimestampsLT[] memory batchParams = new BatchLockup.CreateWithTimestampsLT[](0); + vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + batchLockup.createWithTimestampsLT(lockupTranched, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { + // Asset flow: Alice → batchLockup → Sablier + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + expectCallToTransferFrom({ + from: users.alice, + to: address(batchLockup), + amount: defaults.TOTAL_TRANSFER_AMOUNT() + }); + expectMultipleCallsToCreateWithTimestampsLT({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithTimestampsLT() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batchLockup), + to: address(lockupTranched), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batchLockup.createWithTimestampsLT(lockupTranched, dai, defaults.batchCreateWithTimestampsLT()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.tree b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.tree new file mode 100644 index 000000000..66ab5a5a5 --- /dev/null +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.tree @@ -0,0 +1,6 @@ +createWithTimestampsLT.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with timestamps + └── it should perform the ERC-20 transfers diff --git a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol new file mode 100644 index 000000000..dcad44c14 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; + +import { Integration_Test } from "../Integration.t.sol"; + +abstract contract MerkleLockup_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + + // Create the default MerkleLockup contracts. + merkleLL = createMerkleLL(); + merkleLT = createMerkleLT(); + + // Fund the MerkleLockup contracts. + deal({ token: address(dai), to: address(merkleLL), give: defaults.AGGREGATE_AMOUNT() }); + deal({ token: address(dai), to: address(merkleLT), give: defaults.AGGREGATE_AMOUNT() }); + } + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LL + //////////////////////////////////////////////////////////////////////////*/ + + function claimLL() internal returns (uint256) { + return merkleLL.claim({ + index: defaults.INDEX1(), + recipient: users.recipient1, + amount: defaults.CLAIM_AMOUNT(), + merkleProof: defaults.index1Proof() + }); + } + + function computeMerkleLLAddress() internal view returns (address) { + return computeMerkleLLAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleLLAddress(address admin) internal view returns (address) { + return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleLLAddress(address admin, uint40 expiration) internal view returns (address) { + return computeMerkleLLAddress(admin, defaults.MERKLE_ROOT(), expiration); + } + + function computeMerkleLLAddress(address admin, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION()); + } + + function createMerkleLL() internal returns (ISablierV2MerkleLL) { + return createMerkleLL(users.admin, defaults.EXPIRATION()); + } + + function createMerkleLL(address admin) internal returns (ISablierV2MerkleLL) { + return createMerkleLL(admin, defaults.EXPIRATION()); + } + + function createMerkleLL(uint40 expiration) internal returns (ISablierV2MerkleLL) { + return createMerkleLL(users.admin, expiration); + } + + function createMerkleLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleLL) { + return merkleLockupFactory.createMerkleLL({ + baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + } + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LT + //////////////////////////////////////////////////////////////////////////*/ + + function claimLT() internal returns (uint256) { + return merkleLT.claim({ + index: defaults.INDEX1(), + recipient: users.recipient1, + amount: defaults.CLAIM_AMOUNT(), + merkleProof: defaults.index1Proof() + }); + } + + function computeMerkleLTAddress() internal view returns (address) { + return computeMerkleLTAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleLTAddress(address admin) internal view returns (address) { + return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleLTAddress(address admin, uint40 expiration) internal view returns (address) { + return computeMerkleLTAddress(admin, defaults.MERKLE_ROOT(), expiration); + } + + function computeMerkleLTAddress(address admin, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION()); + } + + function createMerkleLT() internal returns (ISablierV2MerkleLT) { + return createMerkleLT(users.admin, defaults.EXPIRATION()); + } + + function createMerkleLT(address admin) internal returns (ISablierV2MerkleLT) { + return createMerkleLT(admin, defaults.EXPIRATION()); + } + + function createMerkleLT(uint40 expiration) internal returns (ISablierV2MerkleLT) { + return createMerkleLT(users.admin, expiration); + } + + function createMerkleLT(address admin, uint40 expiration) internal returns (ISablierV2MerkleLT) { + return merkleLockupFactory.createMerkleLT({ + baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + lockupTranched: lockupTranched, + tranchesWithPercentages: defaults.tranchesWithPercentages(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + } +} diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol new file mode 100644 index 000000000..277822741 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupLinear } from "core/types/DataTypes.sol"; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { MerkleLockup } from "periphery/types/DataTypes.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public override { + MerkleLockup_Integration_Test.setUp(); + + // Make alice the caller of createMerkleLT. + resetPrank(users.alice); + } + + function test_RevertWhen_CampaignNameTooLong() external { + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + LockupLinear.Durations memory streamDurations = defaults.durations(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + baseParams.name = "this string is longer than 32 characters"; + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2MerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + ) + ); + + merkleLockupFactory.createMerkleLL({ + baseParams: baseParams, + lockupLinear: lockupLinear, + streamDurations: streamDurations, + aggregateAmount: aggregateAmount, + recipientCount: recipientCount + }); + } + + modifier whenCampaignNameNotTooLong() { + _; + } + + /// @dev This test works because a default MerkleLockup contract is deployed in {Integration_Test.setUp} + function test_RevertGiven_CreatedAlready() external whenCampaignNameNotTooLong { + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + LockupLinear.Durations memory streamDurations = defaults.durations(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + // Expect a revert due to CREATE2. + vm.expectRevert(); + merkleLockupFactory.createMerkleLL({ + baseParams: baseParams, + lockupLinear: lockupLinear, + streamDurations: streamDurations, + aggregateAmount: aggregateAmount, + recipientCount: recipientCount + }); + } + + modifier givenNotCreatedAlready() { + _; + } + + function testFuzz_CreateMerkleLL( + address admin, + uint40 expiration + ) + external + whenCampaignNameNotTooLong + givenNotCreatedAlready + { + vm.assume(admin != users.admin); + address expectedLL = computeMerkleLLAddress(admin, expiration); + + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams({ + admin: admin, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + vm.expectEmit({ emitter: address(merkleLockupFactory) }); + emit CreateMerkleLL({ + merkleLL: ISablierV2MerkleLL(expectedLL), + baseParams: baseParams, + lockupLinear: lockupLinear, + streamDurations: defaults.durations(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + address actualLL = address(createMerkleLL(admin, expiration)); + assertGt(actualLL.code.length, 0, "MerkleLL contract not created"); + assertEq(actualLL, expectedLL, "MerkleLL contract does not match computed address"); + } +} diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree new file mode 100644 index 000000000..81de5f399 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree @@ -0,0 +1,9 @@ +createMerkleLL.t.sol +├── when the campaign name is too long +│ └── it should revert +└── when the campaign name is not too long + ├── given the campaign has been created already + │ └── it should revert + └── given the campaign has not been created already + ├── it should create the campaign + └── it should emit a {CreateMerkleLL} event diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol new file mode 100644 index 000000000..b7699617b --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "periphery/libraries/Errors.sol"; +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public override { + MerkleLockup_Integration_Test.setUp(); + + // Make alice the caller of createMerkleLT. + resetPrank(users.alice); + } + + function test_RevertWhen_CampaignNameTooLong() external { + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + baseParams.name = "this string is longer than 32 characters"; + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2MerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + ) + ); + + merkleLockupFactory.createMerkleLT( + baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + ); + } + + modifier whenCampaignNameNotTooLong() { + _; + } + + /// @dev This test works because a default MerkleLockup contract is deployed in {Integration_Test.setUp} + function test_RevertGiven_CreatedAlready() external whenCampaignNameNotTooLong { + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + // Expect a revert due to CREATE2. + vm.expectRevert(); + merkleLockupFactory.createMerkleLT( + baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + ); + } + + modifier givenNotCreatedAlready() { + _; + } + + function testFuzz_CreateMerkleLT( + address admin, + uint40 expiration + ) + external + whenCampaignNameNotTooLong + givenNotCreatedAlready + { + vm.assume(admin != users.admin); + address expectedLT = computeMerkleLTAddress(admin, expiration); + + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams({ + admin: admin, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + vm.expectEmit({ emitter: address(merkleLockupFactory) }); + emit CreateMerkleLT({ + merkleLT: ISablierV2MerkleLT(expectedLT), + baseParams: baseParams, + lockupTranched: lockupTranched, + tranchesWithPercentages: defaults.tranchesWithPercentages(), + totalDuration: defaults.TOTAL_DURATION(), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + address actualLT = address(createMerkleLT(admin, expiration)); + assertGt(actualLT.code.length, 0, "MerkleLT contract not created"); + assertEq(actualLT, expectedLT, "MerkleLT contract does not match computed address"); + } +} diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree new file mode 100644 index 000000000..eda674263 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree @@ -0,0 +1,9 @@ +createMerkleLT.t.sol +├── when the campaign name is too long +│ └── it should revert +└── when the campaign name is not too long + ├── given the campaign has been created already + │ └── it should revert + └── given the campaign has not been created already + ├── it should create the campaign + └── it should emit a {CreateMerkleLT} event diff --git a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol new file mode 100644 index 000000000..70b2255d4 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MAX_UD2x18, ud2x18 } from "@prb/math/src/UD2x18.sol"; + +import { MerkleLT } from "periphery/types/DataTypes.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract IsPercentagesSum100_Integration_Test is MerkleLockup_Integration_Test { + function test_RevertWhen_SumOverflow() public { + MerkleLT.TrancheWithPercentage[] memory tranches = defaults.tranchesWithPercentages(); + tranches[0].unlockPercentage = MAX_UD2x18; + + vm.expectRevert(); + merkleLockupFactory.isPercentagesSum100(tranches); + } + + modifier whenSumDoesNotOverflow() { + _; + } + + modifier whenTotalPercentageNotOneHundred() { + _; + } + + function test_TotalPercentageLessThanOneHundred() + external + view + whenSumDoesNotOverflow + whenTotalPercentageNotOneHundred + { + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + tranchesWithPercentages[0].unlockPercentage = ud2x18(0.05e18); + tranchesWithPercentages[1].unlockPercentage = ud2x18(0.2e18); + + assertFalse(merkleLockupFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); + } + + function test_TotalPercentageGreaterThanOneHundred() + external + view + whenSumDoesNotOverflow + whenTotalPercentageNotOneHundred + { + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + tranchesWithPercentages[0].unlockPercentage = ud2x18(0.5e18); + tranchesWithPercentages[1].unlockPercentage = ud2x18(0.6e18); + + assertFalse(merkleLockupFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); + } + + modifier whenTotalPercentageOneHundred() { + _; + } + + function test_IsPercentagesSum100() external view whenSumDoesNotOverflow whenTotalPercentageOneHundred { + assertTrue(merkleLockupFactory.isPercentagesSum100(defaults.tranchesWithPercentages()), "isPercentagesSum100"); + } +} diff --git a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree new file mode 100644 index 000000000..d500edc0b --- /dev/null +++ b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree @@ -0,0 +1,11 @@ +isPercentagesSum100.t.sol +├── when the sum of the percentages overflows +│ └── it should revert +└── when the sum of the percentages does not overflow + ├── when the sum of the percentages does not equal 100% + │ ├── when the sum of the percentages is less than 100% + │ │ └── it should return false + │ └── when the sum of the percentages is greater than 100% + │ └── it should return false + └── when the sum of the percentages equals 100% + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol new file mode 100644 index 000000000..1af5a3e37 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; + +import { Errors } from "periphery/libraries/Errors.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Claim_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_RevertGiven_CampaignExpired() external { + uint40 expiration = defaults.EXPIRATION(); + uint256 warpTime = expiration + 1 seconds; + bytes32[] memory merkleProof; + vm.warp({ newTimestamp: warpTime }); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2MerkleLockup_CampaignExpired.selector, warpTime, expiration) + ); + merkleLL.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + modifier givenCampaignNotExpired() { + _; + } + + function test_RevertGiven_AlreadyClaimed() external givenCampaignNotExpired { + claimLL(); + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_StreamClaimed.selector, index1)); + merkleLL.claim(index1, users.recipient1, amount, merkleProof); + } + + modifier givenNotClaimed() { + _; + } + + modifier givenNotIncludedInMerkleTree() { + _; + } + + function test_RevertWhen_InvalidIndex() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 invalidIndex = 1337; + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLL.claim(invalidIndex, users.recipient1, amount, merkleProof); + } + + function test_RevertWhen_InvalidRecipient() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + address invalidRecipient = address(1337); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLL.claim(index1, invalidRecipient, amount, merkleProof); + } + + function test_RevertWhen_InvalidAmount() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 invalidAmount = 1337; + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLL.claim(index1, users.recipient1, invalidAmount, merkleProof); + } + + function test_RevertWhen_InvalidMerkleProof() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory invalidMerkleProof = defaults.index2Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLL.claim(index1, users.recipient1, amount, invalidMerkleProof); + } + + modifier givenIncludedInMerkleTree() { + _; + } + + function test_Claim() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { + uint256 expectedStreamId = lockupLinear.nextStreamId(); + + vm.expectEmit({ emitter: address(merkleLL) }); + emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); + uint256 actualStreamId = claimLL(); + + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(actualStreamId); + LockupLinear.StreamLL memory expectedStream = LockupLinear.StreamLL({ + amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), + asset: dai, + cliffTime: getBlockTimestamp() + defaults.CLIFF_DURATION(), + endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), + isCancelable: defaults.CANCELABLE(), + isDepleted: false, + isStream: true, + isTransferable: defaults.TRANSFERABLE(), + recipient: users.recipient1, + sender: users.admin, + startTime: getBlockTimestamp(), + wasCanceled: false + }); + + assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); + assertEq(actualStreamId, expectedStreamId, "invalid stream id"); + assertEq(actualStream, expectedStream); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.tree b/test/periphery/integration/merkle-lockup/ll/claim/claim.tree new file mode 100644 index 000000000..b61221784 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/claim/claim.tree @@ -0,0 +1,20 @@ +claim.t.sol +├── given the campaign has expired +│ └── it should revert +└── given the campaign has not expired + ├── given the recipient has claimed + │ └── it should revert + └── given the recipient has not claimed + ├── given the claim is not included in the Merkle tree + │ ├── when the index is not valid + │ │ └── it should revert + │ ├── when the recipient address is not valid + │ │ └── it should revert + │ ├── when the amount is not valid + │ │ └── it should revert + │ └── when the Merkle proof is not valid + │ └── it should revert + └── given the claim is included in the Merkle tree + ├── it should mark the index as claimed + ├── it should create a stream + └── it should emit a {Claim} event diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol new file mode 100644 index 000000000..8d8abbd6b --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as V2CoreErrors } from "core/libraries/Errors.sol"; + +import { Errors } from "periphery/libraries/Errors.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Clawback_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_RevertWhen_CallerNotAdmin() external { + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(V2CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleLL.clawback({ to: users.eve, amount: 1 }); + } + + modifier whenCallerAdmin() { + resetPrank({ msgSender: users.admin }); + _; + } + + function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { + test_Clawback(users.admin); + } + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { + vm.warp({ newTimestamp: block.timestamp + 6 days }); + test_Clawback(users.admin); + } + + modifier postGracePeriod() { + vm.warp({ newTimestamp: block.timestamp + 8 days }); + _; + } + + function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, + block.timestamp, + defaults.EXPIRATION(), + defaults.FIRST_CLAIM_TIME() + ) + ); + merkleLL.clawback({ to: users.admin, amount: 1 }); + } + + modifier givenCampaignExpired() { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + _; + } + + function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { + test_Clawback(users.admin); + } + + function testFuzz_Clawback(address to) + external + whenCallerAdmin + afterFirstClaim + postGracePeriod + givenCampaignExpired + { + vm.assume(to != address(0)); + test_Clawback(to); + } + + function test_Clawback(address to) internal { + uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLL))); + expectCallToTransfer({ to: to, amount: clawbackAmount }); + vm.expectEmit({ emitter: address(merkleLL) }); + emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); + merkleLL.clawback({ to: to, amount: clawbackAmount }); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree new file mode 100644 index 000000000..b961e8883 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree @@ -0,0 +1,17 @@ +clawback.t.sol +├── when the caller is not the admin +│ └── it should revert +└── when the caller is the admin + ├── when the first claim has not been made + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── when the first claim has been made + ├── given the current time is not more than 7 days after the first claim + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── given the current time is more than 7 days after the first claim + ├── given the campaign has not expired + │ └── it should revert + └── given the campaign has expired + ├── it should perform the ERC-20 transfer + └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol new file mode 100644 index 000000000..dc50b46a2 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { LockupLinear } from "core/types/DataTypes.sol"; + +import { SablierV2MerkleLL } from "periphery/SablierV2MerkleLL.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Constructor_MerkleLL_Integration_Test is MerkleLockup_Integration_Test { + /// @dev Needed to prevent "Stack too deep" error + struct Vars { + address actualAdmin; + uint256 actualAllowance; + address actualAsset; + string actualIpfsCID; + string actualName; + bool actualCancelable; + LockupLinear.Durations actualDurations; + uint40 actualExpiration; + address actualLockupLinear; + bytes32 actualMerkleRoot; + bool actualTransferable; + address expectedAdmin; + uint256 expectedAllowance; + address expectedAsset; + bool expectedCancelable; + LockupLinear.Durations expectedDurations; + uint40 expectedExpiration; + string expectedIpfsCID; + address expectedLockupLinear; + bytes32 expectedMerkleRoot; + bytes32 expectedName; + bool expectedTransferable; + } + + function test_Constructor() external { + SablierV2MerkleLL constructedLL = + new SablierV2MerkleLL(defaults.baseParams(), lockupLinear, defaults.durations()); + + Vars memory vars; + + vars.actualAdmin = constructedLL.admin(); + vars.expectedAdmin = users.admin; + assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); + + vars.actualAllowance = dai.allowance(address(constructedLL), address(lockupLinear)); + vars.expectedAllowance = MAX_UINT256; + assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); + + vars.actualAsset = address(constructedLL.ASSET()); + vars.expectedAsset = address(dai); + assertEq(vars.actualAsset, vars.expectedAsset, "asset"); + + vars.actualCancelable = constructedLL.CANCELABLE(); + vars.expectedCancelable = defaults.CANCELABLE(); + assertEq(vars.actualCancelable, vars.expectedCancelable, "cancelable"); + + (vars.actualDurations.cliff, vars.actualDurations.total) = constructedLL.streamDurations(); + vars.expectedDurations = defaults.durations(); + assertEq(vars.actualDurations.cliff, vars.expectedDurations.cliff, "durations.cliff"); + assertEq(vars.actualDurations.total, vars.expectedDurations.total, "durations.total"); + + vars.actualExpiration = constructedLL.EXPIRATION(); + vars.expectedExpiration = defaults.EXPIRATION(); + assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); + + vars.actualIpfsCID = constructedLL.ipfsCID(); + vars.expectedIpfsCID = defaults.IPFS_CID(); + assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); + + vars.actualLockupLinear = address(constructedLL.LOCKUP_LINEAR()); + vars.expectedLockupLinear = address(lockupLinear); + assertEq(vars.actualLockupLinear, vars.expectedLockupLinear, "lockupLinear"); + + vars.actualMerkleRoot = constructedLL.MERKLE_ROOT(); + vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); + assertEq(vars.actualMerkleRoot, vars.expectedMerkleRoot, "merkleRoot"); + + vars.actualName = constructedLL.name(); + vars.expectedName = defaults.NAME_BYTES32(); + assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); + + vars.actualTransferable = constructedLL.TRANSFERABLE(); + vars.expectedTransferable = defaults.TRANSFERABLE(); + assertEq(vars.actualTransferable, vars.expectedTransferable, "transferable"); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol new file mode 100644 index 000000000..bd61c2e11 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_GetFirstClaimTime_BeforeFirstClaim() external view { + uint256 firstClaimTime = merkleLL.getFirstClaimTime(); + assertEq(firstClaimTime, 0); + } + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function test_GetFirstClaimTime() external afterFirstClaim { + uint256 firstClaimTime = merkleLL.getFirstClaimTime(); + assertEq(firstClaimTime, block.timestamp); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree new file mode 100644 index 000000000..cab778426 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree @@ -0,0 +1,5 @@ +getFirstClaimTime.t.sol +├── when the first claim has not been made +│ └── it should return 0 +└── when the first claim has been made + └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol new file mode 100644 index 000000000..0b07e9166 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract HasClaimed_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_HasClaimed_IndexNotInTree() external { + uint256 indexNotInTree = 1337e18; + assertFalse(merkleLL.hasClaimed(indexNotInTree), "claimed"); + } + + modifier whenIndexInTree() { + _; + } + + function test_HasClaimed_NotClaimed() external whenIndexInTree { + assertFalse(merkleLL.hasClaimed(defaults.INDEX1()), "claimed"); + } + + modifier givenRecipientHasClaimed() { + claimLL(); + _; + } + + function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { + assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree new file mode 100644 index 000000000..dcbcafe7a --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree @@ -0,0 +1,8 @@ +hasClaimed.t.sol +├── when the index is not in the Merkle tree +│ └── it should return false +└── when the index is in the Merkle tree + ├── given the recipient has not claimed + │ └── it should return false + └── given the recipient has claimed + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol new file mode 100644 index 000000000..e482fc65c --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_HasExpired_ExpirationZero() external { + ISablierV2MerkleLL testLockup = createMerkleLL({ expiration: 0 }); + assertFalse(testLockup.hasExpired(), "campaign expired"); + } + + modifier givenExpirationNotZero() { + _; + } + + function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { + assertFalse(merkleLL.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() }); + assertTrue(merkleLL.hasExpired(), "campaign not expired"); + } + + function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + assertTrue(merkleLL.hasExpired(), "campaign not expired"); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree new file mode 100644 index 000000000..5fd22925e --- /dev/null +++ b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree @@ -0,0 +1,10 @@ +hasExpired.t.sol +├── when the expiration is zero +│ └── it should return false +└── when the expiration is not zero + ├── when the expiration is less than the block timestamp + │ └── it should return false + ├── when the expiration is equal to the block timestamp + │ └── it should return true + └── when the expiration is greater than the block timestamp + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol new file mode 100644 index 000000000..d33b7cd03 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { ud2x18 } from "@prb/math/src/UD2x18.sol"; +import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; + +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { Errors } from "periphery/libraries/Errors.sol"; +import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; + +import { MerkleBuilder } from "../../../../utils/MerkleBuilder.sol"; +import { Merkle } from "../../../../utils/Murky.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { + using MerkleBuilder for uint256[]; + + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + modifier whenTotalPercentageNotOneHundred() { + _; + } + + function test_RevertWhen_TotalPercentageLessThanOneHundred() external whenTotalPercentageNotOneHundred { + // Create a MerkleLT campaign with a total percentage less than 100. + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + tranchesWithPercentages[0].unlockPercentage = ud2x18(0.05e18); + tranchesWithPercentages[1].unlockPercentage = ud2x18(0.2e18); + + uint64 totalPercentage = + tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); + + merkleLT = merkleLockupFactory.createMerkleLT( + baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + ); + + // Claim an airstream. + bytes32[] memory merkleProof = defaults.index1Proof(); + + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) + ); + + merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + function test_RevertWhen_TotalPercentageGreaterThanOneHundred() external whenTotalPercentageNotOneHundred { + // Create a MerkleLT campaign with a total percentage less than 100. + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); + tranchesWithPercentages[0].unlockPercentage = ud2x18(0.75e18); + tranchesWithPercentages[1].unlockPercentage = ud2x18(0.8e18); + + uint64 totalPercentage = + tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); + + merkleLT = merkleLockupFactory.createMerkleLT( + baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + ); + + // Claim an airstream. + bytes32[] memory merkleProof = defaults.index1Proof(); + + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) + ); + + merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + modifier whenTotalPercentageOneHundred() { + _; + } + + function test_RevertGiven_CampaignExpired() external whenTotalPercentageOneHundred { + uint40 expiration = defaults.EXPIRATION(); + uint256 warpTime = expiration + 1 seconds; + bytes32[] memory merkleProof; + vm.warp({ newTimestamp: warpTime }); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierV2MerkleLockup_CampaignExpired.selector, warpTime, expiration) + ); + merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + modifier givenCampaignNotExpired() { + _; + } + + function test_RevertGiven_AlreadyClaimed() external whenTotalPercentageOneHundred givenCampaignNotExpired { + claimLT(); + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_StreamClaimed.selector, index1)); + merkleLT.claim(index1, users.recipient1, amount, merkleProof); + } + + modifier givenNotClaimed() { + _; + } + + modifier givenNotIncludedInMerkleTree() { + _; + } + + function test_RevertWhen_InvalidIndex() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 invalidIndex = 1337; + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLT.claim(invalidIndex, users.recipient1, amount, merkleProof); + } + + function test_RevertWhen_InvalidRecipient() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + address invalidRecipient = address(1337); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLT.claim(index1, invalidRecipient, amount, merkleProof); + } + + function test_RevertWhen_InvalidAmount() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 invalidAmount = 1337; + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLT.claim(index1, users.recipient1, invalidAmount, merkleProof); + } + + function test_RevertWhen_InvalidMerkleProof() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory invalidMerkleProof = defaults.index2Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + merkleLT.claim(index1, users.recipient1, amount, invalidMerkleProof); + } + + modifier givenIncludedInMerkleTree() { + _; + } + + /// @dev Needed this variable in storage due to how the imported libraries work. + uint256[] public leaves = new uint256[](4); // same number of recipients as in Defaults + + function test_Claim_CalculatedAmountsSumNotEqualClaimAmount() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenIncludedInMerkleTree + { + // Declare a claim amount that will cause a rounding error. + uint128 claimAmount = defaults.CLAIM_AMOUNT() + 1; + + // Compute the test Merkle tree. + leaves = defaults.getLeaves(); + uint256 leaf = MerkleBuilder.computeLeaf(defaults.INDEX1(), users.recipient1, claimAmount); + leaves[0] = leaf; + MerkleBuilder.sortLeaves(leaves); + + // Compute the test Merkle proof. + uint256 pos = Arrays.findUpperBound(leaves, leaf); + bytes32[] memory proof = getProof(leaves.toBytes32(), pos); + + /// Declare the constructor params. + MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + baseParams.merkleRoot = getRoot(leaves.toBytes32()); + + // Deploy a test MerkleLT contract. + ISablierV2MerkleLT testMerkleLT = merkleLockupFactory.createMerkleLT( + baseParams, + lockupTranched, + defaults.tranchesWithPercentages(), + defaults.AGGREGATE_AMOUNT(), + defaults.RECIPIENT_COUNT() + ); + + // Fund the MerkleLT contract. + deal({ token: address(dai), to: address(testMerkleLT), give: defaults.AGGREGATE_AMOUNT() }); + + uint256 expectedStreamId = lockupTranched.nextStreamId(); + vm.expectEmit({ emitter: address(testMerkleLT) }); + emit Claim(defaults.INDEX1(), users.recipient1, claimAmount, expectedStreamId); + + uint256 actualStreamId = testMerkleLT.claim(defaults.INDEX1(), users.recipient1, claimAmount, proof); + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(actualStreamId); + LockupTranched.StreamLT memory expectedStream = LockupTranched.StreamLT({ + amounts: Lockup.Amounts({ deposited: claimAmount, refunded: 0, withdrawn: 0 }), + asset: dai, + endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), + isCancelable: defaults.CANCELABLE(), + isDepleted: false, + isStream: true, + isTransferable: defaults.TRANSFERABLE(), + recipient: users.recipient1, + sender: users.admin, + startTime: getBlockTimestamp(), + tranches: defaults.tranches(claimAmount), + wasCanceled: false + }); + + assertTrue(testMerkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); + assertEq(actualStreamId, expectedStreamId, "invalid stream id"); + assertEq(actualStream, expectedStream); + } + + modifier whenCalculatedAmountsSumEqualsClaimAmount() { + _; + } + + function test_Claim() + external + whenTotalPercentageOneHundred + givenCampaignNotExpired + givenNotClaimed + givenIncludedInMerkleTree + whenCalculatedAmountsSumEqualsClaimAmount + { + uint256 expectedStreamId = lockupTranched.nextStreamId(); + vm.expectEmit({ emitter: address(merkleLT) }); + emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); + + uint256 actualStreamId = claimLT(); + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(actualStreamId); + LockupTranched.StreamLT memory expectedStream = LockupTranched.StreamLT({ + amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), + asset: dai, + endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), + isCancelable: defaults.CANCELABLE(), + isDepleted: false, + isStream: true, + isTransferable: defaults.TRANSFERABLE(), + recipient: users.recipient1, + sender: users.admin, + startTime: getBlockTimestamp(), + tranches: defaults.tranches(), + wasCanceled: false + }); + + assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); + assertEq(actualStreamId, expectedStreamId, "invalid stream id"); + assertEq(actualStream, expectedStream); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.tree b/test/periphery/integration/merkle-lockup/lt/claim/claim.tree new file mode 100644 index 000000000..ab986c299 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/claim/claim.tree @@ -0,0 +1,33 @@ +claim.t.sol +. +├── when the total percentage does not equal 100% +│ ├── when the total percentage is less than 100% +│ │ └── it should revert +│ └── when the total percentage is greater than 100% +│ └── it should revert +└── when the total percentage equals 100% + ├── given the campaign has expired + │ └── it should revert + └── given the campaign has not expired + ├── given the recipient has claimed + │ └── it should revert + └── given the recipient has not claimed + ├── given the claim is not included in the Merkle tree + │ ├── when the index is not valid + │ │ └── it should revert + │ ├── when the recipient address is not valid + │ │ └── it should revert + │ ├── when the amount is not valid + │ │ └── it should revert + │ └── when the Merkle proof is not valid + │ └── it should revert + └── given the claim is included in the Merkle tree + ├── when the sum of the calculated amounts does not equal the claim amount + │ ├── it should adjust the last tranche amount + │ ├── it should mark the index as claimed + │ ├── it should create a stream + │ └── it should emit a {Claim} event + └── when the sum of the calculated amounts equals the claim amount + ├── it should mark the index as claimed + ├── it should create a stream + └── it should emit a {Claim} event diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol new file mode 100644 index 000000000..653c80eea --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as V2CoreErrors } from "core/libraries/Errors.sol"; + +import { Errors } from "periphery/libraries/Errors.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Clawback_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_RevertWhen_CallerNotAdmin() external { + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(V2CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleLT.clawback({ to: users.eve, amount: 1 }); + } + + modifier whenCallerAdmin() { + resetPrank({ msgSender: users.admin }); + _; + } + + function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { + test_Clawback(users.admin); + } + + modifier afterFirstClaim() { + claimLT(); + _; + } + + function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { + vm.warp({ newTimestamp: block.timestamp + 6 days }); + test_Clawback(users.admin); + } + + modifier postGracePeriod() { + vm.warp({ newTimestamp: block.timestamp + 8 days }); + _; + } + + function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, + block.timestamp, + defaults.EXPIRATION(), + defaults.FIRST_CLAIM_TIME() + ) + ); + merkleLT.clawback({ to: users.admin, amount: 1 }); + } + + modifier givenCampaignExpired() { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + _; + } + + function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { + test_Clawback(users.admin); + } + + function testFuzz_Clawback(address to) + external + whenCallerAdmin + afterFirstClaim + postGracePeriod + givenCampaignExpired + { + vm.assume(to != address(0)); + test_Clawback(to); + } + + function test_Clawback(address to) internal { + uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLT))); + expectCallToTransfer({ to: to, amount: clawbackAmount }); + vm.expectEmit({ emitter: address(merkleLT) }); + emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); + merkleLT.clawback({ to: to, amount: clawbackAmount }); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree new file mode 100644 index 000000000..b961e8883 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree @@ -0,0 +1,17 @@ +clawback.t.sol +├── when the caller is not the admin +│ └── it should revert +└── when the caller is the admin + ├── when the first claim has not been made + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── when the first claim has been made + ├── given the current time is not more than 7 days after the first claim + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── given the current time is more than 7 days after the first claim + ├── given the campaign has not expired + │ └── it should revert + └── given the campaign has expired + ├── it should perform the ERC-20 transfer + └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol new file mode 100644 index 000000000..bb4d143fc --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2MerkleLT } from "periphery/SablierV2MerkleLT.sol"; +import { MerkleLT } from "periphery/types/DataTypes.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract Constructor_MerkleLT_Integration_Test is MerkleLockup_Integration_Test { + /// @dev Needed to prevent "Stack too deep" error + struct Vars { + address actualAdmin; + uint256 actualAllowance; + address actualAsset; + string actualIpfsCID; + string actualName; + bool actualCancelable; + uint40 actualExpiration; + address actualLockupTranched; + bytes32 actualMerkleRoot; + uint64 actualTotalPercentage; + MerkleLT.TrancheWithPercentage[] actualTranchesWithPercentages; + bool actualTransferable; + address expectedAdmin; + uint256 expectedAllowance; + address expectedAsset; + bool expectedCancelable; + string expectedIpfsCID; + uint40 expectedExpiration; + address expectedLockupTranched; + bytes32 expectedMerkleRoot; + bytes32 expectedName; + uint64 expectedTotalPercentage; + MerkleLT.TrancheWithPercentage[] expectedTranchesWithPercentages; + bool expectedTransferable; + } + + function test_Constructor() external { + SablierV2MerkleLT constructedLT = + new SablierV2MerkleLT(defaults.baseParams(), lockupTranched, defaults.tranchesWithPercentages()); + + Vars memory vars; + + vars.actualAdmin = constructedLT.admin(); + vars.expectedAdmin = users.admin; + assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); + + vars.actualAllowance = dai.allowance(address(constructedLT), address(lockupTranched)); + vars.expectedAllowance = MAX_UINT256; + assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); + + vars.actualAsset = address(constructedLT.ASSET()); + vars.expectedAsset = address(dai); + assertEq(vars.actualAsset, vars.expectedAsset, "asset"); + + vars.actualCancelable = constructedLT.CANCELABLE(); + vars.expectedCancelable = defaults.CANCELABLE(); + assertEq(vars.actualCancelable, vars.expectedCancelable, "cancelable"); + + vars.actualExpiration = constructedLT.EXPIRATION(); + vars.expectedExpiration = defaults.EXPIRATION(); + assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); + + vars.actualIpfsCID = constructedLT.ipfsCID(); + vars.expectedIpfsCID = defaults.IPFS_CID(); + assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); + + vars.actualLockupTranched = address(constructedLT.LOCKUP_TRANCHED()); + vars.expectedLockupTranched = address(lockupTranched); + assertEq(vars.actualLockupTranched, vars.expectedLockupTranched, "lockupTranched"); + + vars.actualName = constructedLT.name(); + vars.expectedName = defaults.NAME_BYTES32(); + assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); + + vars.actualMerkleRoot = constructedLT.MERKLE_ROOT(); + vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); + assertEq(vars.actualMerkleRoot, vars.expectedMerkleRoot, "merkleRoot"); + + vars.actualTotalPercentage = constructedLT.TOTAL_PERCENTAGE(); + vars.expectedTotalPercentage = defaults.TOTAL_PERCENTAGE(); + assertEq(vars.actualTotalPercentage, vars.expectedTotalPercentage, "totalPercentage"); + + vars.actualTranchesWithPercentages = constructedLT.getTranchesWithPercentages(); + vars.expectedTranchesWithPercentages = defaults.tranchesWithPercentages(); + assertEq(vars.actualTranchesWithPercentages, vars.expectedTranchesWithPercentages, "tranchesWithPercentages"); + + vars.actualTransferable = constructedLT.TRANSFERABLE(); + vars.expectedTransferable = defaults.TRANSFERABLE(); + assertEq(vars.actualTransferable, vars.expectedTransferable, "transferable"); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol new file mode 100644 index 000000000..3e286f81c --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_GetFirstClaimTime_BeforeFirstClaim() external view { + uint256 firstClaimTime = merkleLT.getFirstClaimTime(); + assertEq(firstClaimTime, 0); + } + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function test_GetFirstClaimTime() external afterFirstClaim { + uint256 firstClaimTime = merkleLT.getFirstClaimTime(); + assertEq(firstClaimTime, block.timestamp); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree new file mode 100644 index 000000000..cab778426 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree @@ -0,0 +1,5 @@ +getFirstClaimTime.t.sol +├── when the first claim has not been made +│ └── it should return 0 +└── when the first claim has been made + └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol new file mode 100644 index 000000000..54b13ac60 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract HasClaimed_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_HasClaimed_IndexNotInTree() external { + uint256 indexNotInTree = 1337e18; + assertFalse(merkleLT.hasClaimed(indexNotInTree), "claimed"); + } + + modifier whenIndexInTree() { + _; + } + + function test_HasClaimed_NotClaimed() external whenIndexInTree { + assertFalse(merkleLT.hasClaimed(defaults.INDEX1()), "claimed"); + } + + modifier givenRecipientHasClaimed() { + claimLT(); + _; + } + + function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { + assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree new file mode 100644 index 000000000..dcbcafe7a --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree @@ -0,0 +1,8 @@ +hasClaimed.t.sol +├── when the index is not in the Merkle tree +│ └── it should return false +└── when the index is in the Merkle tree + ├── given the recipient has not claimed + │ └── it should return false + └── given the recipient has claimed + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol new file mode 100644 index 000000000..a13724264 --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; + +import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; + +contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { + function setUp() public virtual override { + MerkleLockup_Integration_Test.setUp(); + } + + function test_HasExpired_ExpirationZero() external { + ISablierV2MerkleLT testLockup = createMerkleLT({ expiration: 0 }); + assertFalse(testLockup.hasExpired(), "campaign expired"); + } + + modifier givenExpirationNotZero() { + _; + } + + function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { + assertFalse(merkleLT.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() }); + assertTrue(merkleLT.hasExpired(), "campaign not expired"); + } + + function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + assertTrue(merkleLT.hasExpired(), "campaign not expired"); + } +} diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree new file mode 100644 index 000000000..2a359a81e --- /dev/null +++ b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree @@ -0,0 +1,10 @@ +hasExpired.t.sol +├── given the expiration is zero +│ └── it should return false +└── given the expiration is not zero + ├── given the expiration is less than the block timestamp + │ └── it should return false + ├── given the expiration is equal to the block timestamp + │ └── it should return true + └── given the expiration is greater than the block timestamp + └── it should return true diff --git a/test/periphery/mocks/erc20/ERC20Mock.sol b/test/periphery/mocks/erc20/ERC20Mock.sol new file mode 100644 index 000000000..8cf2389dd --- /dev/null +++ b/test/periphery/mocks/erc20/ERC20Mock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) { } +} diff --git a/test/periphery/utils/.npmignore b/test/periphery/utils/.npmignore new file mode 100644 index 000000000..c607d373a --- /dev/null +++ b/test/periphery/utils/.npmignore @@ -0,0 +1 @@ +*.t.sol diff --git a/test/periphery/utils/ArrayBuilder.sol b/test/periphery/utils/ArrayBuilder.sol new file mode 100644 index 000000000..c53ec64e6 --- /dev/null +++ b/test/periphery/utils/ArrayBuilder.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +library ArrayBuilder { + /// @notice Generates an ordered array of integers which starts at `firstStreamId` and ends at `firstStreamId + + /// batchSize - 1`. + function fillStreamIds( + uint256 firstStreamId, + uint256 batchSize + ) + internal + pure + returns (uint256[] memory streamIds) + { + streamIds = new uint256[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + streamIds[i] = firstStreamId + i; + } + } +} diff --git a/test/periphery/utils/Assertions.sol b/test/periphery/utils/Assertions.sol new file mode 100644 index 000000000..2f61dbec4 --- /dev/null +++ b/test/periphery/utils/Assertions.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable event-name-camelcase +pragma solidity >=0.8.22; + +import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; + +import { MerkleLT } from "periphery/types/DataTypes.sol"; + +abstract contract Assertions is PRBMathAssertions { + event log_named_array(string key, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages); + + /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. + function assertEq(MerkleLT.TrancheWithPercentage[] memory a, MerkleLT.TrancheWithPercentage[] memory b) internal { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [MerkleLT.TrancheWithPercentage[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. + function assertEq( + MerkleLT.TrancheWithPercentage[] memory a, + MerkleLT.TrancheWithPercentage[] memory b, + string memory err + ) + internal + { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } +} diff --git a/test/periphery/utils/BaseScript.t.sol b/test/periphery/utils/BaseScript.t.sol new file mode 100644 index 000000000..6fa78951a --- /dev/null +++ b/test/periphery/utils/BaseScript.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { StdAssertions } from "forge-std/src/StdAssertions.sol"; + +import { BaseScript } from "script/Base.s.sol"; + +contract BaseScript_Test is StdAssertions { + using Strings for uint256; + + BaseScript internal baseScript = new BaseScript(); + + function test_ConstructCreate2Salt() public view { + string memory chainId = block.chainid.toString(); + string memory version = "1.2.0"; + string memory salt = string.concat("ChainID ", chainId, ", Version ", version); + + bytes32 actualSalt = baseScript.constructCreate2Salt(); + bytes32 expectedSalt = bytes32(abi.encodePacked(salt)); + assertEq(actualSalt, expectedSalt, "CREATE2 salt mismatch"); + } +} diff --git a/test/periphery/utils/BatchLockupBuilder.sol b/test/periphery/utils/BatchLockupBuilder.sol new file mode 100644 index 000000000..cc2210903 --- /dev/null +++ b/test/periphery/utils/BatchLockupBuilder.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; + +import { BatchLockup } from "../../../src/periphery/types/DataTypes.sol"; + +library BatchLockupBuilder { + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithDurationsLD memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLD[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLD[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLD} structs. + function fillBatch( + LockupDynamic.CreateWithDurations memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLD[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLD[](batchSize); + BatchLockup.CreateWithDurationsLD memory batchSingle = BatchLockup.CreateWithDurationsLD({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + segments: params.segments, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithDurationsLL memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLL[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLL[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLL} structs. + function fillBatch( + LockupLinear.CreateWithDurations memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLL[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLL[](batchSize); + BatchLockup.CreateWithDurationsLL memory batchSingle = BatchLockup.CreateWithDurationsLL({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + durations: params.durations, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithDurationsLT memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLT[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLT[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLT} structs. + function fillBatch( + LockupTranched.CreateWithDurations memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithDurationsLT[] memory batch) + { + batch = new BatchLockup.CreateWithDurationsLT[](batchSize); + BatchLockup.CreateWithDurationsLT memory batchSingle = BatchLockup.CreateWithDurationsLT({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + tranches: params.tranches, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithTimestampsLD memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLD[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLD[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLDs} structs. + function fillBatch( + LockupDynamic.CreateWithTimestamps memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLD[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLD[](batchSize); + BatchLockup.CreateWithTimestampsLD memory batchSingle = BatchLockup.CreateWithTimestampsLD({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + startTime: params.startTime, + segments: params.segments, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithTimestampsLL memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLL[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLL[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLL} structs. + function fillBatch( + LockupLinear.CreateWithTimestamps memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLL[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLL[](batchSize); + BatchLockup.CreateWithTimestampsLL memory batchSingle = BatchLockup.CreateWithTimestampsLL({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + timestamps: params.timestamps, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + BatchLockup.CreateWithTimestampsLT memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLT[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLT[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLT} structs. + function fillBatch( + LockupTranched.CreateWithTimestamps memory params, + uint256 batchSize + ) + internal + pure + returns (BatchLockup.CreateWithTimestampsLT[] memory batch) + { + batch = new BatchLockup.CreateWithTimestampsLT[](batchSize); + BatchLockup.CreateWithTimestampsLT memory batchSingle = BatchLockup.CreateWithTimestampsLT({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + startTime: params.startTime, + tranches: params.tranches, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } +} diff --git a/test/periphery/utils/Defaults.sol b/test/periphery/utils/Defaults.sol new file mode 100644 index 000000000..318fce80b --- /dev/null +++ b/test/periphery/utils/Defaults.sol @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ud2x18, uUNIT } from "@prb/math/src/UD2x18.sol"; +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { Broker, LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; + +import { BatchLockup, MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; + +import { ArrayBuilder } from "./ArrayBuilder.sol"; +import { BatchLockupBuilder } from "./BatchLockupBuilder.sol"; +import { Merkle } from "./Murky.sol"; +import { MerkleBuilder } from "./MerkleBuilder.sol"; +import { Users } from "./Types.sol"; + +/// @notice Contract with default values for testing. +contract Defaults is Merkle { + using MerkleBuilder for uint256[]; + + /*////////////////////////////////////////////////////////////////////////// + GENERICS + //////////////////////////////////////////////////////////////////////////*/ + + uint64 public constant BATCH_SIZE = 10; + UD60x18 public constant BROKER_FEE = UD60x18.wrap(0); + uint40 public constant CLIFF_DURATION = 2500 seconds; + uint40 public immutable CLIFF_TIME; + uint40 public immutable END_TIME; + uint256 public constant ETHER_AMOUNT = 10_000 ether; + uint128 public constant PER_STREAM_AMOUNT = 10_000e18; + uint128 public constant REFUND_AMOUNT = 7500e18; // deposit - cliff amount + uint40 public immutable START_TIME; + uint40 public constant TOTAL_DURATION = 10_000 seconds; + uint128 public constant TOTAL_TRANSFER_AMOUNT = PER_STREAM_AMOUNT * uint128(BATCH_SIZE); + uint128 public constant WITHDRAW_AMOUNT = 2500e18; + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + uint256 public constant AGGREGATE_AMOUNT = CLAIM_AMOUNT * RECIPIENT_COUNT; + bool public constant CANCELABLE = false; + uint128 public constant CLAIM_AMOUNT = 10_000e18; + uint40 public immutable EXPIRATION; + uint40 public immutable FIRST_CLAIM_TIME; + uint256 public constant INDEX1 = 1; + uint256 public constant INDEX2 = 2; + uint256 public constant INDEX3 = 3; + uint256 public constant INDEX4 = 4; + string public constant IPFS_CID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; + uint256[] public LEAVES = new uint256[](RECIPIENT_COUNT); + uint256 public constant RECIPIENT_COUNT = 4; + bytes32 public immutable MERKLE_ROOT; + string public constant NAME = "Airdrop Campaign"; + bytes32 public constant NAME_BYTES32 = bytes32(abi.encodePacked("Airdrop Campaign")); + uint64 public constant TOTAL_PERCENTAGE = uUNIT; + bool public constant TRANSFERABLE = false; + + /*////////////////////////////////////////////////////////////////////////// + VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + IERC20 private asset; + Users private users; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor(Users memory users_, IERC20 asset_) { + users = users_; + asset = asset_; + + // Initialize the immutables. + START_TIME = uint40(block.timestamp) + 100 seconds; + CLIFF_TIME = START_TIME + CLIFF_DURATION; + END_TIME = START_TIME + TOTAL_DURATION; + EXPIRATION = uint40(block.timestamp) + 12 weeks; + FIRST_CLAIM_TIME = uint40(block.timestamp); + + // Initialize the Merkle tree. + LEAVES[0] = MerkleBuilder.computeLeaf(INDEX1, users.recipient1, CLAIM_AMOUNT); + LEAVES[1] = MerkleBuilder.computeLeaf(INDEX2, users.recipient2, CLAIM_AMOUNT); + LEAVES[2] = MerkleBuilder.computeLeaf(INDEX3, users.recipient3, CLAIM_AMOUNT); + LEAVES[3] = MerkleBuilder.computeLeaf(INDEX4, users.recipient4, CLAIM_AMOUNT); + MerkleBuilder.sortLeaves(LEAVES); + MERKLE_ROOT = getRoot(LEAVES.toBytes32()); + } + + function getLeaves() public view returns (uint256[] memory) { + return LEAVES; + } + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + function index1Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX1, users.recipient1, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index2Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX2, users.recipient2, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index3Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX3, users.recipient3, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index4Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX4, users.recipient4, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function baseParams() public view returns (MerkleLockup.ConstructorParams memory) { + return baseParams(users.admin, asset, EXPIRATION, MERKLE_ROOT); + } + + function baseParams( + address admin, + IERC20 asset_, + uint40 expiration, + bytes32 merkleRoot + ) + public + pure + returns (MerkleLockup.ConstructorParams memory) + { + return MerkleLockup.ConstructorParams({ + asset: asset_, + cancelable: CANCELABLE, + expiration: expiration, + initialAdmin: admin, + ipfsCID: IPFS_CID, + merkleRoot: merkleRoot, + name: NAME, + transferable: TRANSFERABLE + }); + } + + function tranchesWithPercentages() + public + pure + returns (MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages_) + { + tranchesWithPercentages_ = new MerkleLT.TrancheWithPercentage[](2); + tranchesWithPercentages_[0] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.25e18), duration: 2500 seconds }); + tranchesWithPercentages_[1] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.75e18), duration: 7500 seconds }); + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + function assets() public view returns (IERC20[] memory assets_) { + assets_ = new IERC20[](1); + assets_[0] = asset; + } + + function broker() public view returns (Broker memory) { + return Broker({ account: users.broker, fee: BROKER_FEE }); + } + + function incrementalStreamIds() public pure returns (uint256[] memory streamIds) { + return ArrayBuilder.fillStreamIds({ firstStreamId: 1, batchSize: BATCH_SIZE }); + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-DYNAMIC + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { + return createWithDurationsLD(asset, PER_STREAM_AMOUNT, segmentsWithDurations()); + } + + function createWithDurationsLD( + IERC20 asset_, + uint128 totalAmount_, + LockupDynamic.SegmentWithDuration[] memory segments_ + ) + public + view + returns (LockupDynamic.CreateWithDurations memory) + { + return LockupDynamic.CreateWithDurations({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: totalAmount_, + asset: asset_, + cancelable: true, + transferable: true, + segments: segments_, + broker: broker() + }); + } + + function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { + return createWithTimestampsLD(asset, PER_STREAM_AMOUNT, segments()); + } + + function createWithTimestampsLD( + IERC20 asset_, + uint128 totalAmount_, + LockupDynamic.Segment[] memory segments_ + ) + public + view + returns (LockupDynamic.CreateWithTimestamps memory) + { + return LockupDynamic.CreateWithTimestamps({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: totalAmount_, + asset: asset_, + cancelable: true, + transferable: true, + startTime: START_TIME, + segments: segments_, + broker: broker() + }); + } + + /// @dev Returns a batch of {LockupDynamic.Segment} parameters. + function segments() public view returns (LockupDynamic.Segment[] memory segments_) { + segments_ = new LockupDynamic.Segment[](2); + segments_[0] = LockupDynamic.Segment({ + amount: 2500e18, + exponent: ud2x18(3.14e18), + timestamp: START_TIME + CLIFF_DURATION + }); + segments_[1] = LockupDynamic.Segment({ + amount: 7500e18, + exponent: ud2x18(3.14e18), + timestamp: START_TIME + TOTAL_DURATION + }); + } + + /// @dev Returns a batch of {LockupDynamic.SegmentWithDuration} parameters. + function segmentsWithDurations() public pure returns (LockupDynamic.SegmentWithDuration[] memory) { + return segmentsWithDurations({ amount0: 2500e18, amount1: 7500e18 }); + } + + /// @dev Returns a batch of {LockupDynamic.SegmentWithDuration} parameters. + function segmentsWithDurations( + uint128 amount0, + uint128 amount1 + ) + public + pure + returns (LockupDynamic.SegmentWithDuration[] memory segments_) + { + segments_ = new LockupDynamic.SegmentWithDuration[](2); + segments_[0] = + LockupDynamic.SegmentWithDuration({ amount: amount0, exponent: ud2x18(3.14e18), duration: 2500 seconds }); + segments_[1] = + LockupDynamic.SegmentWithDuration({ amount: amount1, exponent: ud2x18(3.14e18), duration: 7500 seconds }); + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-LINEAR + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { + return createWithDurationsLL(asset); + } + + function createWithDurationsLL(IERC20 asset_) public view returns (LockupLinear.CreateWithDurations memory) { + return LockupLinear.CreateWithDurations({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: PER_STREAM_AMOUNT, + asset: asset_, + cancelable: true, + transferable: true, + durations: durations(), + broker: broker() + }); + } + + function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { + return createWithTimestampsLL(asset); + } + + function createWithTimestampsLL(IERC20 asset_) public view returns (LockupLinear.CreateWithTimestamps memory) { + return LockupLinear.CreateWithTimestamps({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: PER_STREAM_AMOUNT, + asset: asset_, + cancelable: true, + transferable: true, + timestamps: linearTimestamps(), + broker: broker() + }); + } + + function durations() public pure returns (LockupLinear.Durations memory) { + return LockupLinear.Durations({ cliff: CLIFF_DURATION, total: TOTAL_DURATION }); + } + + function linearTimestamps() private view returns (LockupLinear.Timestamps memory) { + return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); + } + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { + return createWithDurationsLT(asset, PER_STREAM_AMOUNT, tranchesWithDurations()); + } + + function createWithDurationsLT( + IERC20 asset_, + uint128 totalAmount_, + LockupTranched.TrancheWithDuration[] memory tranches_ + ) + public + view + returns (LockupTranched.CreateWithDurations memory) + { + return LockupTranched.CreateWithDurations({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: totalAmount_, + asset: asset_, + cancelable: true, + transferable: true, + tranches: tranches_, + broker: broker() + }); + } + + function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { + return createWithTimestampsLT(asset, PER_STREAM_AMOUNT, tranches()); + } + + function createWithTimestampsLT( + IERC20 asset_, + uint128 totalAmount_, + LockupTranched.Tranche[] memory tranches_ + ) + public + view + returns (LockupTranched.CreateWithTimestamps memory) + { + return LockupTranched.CreateWithTimestamps({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: totalAmount_, + asset: asset_, + cancelable: true, + transferable: true, + startTime: START_TIME, + tranches: tranches_, + broker: broker() + }); + } + + function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = new LockupTranched.Tranche[](2); + tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: uint40(block.timestamp) + CLIFF_DURATION }); + tranches_[1] = LockupTranched.Tranche({ amount: 7500e18, timestamp: uint40(block.timestamp) + TOTAL_DURATION }); + } + + /// @dev Mirros the logic from {SablierV2MerkleLT._calculateTranches}. + function tranches(uint128 totalAmount) public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = tranches(); + + uint128 amount0 = ud(totalAmount).mul(tranchesWithPercentages()[0].unlockPercentage.intoUD60x18()).intoUint128(); + uint128 amount1 = ud(totalAmount).mul(tranchesWithPercentages()[1].unlockPercentage.intoUD60x18()).intoUint128(); + + tranches_[0].amount = amount0; + tranches_[1].amount = amount1; + + uint128 amountsSum = amount0 + amount1; + + if (amountsSum != totalAmount) { + tranches_[1].amount += totalAmount - amountsSum; + } + } + + /// @dev Returns a batch of {LockupTranched.TrancheWithDuration} parameters. + function tranchesWithDurations() public pure returns (LockupTranched.TrancheWithDuration[] memory) { + return tranchesWithDurations({ amount0: 2500e18, amount1: 7500e18 }); + } + + /// @dev Returns a batch of {LockupTranched.TrancheWithDuration} parameters. + function tranchesWithDurations( + uint128 amount0, + uint128 amount1 + ) + public + pure + returns (LockupTranched.TrancheWithDuration[] memory segments_) + { + segments_ = new LockupTranched.TrancheWithDuration[](2); + segments_[0] = LockupTranched.TrancheWithDuration({ amount: amount0, duration: 2500 seconds }); + segments_[1] = LockupTranched.TrancheWithDuration({ amount: amount1, duration: 7500 seconds }); + } + + /*////////////////////////////////////////////////////////////////////////// + BATCH-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLD} parameters. + function batchCreateWithDurationsLD() public view returns (BatchLockup.CreateWithDurationsLD[] memory batch) { + batch = BatchLockupBuilder.fillBatch(createWithDurationsLD(), BATCH_SIZE); + } + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLL} parameters. + function batchCreateWithDurationsLL() public view returns (BatchLockup.CreateWithDurationsLL[] memory batch) { + batch = BatchLockupBuilder.fillBatch(createWithDurationsLL(), BATCH_SIZE); + } + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLT} parameters. + function batchCreateWithDurationsLT() public view returns (BatchLockup.CreateWithDurationsLT[] memory batch) { + batch = BatchLockupBuilder.fillBatch(createWithDurationsLT(), BATCH_SIZE); + } + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLD} parameters. + function batchCreateWithTimestampsLD() public view returns (BatchLockup.CreateWithTimestampsLD[] memory batch) { + batch = batchCreateWithTimestampsLD(BATCH_SIZE); + } + + /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLD} parameters. + function batchCreateWithTimestampsLD(uint256 batchSize) + public + view + returns (BatchLockup.CreateWithTimestampsLD[] memory batch) + { + batch = BatchLockupBuilder.fillBatch(createWithTimestampsLD(), batchSize); + } + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLL} parameters. + function batchCreateWithTimestampsLL() public view returns (BatchLockup.CreateWithTimestampsLL[] memory batch) { + batch = batchCreateWithTimestampsLL(BATCH_SIZE); + } + + /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLL} parameters. + function batchCreateWithTimestampsLL(uint256 batchSize) + public + view + returns (BatchLockup.CreateWithTimestampsLL[] memory batch) + { + batch = BatchLockupBuilder.fillBatch(createWithTimestampsLL(), batchSize); + } + + /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLT} parameters. + function batchCreateWithTimestampsLT() public view returns (BatchLockup.CreateWithTimestampsLT[] memory batch) { + batch = batchCreateWithTimestampsLT(BATCH_SIZE); + } + + /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLL} parameters. + function batchCreateWithTimestampsLT(uint256 batchSize) + public + view + returns (BatchLockup.CreateWithTimestampsLT[] memory batch) + { + batch = BatchLockupBuilder.fillBatch(createWithTimestampsLT(), batchSize); + } +} diff --git a/test/periphery/utils/DeployOptimized.sol b/test/periphery/utils/DeployOptimized.sol new file mode 100644 index 000000000..1eb192765 --- /dev/null +++ b/test/periphery/utils/DeployOptimized.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { StdCheats } from "forge-std/src/StdCheats.sol"; + +import { ISablierV2BatchLockup } from "../../../src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLockupFactory } from "../../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; + +abstract contract DeployOptimized is StdCheats { + /// @dev Deploys {SablierV2BatchLockup} from an optimized source compiled with `--via-ir`. + function deployOptimizedBatchLockup() internal returns (ISablierV2BatchLockup) { + return ISablierV2BatchLockup(deployCode("out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json")); + } + + /// @dev Deploys {SablierV2MerkleLockupFactory} from an optimized source compiled with `--via-ir`. + function deployOptimizedMerkleLockupFactory() internal returns (ISablierV2MerkleLockupFactory) { + return ISablierV2MerkleLockupFactory( + deployCode("out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json") + ); + } + + /// @notice Deploys all V2 Periphery contracts from an optimized source in the following order: + /// + /// 1. {SablierV2BatchLockup} + /// 2. {SablierV2MerkleLockupFactory} + function deployOptimizedPeriphery() internal returns (ISablierV2BatchLockup, ISablierV2MerkleLockupFactory) { + return (deployOptimizedBatchLockup(), deployOptimizedMerkleLockupFactory()); + } +} diff --git a/test/periphery/utils/Events.sol b/test/periphery/utils/Events.sol new file mode 100644 index 000000000..aad3d28da --- /dev/null +++ b/test/periphery/utils/Events.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { LockupLinear } from "core/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; + +import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; + +/// @notice Abstract contract containing all the events emitted by the protocol. +abstract contract Events { + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); + event Clawback(address indexed admin, address indexed to, uint128 amount); + event CreateMerkleLL( + ISablierV2MerkleLL indexed merkleLL, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations streamDurations, + uint256 aggregateAmount, + uint256 recipientCount + ); + event CreateMerkleLT( + ISablierV2MerkleLT indexed merkleLT, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, + uint256 totalDuration, + uint256 aggregateAmount, + uint256 recipientCount + ); +} diff --git a/test/periphery/utils/MerkleBuilder.sol b/test/periphery/utils/MerkleBuilder.sol new file mode 100644 index 000000000..ad6bb0c20 --- /dev/null +++ b/test/periphery/utils/MerkleBuilder.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// solhint-disable reason-string +pragma solidity >=0.8.22; + +import { LibSort } from "solady/src/utils/LibSort.sol"; + +/// @dev A helper library for building Merkle leaves, roots, and proofs. +library MerkleBuilder { + /// @dev Function that double hashes the data needed for a Merkle tree leaf. + function computeLeaf(uint256 index, address recipient, uint128 amount) internal pure returns (uint256 leaf) { + leaf = uint256(keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount))))); + } + + /// @dev A batch function for `computeLeaf`. + function computeLeaves( + uint256[] memory indexes, + address[] memory recipient, + uint128[] memory amount + ) + internal + pure + returns (uint256[] memory leaves) + { + uint256 count = indexes.length; + require(count == recipient.length && count == amount.length, "Merkle leaves arrays must have the same length"); + leaves = new uint256[](count); + for (uint256 i = 0; i < count; ++i) { + leaves[i] = computeLeaf(indexes[i], recipient[i], amount[i]); + } + } + + /// @dev Function that convert a storage array to memory and sorts it in ascending order. We need this + /// because `LibSort` does not support storage arrays. + function sortLeaves(uint256[] storage leaves) internal { + uint256 leavesCount = leaves.length; + + // Declare the memory array. + uint256[] memory _leaves = new uint256[](leavesCount); + for (uint256 i = 0; i < leavesCount; ++i) { + _leaves[i] = leaves[i]; + } + + // Sort the memory array. + LibSort.sort(_leaves); + + // Copy the memory array back to storage. + for (uint256 i = 0; i < leavesCount; ++i) { + leaves[i] = _leaves[i]; + } + } + + /// @dev Function that converts an array of `uint256` to an array of `bytes32`. + function toBytes32(uint256[] storage arr_) internal view returns (bytes32[] memory arr) { + arr = new bytes32[](arr_.length); + for (uint256 i = 0; i < arr_.length; ++i) { + arr[i] = bytes32(arr_[i]); + } + } +} diff --git a/test/periphery/utils/MerkleBuilder.t.sol b/test/periphery/utils/MerkleBuilder.t.sol new file mode 100644 index 000000000..ff6700857 --- /dev/null +++ b/test/periphery/utils/MerkleBuilder.t.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { StdAssertions } from "forge-std/src/StdAssertions.sol"; +import { StdUtils } from "forge-std/src/StdUtils.sol"; + +import { MerkleBuilder } from "./MerkleBuilder.sol"; + +contract MerkleBuilder_Test is StdAssertions, StdUtils { + function testFuzz_ComputeLeaf(uint256 index, address recipient, uint128 amount) external pure { + uint256 actualLeaf = MerkleBuilder.computeLeaf(index, recipient, amount); + uint256 expectedLeaf = uint256(keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount))))); + assertEq(actualLeaf, expectedLeaf, "computeLeaf"); + } + + /// @dev We declare this struct so that we will not need cheatcodes in the `computeLeaves` test. + struct LeavesParams { + uint256 indexes; + address recipients; + uint128 amounts; + } + + function testFuzz_ComputeLeaves(LeavesParams[] memory params) external pure { + uint256 count = params.length; + + uint256[] memory indexes = new uint256[](count); + address[] memory recipients = new address[](count); + uint128[] memory amounts = new uint128[](count); + for (uint256 i = 0; i < count; ++i) { + indexes[i] = params[i].indexes; + recipients[i] = params[i].recipients; + amounts[i] = params[i].amounts; + } + + uint256[] memory actualLeaves = new uint256[](count); + actualLeaves = MerkleBuilder.computeLeaves(indexes, recipients, amounts); + + uint256[] memory expectedLeaves = new uint256[](count); + for (uint256 i = 0; i < count; ++i) { + expectedLeaves[i] = + uint256(keccak256(bytes.concat(keccak256(abi.encode(indexes[i], recipients[i], amounts[i]))))); + } + + assertEq(actualLeaves, expectedLeaves, "computeLeaves"); + } +} diff --git a/test/periphery/utils/Murky.sol b/test/periphery/utils/Murky.sol new file mode 100644 index 000000000..df29f9a4f --- /dev/null +++ b/test/periphery/utils/Murky.sol @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: MIT +// solhint-disable code-complexity,no-inline-assembly,reason-string +pragma solidity >=0.8.22; + +/// @dev Credits to https://github.com/dmfxyz/murky +abstract contract MurkyBase { + /** + * + * CONSTRUCTOR * + * + */ + constructor() { } + + /** + * + * VIRTUAL HASHING FUNCTIONS * + * + */ + function hashLeafPairs(bytes32 left, bytes32 right) public pure virtual returns (bytes32 _hash); + + /** + * + * PROOF VERIFICATION * + * + */ + function verifyProof(bytes32 root, bytes32[] memory proof, bytes32 valueToProve) external pure returns (bool) { + // proof length must be less than max array size + bytes32 rollingHash = valueToProve; + uint256 length = proof.length; + unchecked { + for (uint256 i = 0; i < length; ++i) { + rollingHash = hashLeafPairs(rollingHash, proof[i]); + } + } + return root == rollingHash; + } + + /** + * + * PROOF GENERATION * + * + */ + function getRoot(bytes32[] memory data) public pure returns (bytes32) { + require(data.length > 1, "won't generate root for single leaf"); + while (data.length > 1) { + data = hashLevel(data); + } + return data[0]; + } + + function getProof(bytes32[] memory data, uint256 node) public pure returns (bytes32[] memory) { + require(data.length > 1, "won't generate proof for single leaf"); + // The size of the proof is equal to the ceiling of log2(numLeaves) + bytes32[] memory result = new bytes32[](log2ceilBitMagic(data.length)); + uint256 pos = 0; + + // Two overflow risks: node, pos + // node: max array size is 2**256-1. Largest index in the array will be 1 less than that. Also, + // for dynamic arrays, size is limited to 2**64-1 + // pos: pos is bounded by log2(data.length), which should be less than type(uint256).max + while (data.length > 1) { + unchecked { + if (node & 0x1 == 1) { + result[pos] = data[node - 1]; + } else if (node + 1 == data.length) { + result[pos] = bytes32(0); + } else { + result[pos] = data[node + 1]; + } + ++pos; + node /= 2; + } + data = hashLevel(data); + } + return result; + } + + ///@dev function is private to prevent unsafe data from being passed + function hashLevel(bytes32[] memory data) private pure returns (bytes32[] memory) { + bytes32[] memory result; + + // Function is private, and all internal callers check that data.length >=2. + // Underflow is not possible as lowest possible value for data/result index is 1 + // overflow should be safe as length is / 2 always. + unchecked { + uint256 length = data.length; + if (length & 0x1 == 1) { + result = new bytes32[](length / 2 + 1); + result[result.length - 1] = hashLeafPairs(data[length - 1], bytes32(0)); + } else { + result = new bytes32[](length / 2); + } + // pos is upper bounded by data.length / 2, so safe even if array is at max size + uint256 pos = 0; + for (uint256 i = 0; i < length - 1; i += 2) { + result[pos] = hashLeafPairs(data[i], data[i + 1]); + ++pos; + } + } + return result; + } + + /** + * + * MATH "LIBRARY" * + * + */ + + /// @dev Note that x is assumed > 0 + function log2ceil(uint256 x) public pure returns (uint256) { + uint256 ceil = 0; + uint256 pOf2; + // If x is a power of 2, then this function will return a ceiling + // that is 1 greater than the actual ceiling. So we need to check if + // x is a power of 2, and subtract one from ceil if so. + assembly { + // we check by seeing if x == (~x + 1) & x. This applies a mask + // to find the lowest set bit of x and then checks it for equality + // with x. If they are equal, then x is a power of 2. + + /* Example + x has single bit set + x := 0000_1000 + (~x + 1) = (1111_0111) + 1 = 1111_1000 + (1111_1000 & 0000_1000) = 0000_1000 == x + + x has multiple bits set + x := 1001_0010 + (~x + 1) = (0110_1101 + 1) = 0110_1110 + (0110_1110 & x) = 0000_0010 != x + */ + + // we do some assembly magic to treat the bool as an integer later on + pOf2 := eq(and(add(not(x), 1), x), x) + } + + // if x == type(uint256).max, than ceil is capped at 256 + // if x == 0, then pO2 == 0, so ceil won't underflow + unchecked { + while (x > 0) { + x >>= 1; + ceil++; + } + ceil -= pOf2; // see above + } + return ceil; + } + + /// Original bitmagic adapted from https://github.com/paulrberg/prb-math/blob/main/contracts/PRBMath.sol + /// @dev Note that x assumed > 1 + function log2ceilBitMagic(uint256 x) public pure returns (uint256) { + if (x <= 1) { + return 0; + } + uint256 msb = 0; + uint256 _x = x; + if (x >= 2 ** 128) { + x >>= 128; + msb += 128; + } + if (x >= 2 ** 64) { + x >>= 64; + msb += 64; + } + if (x >= 2 ** 32) { + x >>= 32; + msb += 32; + } + if (x >= 2 ** 16) { + x >>= 16; + msb += 16; + } + if (x >= 2 ** 8) { + x >>= 8; + msb += 8; + } + if (x >= 2 ** 4) { + x >>= 4; + msb += 4; + } + if (x >= 2 ** 2) { + x >>= 2; + msb += 2; + } + if (x >= 2 ** 1) { + msb += 1; + } + + uint256 lsb = (~_x + 1) & _x; + if ((lsb == _x) && (msb > 0)) { + return msb; + } else { + return msb + 1; + } + } +} + +/// @notice Nascent, simple, kinda efficient (and improving!) Merkle proof generator and verifier +/// @author dmfxyz +/// @dev Note Generic Merkle Tree +contract Merkle is MurkyBase { + /** + * + * HASHING FUNCTION * + * + */ + + /// ascending sort and concat prior to hashing + function hashLeafPairs(bytes32 left, bytes32 right) public pure override returns (bytes32 _hash) { + assembly { + switch lt(left, right) + case 0 { + mstore(0x0, right) + mstore(0x20, left) + } + default { + mstore(0x0, left) + mstore(0x20, right) + } + _hash := keccak256(0x0, 0x40) + } + } +} diff --git a/test/periphery/utils/Precompiles.t.sol b/test/periphery/utils/Precompiles.t.sol new file mode 100644 index 000000000..f296d6aff --- /dev/null +++ b/test/periphery/utils/Precompiles.t.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Precompiles } from "precompiles/Precompiles.sol"; +import { ISablierV2BatchLockup } from "periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLockupFactory } from "periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; + +import { Base_Test } from "../Base.t.sol"; + +contract Precompiles_Test is Base_Test { + Precompiles internal precompiles = new Precompiles(); + + modifier onlyTestOptimizedProfile() { + if (isTestOptimizedProfile()) { + _; + } + } + + function test_DeployBatchLockup() external onlyTestOptimizedProfile { + address actualBatchLockup = address(precompiles.deployBatchLockup()); + address expectedBatchLockup = address(deployOptimizedBatchLockup()); + assertEq(actualBatchLockup.code, expectedBatchLockup.code, "bytecodes mismatch"); + } + + function test_DeployMerkleLockupFactory() external onlyTestOptimizedProfile { + address actualFactory = address(precompiles.deployMerkleLockupFactory()); + address expectedFactory = address(deployOptimizedMerkleLockupFactory()); + assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); + } + + function test_DeployPeriphery() external onlyTestOptimizedProfile { + (ISablierV2BatchLockup actualBatchLockup, ISablierV2MerkleLockupFactory actualMerkleLockupFactory) = + precompiles.deployPeriphery(); + + (ISablierV2BatchLockup expectedBatchLockup, ISablierV2MerkleLockupFactory expectedMerkleLockupFactory) = + deployOptimizedPeriphery(); + + assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); + assertEq( + address(actualMerkleLockupFactory).code, address(expectedMerkleLockupFactory).code, "bytecodes mismatch" + ); + } +} diff --git a/test/periphery/utils/Types.sol b/test/periphery/utils/Types.sol new file mode 100644 index 000000000..39fdda5af --- /dev/null +++ b/test/periphery/utils/Types.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +struct Users { + address alice; + address admin; + address broker; + address eve; + address recipient0; + address recipient1; + address recipient2; + address recipient3; + address recipient4; +} From 7b8dce267ad1f7b35c6db565f501784d7e18a0a5 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 29 Jul 2024 14:06:16 +0100 Subject: [PATCH 05/34] test: add a common utils dir refactor: precompile constants test: merge Base_Test contracts for both core and periphery test: add Periphery_Test contract test: add params for create with null broker test: use broker null param functions in batch test: update the starting timestamp test: use recipient0 in core tests test: fix periphery tests test: use recipient0 in core tests test: add an init merkle tree function test: add tranches functions for merkle lockup test: remove unneeded brokerFee declarations test(periphery-fork): use null broker in batch test(fork): make the admin the caller to fix merkle tests test: add caller param in computeMerkleAddress function refactor: remove core and periphery remappings test: replace block.timestamp with getBlockTimestamp test: remove unused imports Co-authored-by: PaulRBerg Co-authored-by: andreivladbrg --- precompiles/Precompiles.sol | 23 +- remappings.txt | 4 +- test/{core => }/Base.t.sol | 67 +- test/core/fork/Fork.t.sol | 2 +- test/core/fork/LockupDynamic.t.sol | 2 +- test/core/fork/LockupLinear.t.sol | 2 +- test/core/fork/LockupTranched.t.sol | 2 +- test/core/fork/NFTDescriptor.t.sol | 4 +- test/core/integration/Integration.t.sol | 39 +- .../lockup-dynamic/LockupDynamic.t.sol | 2 +- .../concrete/lockup-dynamic/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 10 +- .../createWithTimestamps.t.sol | 16 +- .../get-segments/getSegments.t.sol | 4 +- .../lockup-dynamic/get-stream/getStream.t.sol | 4 +- .../get-timestamps/getTimestamps.t.sol | 4 +- .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../withdrawableAmountOf.t.sol | 2 +- .../concrete/lockup-linear/LockupLinear.t.sol | 2 +- .../concrete/lockup-linear/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 10 +- .../createWithTimestamps.t.sol | 12 +- .../get-cliff-time/getCliffTime.t.sol | 2 +- .../lockup-linear/get-stream/getStream.t.sol | 4 +- .../get-timestamps/getTimestamps.t.sol | 4 +- .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../withdrawableAmountOf.t.sol | 2 +- .../lockup-tranched/LockupTranched.t.sol | 2 +- .../lockup-tranched/constructor.t.sol | 2 +- .../createWithDurations.t.sol | 10 +- .../createWithTimestamps.t.sol | 16 +- .../get-stream/getStream.t.sol | 4 +- .../get-timestamps/getTimestamps.t.sol | 4 +- .../get-tranches/getTranches.t.sol | 4 +- .../withdrawableAmountOf.t.sol | 2 +- .../lockup/allow-to-hook/allowToHook.t.sol | 2 +- .../concrete/lockup/burn/burn.t.sol | 10 +- .../cancel-multiple/cancelMultiple.t.sol | 20 +- .../concrete/lockup/cancel/cancel.t.sol | 14 +- .../concrete/lockup/get-asset/getAsset.t.sol | 2 +- .../getDepositedAmount.t.sol | 2 +- .../lockup/get-end-time/getEndTime.t.sol | 2 +- .../lockup/get-recipient/getRecipient.t.sol | 6 +- .../getRefundedAmount.t.sol | 6 +- .../lockup/get-sender/getSender.t.sol | 2 +- .../lockup/get-start-time/getStartTime.t.sol | 2 +- .../getWithdrawnAmount.t.sol | 4 +- .../lockup/is-cancelable/isCancelable.t.sol | 2 +- .../concrete/lockup/is-cold/isCold.t.sol | 4 +- .../lockup/is-depleted/isDepleted.t.sol | 4 +- .../is-transferable/isTransferable.t.sol | 2 +- .../concrete/lockup/is-warm/isWarm.t.sol | 4 +- .../refundableAmountOf.t.sol | 6 +- .../concrete/lockup/renounce/renounce.t.sol | 6 +- .../set-nft-descriptor/setNFTDescriptor.t.sol | 6 +- .../concrete/lockup/status-of/statusOf.t.sol | 6 +- .../streamed-amount-of/streamedAmountOf.t.sol | 6 +- .../lockup/transfer-from/transferFrom.t.sol | 10 +- .../lockup/was-canceled/wasCanceled.t.sol | 2 +- .../lockup/withdraw-hooks/withdrawHooks.t.sol | 2 +- .../withdrawMaxAndTransfer.t.sol | 20 +- .../lockup/withdraw-max/withdrawMax.t.sol | 16 +- .../withdraw-multiple/withdrawMultiple.t.sol | 28 +- .../concrete/lockup/withdraw/withdraw.t.sol | 40 +- .../withdrawableAmountOf.t.sol | 6 +- .../nft-descriptor/generateAccentColor.t.sol | 2 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 2 +- .../safe-asset-symbol/safeAssetSymbol.t.sol | 4 +- .../fuzz/lockup-dynamic/LockupDynamic.t.sol | 2 +- .../lockup-dynamic/createWithDurations.t.sol | 10 +- .../lockup-dynamic/createWithTimestamps.t.sol | 10 +- .../lockup-dynamic/streamedAmountOf.t.sol | 21 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 6 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 38 +- .../fuzz/lockup-linear/LockupLinear.t.sol | 2 +- .../lockup-linear/createWithDurations.t.sol | 8 +- .../lockup-linear/createWithTimestamps.t.sol | 4 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 15 +- .../lockup-linear/withdrawableAmountOf.t.sol | 34 +- .../fuzz/lockup-tranched/LockupTranched.t.sol | 2 +- .../lockup-tranched/createWithDurations.t.sol | 8 +- .../createWithTimestamps.t.sol | 10 +- .../lockup-tranched/streamedAmountOf.t.sol | 4 +- .../fuzz/lockup-tranched/withdraw.t.sol | 6 +- .../withdrawableAmountOf.t.sol | 24 +- .../core/integration/fuzz/lockup/cancel.t.sol | 2 +- .../fuzz/lockup/cancelMultiple.t.sol | 8 +- .../fuzz/lockup/getWithdrawnAmount.t.sol | 2 +- .../integration/fuzz/lockup/withdraw.t.sol | 12 +- .../integration/fuzz/lockup/withdrawMax.t.sol | 16 +- .../fuzz/lockup/withdrawMaxAndTransfer.t.sol | 6 +- .../fuzz/lockup/withdrawMultiple.t.sol | 14 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 6 +- .../shared/lockup-linear/LockupLinear.t.sol | 2 +- .../lockup-tranched/LockupTranched.t.sol | 6 +- .../integration/shared/lockup/Lockup.t.sol | 9 +- .../shared/lockup/getWithdrawnAmount.t.sol | 2 +- .../integration/shared/lockup/withdraw.t.sol | 2 +- .../shared/lockup/withdrawMax.t.sol | 2 +- .../lockup/withdrawMaxAndTransfer.t.sol | 2 +- .../shared/lockup/withdrawMultiple.t.sol | 6 +- .../shared/nft-descriptor/NFTDescriptor.t.sol | 2 +- test/core/invariant/Invariant.t.sol | 2 +- test/core/invariant/Lockup.t.sol | 4 +- test/core/invariant/LockupDynamic.t.sol | 2 +- test/core/invariant/LockupLinear.t.sol | 2 +- test/core/invariant/LockupTranched.t.sol | 2 +- test/core/invariant/handlers/BaseHandler.sol | 6 +- .../handlers/LockupDynamicCreateHandler.sol | 4 +- .../handlers/LockupDynamicHandler.sol | 2 +- .../core/invariant/handlers/LockupHandler.sol | 4 +- .../handlers/LockupLinearCreateHandler.sol | 4 +- .../handlers/LockupLinearHandler.sol | 2 +- .../handlers/LockupTranchedCreateHandler.sol | 4 +- .../handlers/LockupTranchedHandler.sol | 2 +- test/core/invariant/stores/LockupStore.sol | 2 +- .../transfer-admin/transferAdmin.t.sol | 2 +- .../nft-descriptor/NFTDescriptor.t.sol | 6 +- .../nft-descriptor/abbreviateAmount.t.sol | 2 +- .../calculateDurationInDays.t.sol | 14 +- .../concrete/nft-descriptor/generateSVG.t.sol | 4 +- .../concrete/nft-descriptor/hourglass.t.sol | 2 +- .../nft-descriptor/stringifyCardType.t.sol | 2 +- .../nft-descriptor/stringifyStatus.t.sol | 2 +- test/core/unit/fuzz/transferAdmin.t.sol | 2 +- test/core/unit/shared/Adminable.t.sol | 4 +- test/core/utils/Defaults.sol | 284 --------- test/core/utils/DeployOptimized.sol | 86 --- test/{core => }/mocks/AdminableMock.sol | 4 +- test/{core => }/mocks/Hooks.sol | 4 +- test/{core => }/mocks/NFTDescriptorMock.sol | 8 +- test/{core => }/mocks/Noop.sol | 0 test/{core => }/mocks/erc20/ERC20Bytes32.sol | 0 .../mocks/erc20/ERC20MissingReturn.sol | 0 test/{core => }/mocks/erc20/ERC20Mock.sol | 0 .../periphery/{Base.t.sol => Periphery.t.sol} | 180 +----- test/periphery/fork/Fork.t.sol | 29 +- .../batch-lockup/createWithTimestampsLD.t.sol | 20 +- .../batch-lockup/createWithTimestampsLL.t.sol | 18 +- .../batch-lockup/createWithTimestampsLT.t.sol | 20 +- .../fork/merkle-lockup/MerkleLL.t.sol | 17 +- .../fork/merkle-lockup/MerkleLT.t.sol | 18 +- test/periphery/integration/Integration.t.sol | 42 -- .../createWithDurationsLD.t.sol | 21 +- .../createWithDurationsLL.t.sol | 21 +- .../createWithDurationsLT.t.sol | 21 +- .../createWithTimestampsLD.t.sol | 21 +- .../createWithTimestamps.t.sol | 21 +- .../createWithTimestampsLT.t.sol | 21 +- .../merkle-lockup/MerkleLockup.t.sol | 37 +- .../create-merkle-ll/createMerkleLL.t.sol | 16 +- .../create-merkle-lt/createMerkleLT.t.sol | 13 +- .../isPercentagesSum100.t.sol | 2 +- .../merkle-lockup/ll/claim/claim.t.sol | 5 +- .../merkle-lockup/ll/clawback/clawback.t.sol | 13 +- .../ll/constructor/constructor.t.sol | 5 +- .../getFirstClaimTime.t.sol | 2 +- .../ll/has-expired/hasExpired.t.sol | 2 +- .../merkle-lockup/lt/claim/claim.t.sol | 16 +- .../merkle-lockup/lt/clawback/clawback.t.sol | 13 +- .../lt/constructor/constructor.t.sol | 4 +- .../getFirstClaimTime.t.sol | 2 +- .../lt/has-expired/hasExpired.t.sol | 2 +- test/periphery/mocks/erc20/ERC20Mock.sol | 8 - test/periphery/utils/.npmignore | 1 - test/periphery/utils/Assertions.sol | 35 -- test/periphery/utils/BaseScript.t.sol | 23 - test/periphery/utils/DeployOptimized.sol | 29 - test/periphery/utils/Events.sol | 33 - test/periphery/utils/Precompiles.t.sol | 43 -- test/periphery/utils/Types.sol | 14 - test/{core => }/utils/.npmignore | 0 test/{periphery => }/utils/ArrayBuilder.sol | 0 test/{core => }/utils/Assertions.sol | 35 +- test/{core => }/utils/BaseScript.t.sol | 0 .../utils/BatchLockupBuilder.sol | 4 +- test/{core => }/utils/Calculations.sol | 42 +- test/{core => }/utils/Constants.sol | 2 +- test/{periphery => }/utils/Defaults.sol | 585 ++++++++++-------- test/utils/DeployOptimized.sol | 154 +++++ test/{core => }/utils/Events.sol | 51 +- test/{core => }/utils/Fuzzers.sol | 37 +- test/{periphery => }/utils/MerkleBuilder.sol | 0 .../{periphery => }/utils/MerkleBuilder.t.sol | 0 test/{periphery => }/utils/Murky.sol | 0 test/{core => }/utils/Precompiles.t.sol | 47 +- test/{core => }/utils/Types.sol | 10 +- test/{core => }/utils/Utils.sol | 2 +- 188 files changed, 1327 insertions(+), 1726 deletions(-) rename test/{core => }/Base.t.sol (70%) delete mode 100644 test/core/utils/Defaults.sol delete mode 100644 test/core/utils/DeployOptimized.sol rename test/{core => }/mocks/AdminableMock.sol (65%) rename test/{core => }/mocks/Hooks.sol (96%) rename test/{core => }/mocks/NFTDescriptorMock.sol (92%) rename test/{core => }/mocks/Noop.sol (100%) rename test/{core => }/mocks/erc20/ERC20Bytes32.sol (100%) rename test/{core => }/mocks/erc20/ERC20MissingReturn.sol (100%) rename test/{core => }/mocks/erc20/ERC20Mock.sol (100%) rename test/periphery/{Base.t.sol => Periphery.t.sol} (54%) delete mode 100644 test/periphery/integration/Integration.t.sol delete mode 100644 test/periphery/mocks/erc20/ERC20Mock.sol delete mode 100644 test/periphery/utils/.npmignore delete mode 100644 test/periphery/utils/Assertions.sol delete mode 100644 test/periphery/utils/BaseScript.t.sol delete mode 100644 test/periphery/utils/DeployOptimized.sol delete mode 100644 test/periphery/utils/Events.sol delete mode 100644 test/periphery/utils/Precompiles.t.sol delete mode 100644 test/periphery/utils/Types.sol rename test/{core => }/utils/.npmignore (100%) rename test/{periphery => }/utils/ArrayBuilder.sol (100%) rename test/{core => }/utils/Assertions.sol (86%) rename test/{core => }/utils/BaseScript.t.sol (100%) rename test/{periphery => }/utils/BatchLockupBuilder.sol (98%) rename test/{core => }/utils/Calculations.sol (82%) rename test/{core => }/utils/Constants.sol (89%) rename test/{periphery => }/utils/Defaults.sol (57%) create mode 100644 test/utils/DeployOptimized.sol rename test/{core => }/utils/Events.sol (68%) rename test/{core => }/utils/Fuzzers.sol (94%) rename test/{periphery => }/utils/MerkleBuilder.sol (100%) rename test/{periphery => }/utils/MerkleBuilder.t.sol (100%) rename test/{periphery => }/utils/Murky.sol (100%) rename test/{core => }/utils/Precompiles.t.sol (66%) rename test/{core => }/utils/Types.sol (62%) rename test/{core => }/utils/Utils.sol (97%) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index fa82c23d9..9853f20c3 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -21,22 +21,26 @@ contract Precompiles { CONSTANTS //////////////////////////////////////////////////////////////////////////*/ - uint256 public constant MAX_SEGMENT_COUNT = 500; - uint256 public constant MAX_TRANCHE_COUNT = 500; - - /*////////////////////////////////////////////////////////////////////////// - CORE - //////////////////////////////////////////////////////////////////////////*/ - + bytes public constant BYTECODE_BATCH_LOCKUP = + hex"60808060405234601557611e0a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd3146111a357806349a32c4014610e3e578063606ef87514610b025780639e743f29146107a6578063a514f83e1461040c5763f7ca34eb1461005b575f80fd5b3461033c5761006936611512565b91909282156103e4575f905f5b8481106103b057506001600160a01b036100939116918383611a7a565b61009c83611758565b926001600160a01b035f9316925b8181106100c357604051806100bf8782611587565b0390f35b6100ce818388611a17565b6100d7906117a7565b90826100e482828a611a17565b6020016100f0906117a7565b6100fb83838b611a17565b60400161010790611643565b9389610114858583611a17565b606001610120906117bb565b61012b868684611a17565b608001610137906117bb565b610142878785611a17565b60a00161014e90611a57565b918761015b818987611a17565b60c0810161016891611926565b98610174929196611a17565b60e0019360405195610185876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101ec9261197a565b9360e08601948552366101fe916118c8565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610353575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610312575b6001925061030b8288611901565b52016100aa565b506020823d8211610340575b8161032b602093836116ff565b8101031261033c57600191516102fd565b5f80fd5b3d915061031e565b6040513d5f823e3d90fd5b919493509160206060826103a1600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102be565b916001906fffffffffffffffffffffffffffffffff6103db60406103d5878a8c611a17565b01611643565b16019201610076565b7ff8bf106c000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c576104436115c0565b61044b6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610140870201011161033c5783156103e45790915f9190825b85811061077457506001600160a01b036104be9116928484611a7a565b6104c784611758565b926001600160a01b03165f5b8581106104e857604051806100bf8782611587565b6104fb6104f6828886611a69565b6117a7565b90610512602061050c838a88611a69565b016117a7565b878561052460406103d5868585611a69565b61053a6060610534878686611a69565b016117bb565b906101006105648761055d8188610557608061053484848d611a69565b98611a69565b968c611a69565b01906001600160a01b036040519861057b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c57604051956105fa876116e3565b61060660a08201611839565b875261061460c08201611839565b602088015260e00161062590611839565b604087015260c089019586523661063b916118c8565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff1661010484015251610124830161071291602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610348575f90610742575b6001925061073b8288611901565b52016104d3565b506020823d821161076c575b8161075b602093836116ff565b8101031261033c576001915161072d565b3d915061074e565b93926001906fffffffffffffffffffffffffffffffff61079a60406103d5898b89611a69565b160194019392936104a1565b3461033c576107b436611512565b91909282156103e4575f905f5b848110610ad457506001600160a01b036107de9116918383611a7a565b6107e783611758565b926001600160a01b035f9316925b81811061080a57604051806100bf8782611587565b610815818388611a17565b61081e906117a7565b908261082b82828a611a17565b602001610837906117a7565b61084283838b611a17565b60400161084e90611643565b938961085b858583611a17565b606001610867906117bb565b610872868684611a17565b60800161087e906117bb565b610889878785611a17565b60a00161089590611a57565b91876108a2818987611a17565b60c081016108af916117c8565b986108bb929196611a17565b60e00193604051956108cc876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906109339261184b565b9360e0860194855236610945916118c8565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610a8b575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610a59575b60019250610a528288611901565b52016107f5565b506020823d8211610a83575b81610a72602093836116ff565b8101031261033c5760019151610a44565b3d9150610a65565b91949350916020604082610ac5600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291610a05565b916001906fffffffffffffffffffffffffffffffff610af960406103d5878a8c611a17565b160192016107c1565b3461033c57610b1036611512565b91909282156103e4575f905f5b848110610e1057506001600160a01b03610b3a9116918383611a7a565b610b4383611758565b926001600160a01b035f9316925b818110610b6657604051806100bf8782611587565b610b718183886115d6565b610b7a906117a7565b9082610b8782828a6115d6565b602001610b93906117a7565b610b9e83838b6115d6565b604001610baa90611643565b9389610bb78585836115d6565b606001610bc3906117bb565b610bce8686846115d6565b608001610bda906117bb565b9086610be78188866115d6565b60a08101610bf491611926565b97610c009291956115d6565b60c0019260405194610c1186611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a0860193151584523690610c6a9261197a565b9260c0850193845236610c7c916118c8565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610db3575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90610d81575b60019250610d7a8288611901565b5201610b51565b506020823d8211610dab575b81610d9a602093836116ff565b8101031261033c5760019151610d6c565b3d9150610d8d565b91949350916020606082610e01600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610d2d565b916001906fffffffffffffffffffffffffffffffff610e3560406103d5878a8c6115d6565b16019201610b1d565b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c57610e756115c0565b610e7d6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610120870201011161033c5783156103e45790915f9190825b85811061117157506001600160a01b03610ef09116928484611a7a565b610ef984611758565b926001600160a01b03165f5b858110610f1a57604051806100bf8782611587565b610f286104f6828886611915565b90610f39602061050c838a88611915565b8785610f4b60406103d5868585611915565b610f5b6060610534878686611915565b9060e0610f8487610f7d8188610f77608061053484848d611915565b98611915565b968c611915565b01906001600160a01b0360405198610f9b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c576040519561101a876116aa565b61102660a08201611839565b875260c00161103490611839565b602087015260c089019586523661104a916118c8565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e484015251610104830161110f91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610348575f9061113f575b600192506111388288611901565b5201610f05565b506020823d8211611169575b81611158602093836116ff565b8101031261033c576001915161112a565b3d915061114b565b93926001906fffffffffffffffffffffffffffffffff61119760406103d5898b89611915565b16019401939293610ed3565b3461033c576111b136611512565b91909282156103e4575f905f5b84811061149d57506001600160a01b036111db9116918383611a7a565b6111e483611758565b926001600160a01b035f9316925b81811061120757604051806100bf8782611587565b6112128183886115d6565b61121b906117a7565b908261122882828a6115d6565b602001611234906117a7565b61123f83838b6115d6565b60400161124b90611643565b93896112588585836115d6565b606001611264906117bb565b61126f8686846115d6565b60800161127b906117bb565b90866112888188866115d6565b60a08101611295916117c8565b976112a19291956115d6565b60c00192604051946112b286611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a086019315158452369061130b9261184b565b9260c085019384523661131d916118c8565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611454575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90611422575b6001925061141b8288611901565b52016111f2565b506020823d821161144c575b8161143b602093836116ff565b8101031261033c576001915161140d565b3d915061142e565b9194935091602060408261148e600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b019501920186939492916113ce565b916001906fffffffffffffffffffffffffffffffff6114c260406103d5878a8c6115d6565b160192016111be565b602435906001600160a01b038216820361033c57565b9181601f8401121561033c5782359167ffffffffffffffff831161033c576020808501948460051b01011161033c57565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261033c576004356001600160a01b038116810361033c57916024356001600160a01b038116810361033c57916044359067ffffffffffffffff821161033c57611583916004016114e1565b9091565b60206040818301928281528451809452019201905f5b8181106115aa5750505090565b825184526020938401939092019160010161159d565b600435906001600160a01b038216820361033c57565b91908110156116165760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018136030182121561033c570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356fffffffffffffffffffffffffffffffff8116810361033c5790565b610100810190811067ffffffffffffffff82111761167d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761167d57604052565b610120810190811067ffffffffffffffff82111761167d57604052565b6060810190811067ffffffffffffffff82111761167d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761167d57604052565b67ffffffffffffffff811161167d5760051b60200190565b9061176282611740565b61176f60405191826116ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061179d8294611740565b0190602036910137565b356001600160a01b038116810361033c5790565b35801515810361033c5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c57602001918160061b3603831361033c57565b35906fffffffffffffffffffffffffffffffff8216820361033c57565b359064ffffffffff8216820361033c57565b92919261185782611740565b9361186560405195866116ff565b602085848152019260061b82019181831161033c57925b8284106118895750505050565b60408483031261033c57602060409182516118a3816116aa565b6118ac8761181c565b81526118b9838801611839565b8382015281520193019261187c565b919082604091031261033c576040516118e0816116aa565b809280356001600160a01b038116810361033c578252602090810135910152565b80518210156116165760209160051b010190565b919081101561161657610120020190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c5760200191606082023603831361033c57565b92919261198682611740565b9361199460405195866116ff565b606060208685815201930282019181831161033c57925b8284106119b85750505050565b60608483031261033c57604051906119cf826116e3565b6119d88561181c565b825260208501359067ffffffffffffffff8216820361033c5782602092836060950152611a0760408801611839565b60408201528152019301926119ab565b91908110156116165760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18136030182121561033c570190565b3564ffffffffff8116810361033c5790565b919081101561161657610140020190565b9190611acf6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015233602482015230604482015283606482015260648152611ac96084826116ff565b82611c8f565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103485784915f91611c42575b5010611b3b575b50505050565b5f806040519460208601907f095ea7b3000000000000000000000000000000000000000000000000000000008252876024880152604487015260448652611b836064876116ff565b85519082855af190611b93611d14565b82611c10575b5081611c05575b5015611bad575b80611b35565b611bf8611bfd93604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152611ac96064826116ff565b611c8f565b5f8080611ba7565b90503b15155f611ba0565b80519192508115918215611c28575b5050905f611b99565b611c3b9250602080918301019101611c77565b5f80611c1f565b9150506020813d602011611c6f575b81611c5e602093836116ff565b8101031261033c578390515f611b2e565b3d9150611c51565b9081602091031261033c5751801515810361033c5790565b5f806001600160a01b03611cb893169360208151910182865af1611cb1611d14565b9083611d71565b8051908115159182611cf9575b5050611cce5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611d0c9250602080918301019101611c77565b155f80611cc5565b3d15611d6c573d9067ffffffffffffffff821161167d5760405191611d6160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846116ff565b82523d5f602084013e565b606090565b90611dae5750805115611d8657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611df4575b611dbf575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611db756fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = hex"60c0604052346103e457615a506060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615642908161040e823960805181613935015260a051818181610bca01526139ff0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c657508063027b6744146127a457806306fdde03146126e9578063081812fc146126cb578063095ea7b3146125c65780631400ecec146125155780631c1cdd4c146124b15780631e99d5691461249457806323b872dd1461247d578063303acc851461244057806331df3d481461232d578063406887cb146121be57806340e58ee514611ea5578063425d30dd14611e5557806342842e0e14611e2c57806342966c6814611c685780634426757014611c425780634857501f14611bd15780634869e12d14611b975780634cc55e1114611a9f57806354c02292146117ee57806357404b12146117605780636352211e146117315780636d0cee751461173157806370a08231146116c757806375829def146116595780637cad6cd1146115685780637de6b1db146113e95780638659c27014610feb578063894e9a0d14610cbc5780638f69b99314610c3c5780639067b67714610bed5780639188ec8414610bb357806395d89b4114610aab578063a22cb465146109f7578063a80fc071146109a6578063ad35efd414610947578063b2564569146108f7578063b637b8651461089e578063b88d4fde14610816578063b8a3be66146107e1578063b971302a14610793578063bc2be1be14610744578063c156a11d1461060e578063c87b56dd146104f8578063d4dbd20b146104a7578063d511609f1461045c578063d975dfed14610422578063e985e9c5146103c9578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f3565b6044356001600160801b03811681036102b0576102ae916102a661392b565b6004356133df565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b86103a66128f3565b916103b081614206565b928391613082565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e26128dd565b6001600160a01b036103f26128f3565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614206565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610515816136ad565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610603575f90610586575b610582906040519182916020835260208301906128b8565b0390f35b503d805f833e6105968183612a76565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105ce83612a98565b916105dc6040519384612a76565b838352602084830101116102b057610582926105fe9160208085019101612897565b61056a565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062a6128f3565b61063261392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f5260036020526001600160a01b0360405f205416908133036107125761067483614206565b6001600160801b0381169182610702575b6001600160a01b038116156106ef576106a6856001600160a01b03926137f1565b1692836106c05784637e27328960e01b5f5260045260245ffd5b80859185036106d457602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070d828587613082565b610685565b8263216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b05761082f6128dd565b6108376128f3565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086483612a98565b926108726040519485612a76565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105826108e360405f20612f0b565b604051918291602083526020830190612988565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761097f9061375d565b6040516005821015610992576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a106128dd565b602435908115158092036102b0576001600160a01b0316908115610a7f57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610ba9575b602083108114610b9557828552908115610b715750600114610b13575b61058283610aff81850382612a76565b6040519182916020835260208301906128b8565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5757509091508101602001610aff610aef565b919260018160209254838588010152019101909291610b3f565b60ff191660208086019190915291151560051b84019091019150610aff9050610aef565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad2565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c749061375d565b6005811015806109925760028214908115610cb0575b8115610c9e575b6020826040519015158152f35b90506109925760046020911482610c91565b5050600381145f610c8a565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd757606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d37612ebb565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7281612a59565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e11600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612ed9565b61012083019081526002610e248c61375d565b610e2d816129fa565b14610fcf575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea46101808d612a76565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610ef890612f0b565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161058291612988565b5f8752610e33565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101c903690600401612957565b9061102561392b565b5f915b80831061103157005b61103c838284612e4a565b359261104661392b565b835f52600a60205260ff600160405f20015460a81c16156113d657835f52600a60205260ff600160405f20015460a01c165f146110905783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c4576110c5815f52600a6020526001600160a01b0360405f205416331490565b156113ae576110d3816136ce565b90805f52600a6020526110eb600260405f2001612ed9565b916001600160801b038351166001600160801b038216101561139a57815f52600a60205260ff60405f205460f01c161561138657806001600160801b0360208161113f948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611361575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125a6001600160a01b03600160405f2001541694611232888588614660565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a4866001600160a01b03165f52600960205260405f2090565b54166112ba575b50505050506001019190611028565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91611333575b50160361131757808080806112ab565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611354915060203d811161135a575b61134c8183612a76565b81019061368d565b87611307565b503d611342565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611189565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140561392b565b805f52600a60205260ff600160405f20015460a81c1615610323576114298161375d565b611432816129fa565b6004810361144d5750634a5541ef60e01b5f5260045260245ffd5b611456816129fa565b60038103611471575063fe19f19f60e01b5f5260045260245ffd5b60029061147d816129fa565b14611556576114a0815f52600a6020526001600160a01b0360405f205416331490565b1561153757805f52600a60205260ff60405f205460f01c1615611525576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611643575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161162f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116726128dd565b5f546001600160a01b03811633810361164357506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116e86128dd565b168015611705575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174f6004356136ad565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177c612ea3565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c683612a3d565b825260208201526117ec8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182961392b565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186b913691612d66565b9081519161187883612d4e565b926118866040519485612a76565b808452601f1961189582612d4e565b015f5b818110611a8857505064ffffffffff4216916001600160801b036118bb82613985565b51511667ffffffffffffffff60206118d284613985565b5101511664ffffffffff8060406118e886613985565b5101511686011690604051926118fd84612a21565b83526020830152604082015261191286613985565b5261191c85613985565b5060015b8281106119f45750505061193682600401612e82565b9261194360248401612e82565b9261195060448201612e6e565b916064820135936001600160a01b0385168095036102b0576020966119ec966119ac966001600160801b036119e1976001600160a01b0361199360848a01612e96565b94816119a160a48c01612e96565b976040519d8e612a04565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e03565b6101008201526139a6565b604051908152f35b806001600160801b03611a0960019385613992565b51511667ffffffffffffffff6020611a218487613992565b5101511664ffffffffff806040611a3b5f1987018d613992565b51015116816040611a4c878a613992565b5101511601169060405192611a6084612a21565b835260208301526040820152611a768289613992565b52611a818188613992565b5001611920565b602090611a93612ebb565b82828901015201611898565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad0903690600401612957565b9060243567ffffffffffffffff81116102b057611af1903690600401612957565b9091611afb61392b565b818403611b67575f5b848110611b0d57005b80611b61611b1e6001938886612e4a565b35611b2a838987612e4a565b355f5260036020526001600160a01b0360405f205416611b53611b4e85898b612e4a565b612e6e565b91611b5c61392b565b6133df565b01611b04565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614156565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0a8261375d565b600581101561099257600203611c28575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1b565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8461392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0157611cc3816140e4565b156113ae57805f5260036020526001600160a01b0360405f205416151580611dfa575b80611ddd575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d94575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8257005b637e27328960e01b5f5260045260245ffd5b611db3835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cec565b505f611ce6565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3d3661291d565b9060405192611e4d602085612a76565b5f8452612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec161392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c457611f3c815f52600a6020526001600160a01b0360405f205416331490565b1561153757611f4a816136ce565b90805f52600a602052611f62600260405f2001612ed9565b916001600160801b038351166001600160801b03821610156121ab57815f52600a60205260ff60405f205460f01c161561219857806001600160801b03602081611fb6948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612173575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120a96001600160a01b03600160405f2001541694611232888588614660565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ec57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91612154575b50160361214257005b632187e5e760e21b5f5260045260245ffd5b61216d915060203d60201161135a5761134c8183612a76565b84612139565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612000565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121d76128dd565b6001600160a01b035f54169033820361231657806001600160a01b03913b156122ea57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610603575f916122bb575b501561229057805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122dd915060203d6020116122e3575b6122d58183612a76565b810190612e32565b82612245565b503d6122cb565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236761392b565b6040519061237482612a04565b61238081600401612909565b825261238e60248201612909565b602083015261239f60448201612ab4565b604083015260648101356001600160a01b03811681036102b05760608301526123ca608482016129ed565b60808301526123db60a482016129ed565b60a08301526123ec60c48201612d3c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e16119ec926124306020953690602460048201359101612d66565b60e0840152610104369101612e03565b346102b05760203660031901126102b0576001600160a01b036124616128dd565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248e3661291d565b91612b0a565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e99061375d565b600581101561099257806020911590811561250a575b506040519015158152f35b6001915014826124ff565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125aa575b612578575b506001600160801b0360405191168152f35b6125a49150805f52600a835261259e6001600160801b03600260405f20015416916136ce565b90612aea565b82612566565b50805f52600a835260ff600160405f20015460a01c1615612561565b346102b05760403660031901126102b0576125df6128dd565b6024356125eb816136ad565b331515806126b8575b80612685575b6126595781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fa565b50336001600160a01b03821614156125f4565b346102b05760203660031901126102b057602061174f600435612ac8565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279a575b602083108114610b9557828552908115610b71575060011461273c5761058283610aff81850382612a76565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278057509091508101602001610aff610aef565b919260018160209254838588010152019101909291612768565b91607f1691612710565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612822575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561286d575b811561285c575b508361281b565b6301ffc9a760e01b91501483612855565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061284e565b5f5b8381106128a85750505f910152565b8181015183820152602001612899565b906020916128d181518092818552858086019101612897565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a55750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612998565b359081151582036102b057565b6005111561099257565b610120810190811067ffffffffffffffff821117610fd757604052565b6060810190811067ffffffffffffffff821117610fd757604052565b6040810190811067ffffffffffffffff821117610fd757604052565b610140810190811067ffffffffffffffff821117610fd757604052565b90601f8019910116810190811067ffffffffffffffff821117610fd757604052565b67ffffffffffffffff8111610fd757601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad1816136ad565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162f57565b91906001600160a01b031680156106ef57815f5260036020526001600160a01b0360405f205416151580612d34575b80612d17575b612d04577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c4f575b6001600160a01b03935085612c18575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0057505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c37825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b9f565b9192905080612cad575b15612c6657828291612b8f565b8284612c7e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cdb575b80612c595750825f526005602052336001600160a01b0360405f20541614612c59565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cb8565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b3f565b506001612b39565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd75760051b60200190565b929192612d7282612d4e565b93612d806040519586612a76565b60606020868581520193028201918183116102b057925b828410612da45750505050565b6060848303126102b05760405190612dbb82612a21565b612dc485612ab4565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df360408801612d3c565b6040820152815201930192612d97565b91908260409103126102b057604051612e1b81612a3d565b6020808294612e2981612909565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb082612a3d565b5f6020838281520152565b60405190612ec882612a21565b5f6040838281528260208201520152565b90604051612ee681612a21565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1781612d4e565b92612f256040519485612a76565b81845260208401905f5260205f205f915b838310612f435750505050565b600160208192604051612f5581612a21565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f36565b90612f9e838284612b0a565b803b612fab575b50505050565b602091612ff16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b8565b03815f865af15f9181613061575b5061302d575061300d6141d7565b805190816130285782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361304f57505f808080612fa5565b633250574960e11b5f5260045260245ffd5b61307b91925060203d60201161135a5761134c8183612a76565b905f612fff565b9061308b61392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f205416948583141580613364575b613330576001600160801b0361311786614206565b168085116132fd575061313c90855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561317f90612ed9565b6001600160801b036131a38160208401511692826040818351169201511690612aea565b1611156132cb575b835f52600a6020526131cf836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b5575b6132395750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613296575b50160361214257808080612fa5565b6132af915060203d60201161135a5761134c8183612a76565b5f613287565b50835f52600960205260ff60405f20541661322f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ab565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061336e856140e4565b15613102565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f20541694858314158061367d575b613330576001600160801b0361346c86614206565b168085116132fd575061349190855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d490612ed9565b6001600160801b036134f88160208401511692826040818351169201511690612aea565b16111561364b575b835f52600a602052613524836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613626575b61358e5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613607575b5016036135eb57808080612fa5565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613620915060203d60201161135a5761134c8183612a76565b5f6135dc565b5060ff613644856001600160a01b03165f52600960205260405f2090565b5416613584565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613500565b50613687856140e4565b15613457565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d82575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375757815f52600a60205264ffffffffff60405f205460c81c16111561373c57805f52600b602052600160405f2054115f14613733576137309061430c565b90565b6137309061424c565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f1461377f5750600490565b805f52600a60205260405f205460f81c6137eb57805f52600a60205264ffffffffff60405f205460a01c1642106137e6576137b9816136ce565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e157600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613919575b806138fc575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c5575b16806138ad575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613869565b6138e4835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613862565b50805f52600a60205260ff600160405f20015460b01c1615613816565b506001600160a01b0382161515613810565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361395d57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5a5760200190565b8051821015612e5a5760209160051b010190565b906139c86001600160801b036040840151166020610100850151015190614522565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bc578015614094578151801561406c577f00000000000000000000000000000000000000000000000000000000000000008111614041575064ffffffffff6040613a3684613985565b51015116811015613ffd57505f905f905f81515f905b808210613f75575050505064ffffffffff80421691169081811015613f475750506001600160801b031690818103613f1957505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c218751975f19890190613992565b51015160c81b169360a01b169116171785555f5b818110613e0b575050600187016007556001600160a01b0360208301511680156106ef57613c6b886001600160a01b03926137f1565b16613ddf578682613cb96001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145ff565b6001600160801b0360208401511680613daf575b506001600160a01b0381511694613da4613d866001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2b8b612a3d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612988565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dd9906001600160a01b036060840151166001600160a01b0361010085015151169033906145ff565b5f613ccd565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e268160e0870151613992565b51825468010000000000000000811015610fd75760018101808555811015612e5a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c35565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f99906001600160801b03613f908588613992565b5151169061422c565b9364ffffffffff806040613fad8685613992565b51015116941680851115613fc957506001849301909291613a4c565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400e84613985565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412a575b508115614111575090565b90506001600160a01b036141253392612ac8565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614106565b805f52600a60205261416d600260405f2001612ed9565b90805f52600a60205260ff600160405f20015460a01c165f1461419b5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ba5750613730906136ce565b61373091506001600160801b036040818351169201511690612aea565b3d15614201573d906141e882612a98565b916141f66040519384612a76565b82523d5f602084013e565b606090565b6137309061421381614156565b905f52600a602052600260405f20015460801c90612aea565b906001600160801b03809116911601906001600160801b03821161162f57565b5f818152600a60205260409020546142839064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b0565b90805f52600b60205260405f20805415612e5a575f526142d867ffffffffffffffff60205f205460801c1692825f52600a6020526142d36001600160801b03600260405f20015416948592614790565b614803565b9182136142f557506142f16001600160801b03916148de565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433082612a59565b6101206143c360028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612ed9565b92019182525f52600b6020526143db60405f20612f0b565b915f9264ffffffffff60406143ef83613985565b510151168664ffffffffff5f925b16106144e3578161447464ffffffffff9697988784816001600160801b0361442c6142d3986144799b9a613992565b5151169a8b9867ffffffffffffffff6020614447868b613992565b51015116978260406144598784613992565b5101511694806144c6575050511680925b03169203166146b0565b614790565b91821361449a5750906001600160801b0361449481936148de565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c1575090565b905090565b60409250906144d8915f190190613992565b51015116809261446a565b936001600160801b03600191816144fa8886613992565b51511601169401958064ffffffffff8060406145168b87613992565b510151169892986143fd565b91909160405161453181612a3d565b5f81525f6020820152926001600160801b0382169081156145e25767016345785d8a000081116145ab5761456d6001600160801b0391836154fb565b1660208501918183521115614597576001600160801b03918261459292511690612aea565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f381612a3d565b5f81525f602082015290565b9091926001600160a01b0361465e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614659608483612a76565b614913565b565b61465e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614659606483612a76565b600160ff1b81148015614783575b61475b575f811215614752576146e2815f035b5f84121561474b57835f0390614998565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471c575f19911813156147175790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614998565b6146e2816146d1565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146be565b806147aa57506147a657670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f557806147cd575050670de0b6b3a764000090565b670de0b6b3a764000081146147f1576147ec906142d361373093614a9e565b614bf5565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d1575b6148a9575f8112156148a057614835815f035b5f84121561489957835f03906154fb565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486a575f19911813156147175790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fb565b61483581614824565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614811565b5f81126148e85790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493c93169360208151910182865af16149356141d7565b90836155a9565b805190811515918261497d575b50506149525750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149909250602080918301019101612e32565b155f80614949565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a635781841015614a2957670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a70570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a70576ec097ce7bc90715b34b9f10000000000590565b805f811315614bca57670de0b6b3a76400008112614baa57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9757506706f05b59d3b20000905b5f8213614b615750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b89575b60011d90614b54565b809192019160011d90614b80565b9050670de0b6b3a7640000929150020290565b5f1991508015614a70576ec097ce7bc90715b34b9f100000000005614abb565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c225768033dd1780914b971141981126137e657614c19905f03614bf5565b61373090614a84565b680a688906bd8affffff81136154d057670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539b575b670de0b6b3a76400009066ff000000000000831661528b575b65ff00000000008316615183575b64ff000000008316615083575b63ff0000008316614f8b575b62ff00008316614e9b575b61ff008316614db3575b60ff8316614cd3575b029060401c60bf031c90565b60808316614da0575b60408316614d8d575b60208316614d7a575b60108316614d67575b60088316614d54575b60048316614d41575b60028316614d2e575b6001831615614cc757680100000000000000010260401c614cc7565b680100000000000000010260401c614d12565b680100000000000000030260401c614d09565b680100000000000000060260401c614d00565b6801000000000000000b0260401c614cf7565b680100000000000000160260401c614cee565b6801000000000000002c0260401c614ce5565b680100000000000000590260401c614cdc565b6180008316614e88575b6140008316614e75575b6120008316614e62575b6110008316614e4f575b6108008316614e3c575b6104008316614e29575b6102008316614e16575b610100831615614cbe57680100000000000000b10260401c614cbe565b680100000000000001630260401c614df9565b680100000000000002c60260401c614def565b6801000000000000058c0260401c614de5565b68010000000000000b170260401c614ddb565b6801000000000000162e0260401c614dd1565b68010000000000002c5d0260401c614dc7565b680100000000000058b90260401c614dbd565b628000008316614f78575b624000008316614f65575b622000008316614f52575b621000008316614f3f575b620800008316614f2c575b620400008316614f19575b620200008316614f06575b62010000831615614cb4576801000000000000b1720260401c614cb4565b680100000000000162e40260401c614ee8565b6801000000000002c5c80260401c614edd565b68010000000000058b910260401c614ed2565b680100000000000b17210260401c614ec7565b68010000000000162e430260401c614ebc565b680100000000002c5c860260401c614eb1565b6801000000000058b90c0260401c614ea6565b63800000008316615070575b6340000000831661505d575b6320000000831661504a575b63100000008316615037575b63080000008316615024575b63040000008316615011575b63020000008316614ffe575b6301000000831615614ca95768010000000000b172180260401c614ca9565b6801000000000162e4300260401c614fdf565b68010000000002c5c8600260401c614fd3565b680100000000058b90c00260401c614fc7565b6801000000000b17217f0260401c614fbb565b680100000000162e42ff0260401c614faf565b6801000000002c5c85fe0260401c614fa3565b68010000000058b90bfc0260401c614f97565b6480000000008316615170575b644000000000831661515d575b642000000000831661514a575b6410000000008316615137575b6408000000008316615124575b6404000000008316615111575b64020000000083166150fe575b640100000000831615614c9d57680100000000b17217f80260401c614c9d565b68010000000162e42ff10260401c6150de565b680100000002c5c85fe30260401c6150d1565b6801000000058b90bfce0260401c6150c4565b68010000000b17217fbb0260401c6150b7565b6801000000162e42fff00260401c6150aa565b68010000002c5c8601cc0260401c61509d565b680100000058b90c0b490260401c615090565b658000000000008316615278575b654000000000008316615265575b652000000000008316615252575b65100000000000831661523f575b65080000000000831661522c575b650400000000008316615219575b650200000000008316615206575b65010000000000831615614c90576801000000b1721835510260401c614c90565b680100000162e430e5a20260401c6151e5565b6801000002c5c863b73f0260401c6151d7565b68010000058b90cf1e6e0260401c6151c9565b680100000b1721bcfc9a0260401c6151bb565b68010000162e43f4f8310260401c6151ad565b680100002c5c89d5ec6d0260401c61519f565b6801000058b91b5bc9ae0260401c615191565b66800000000000008316615388575b66400000000000008316615375575b66200000000000008316615362575b6610000000000000831661534f575b6608000000000000831661533c575b66040000000000008316615329575b66020000000000008316615316575b6601000000000000831615614c825768010000b17255775c040260401c614c82565b6801000162e525ee05470260401c6152f4565b68010002c5cc37da94920260401c6152e5565b680100058ba01fb9f96d0260401c6152d6565b6801000b175effdc76ba0260401c6152c7565b680100162f3904051fa10260401c6152b8565b6801002c605e2e8cec500260401c6152a9565b68010058c86da1c09ea20260401c61529a565b67800000000000000082166154b1575b670de0b6b3a764000090674000000000000000831661549e575b672000000000000000831661548b575b6710000000000000008316615478575b6708000000000000008316615465575b6704000000000000008316615452575b670200000000000000831661543f575b670100000000000000831661542c575b9050614c69565b680100b1afa5abcbed610260401c615425565b68010163da9fb33356d80260401c615415565b680102c9a3e778060ee70260401c615405565b6801059b0d31585743ae0260401c6153f5565b68010b5586cf9890f62a0260401c6153e5565b6801172b83c7d517adce0260401c6153d5565b6801306fe0a31b7152df0260401c6153c5565b5077b504f333f9de6484800000000000000000000000000000006153ab565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559857670de0b6b3a7640000821015615568577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e657508051156155be57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562c575b6155f7575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155ef56fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = hex"60a0604052346103bf57614b706040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478790816103e9823960805181613adb0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313757508063027b67441461311557806306fdde031461305a578063081812fc1461303c578063095ea7b314612f375780631400ecec14612e865780631c1cdd4c14612e225780631e99d56914612e0557806323b872dd14612dee578063303acc8514612db1578063406887cb14612c4257806340e58ee51461296b578063425d30dd1461291b57806342842e0e146128f257806342966c681461272e57806344267570146127085780634857501f146126975780634869e12d1461265d5780634cc55e11146122b657806353b157271461218b57806357404b12146120c55780636352211e146120965780636d0cee751461209657806370a082311461202c57806375829def14611fbe578063780a82c814611f725780637cad6cd114611e955780637de6b1db14611d485780638659c27014611991578063894e9a0d146116a95780638f69b993146116295780639067b677146115da57806395d89b41146114d2578063a22cb4651461141e578063a80fc071146113cd578063ab167ccc1461125c578063ad35efd4146111fd578063b2564569146111ad578063b88d4fde14611123578063b8a3be66146110ee578063b971302a146110a0578063bc2be1be14611051578063c156a11d14610c3c578063c87b56dd14610b31578063d4dbd20b14610ae0578063d511609f14610a95578063d975dfed14610a4a578063e985e9c5146109f1578063ea5ead19146106ac578063eac8f5b81461065b578063f590c17614610600578063f851a440146105db5763fdd46d6014610263575f80fd5b346105d75760603660031901126105d75760043561027f613264565b906102886133c6565b610290613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431b565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136aa565b6001600160801b036103b681602084015116928260408183511692015116906133fe565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b632187e5e760e21b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb8183613388565b8101906137e0565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061058684613b2b565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d7575f3660031901126105d75760206001600160a01b035f5416604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d75760403660031901126105d7576004356106c8613264565b906106d28161431b565b906106db613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c166109df576001600160a01b0383169182156109cc576001600160801b03169182156109b957815f5260036020526001600160a01b0360405f2054169384821415806109a9575b61098e576001600160801b036107678461431b565b168085116109745750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107dd600260405f20016136aa565b6001600160801b0361080181602084015116928260408183511692015116906133fe565b161115610942575b825f52600a60205261082d846001600160a01b03600160405f200154169283614341565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092c575b61089d575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090d575b5016036108fa578180610892565b50632187e5e760e21b5f5260045260245ffd5b610926915060203d6020116104d9576104cb8183613388565b856108ec565b50835f52600960205260ff60405f20541661088d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610809565b848463287ecaef60e21b5f5260045260245260445260645ffd5b509063b34359d360e01b5f526004523360245260445260645ffd5b506109b383613b2b565b15610752565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105d75760403660031901126105d757610a0a61324e565b6001600160a01b03610a1a613264565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a8460209161431b565b6001600160801b0360405191168152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a6020526020600260405f20015460801c604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d75760203660031901126105d757600435610b4e81613800565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bbf575b610bbb90604051918291602083526020830190613229565b0390f35b503d805f833e610bcf8183613388565b8101906020818303126105d75780519067ffffffffffffffff82116105d757019080601f830112156105d757815191610c07836133aa565b91610c156040519384613388565b838352602084830101116105d757610bbb92610c379160208085019101613208565b610ba3565b346105d75760403660031901126105d757600435610c58613264565b610c60613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103a576001600160801b03610caa8461431b565b169081158015610d33575b506001600160a01b03811615610d2057610cd7846001600160a01b0392613997565b169182610cf15783637e27328960e01b5f5260045260245ffd5b8084918403610d0557602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3b613ad1565b845f52600a60205260ff600160405f20015460a81c161561102857845f52600a60205260ff600160405f20015460a01c1661101557831561100257610fef57835f5260036020526001600160a01b0360405f2054168084141580610fdf575b610fc4576001600160801b03610daf8661431b565b16808411610faa5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e0e90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e25600260405f20016136aa565b6001600160801b03610e4981602084015116928260408183511692015116906133fe565b161115610f78575b845f52600a6020526001600160a01b03600160405f20015416610e75848683614341565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f62575b15610cb5576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f43575b501614610cb557632187e5e760e21b5f5260045260245ffd5b610f5c915060203d6020116104d9576104cb8183613388565b88610f2a565b50805f52600960205260ff60405f205416610ed5565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e51565b838663287ecaef60e21b5f5260045260245260445260645ffd5b838563b34359d360e01b5f526004523360245260445260645ffd5b50610fe985613b2b565b15610d9a565b8363d2aabcd960e01b5f5260045260245ffd5b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d75760203660031901126105d7576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d75760803660031901126105d75761113c61324e565b611144613264565b6064359167ffffffffffffffff83116105d757366023840112156105d757826004013591611171836133aa565b9261117f6040519485613388565b80845236602482870101116105d7576020815f9260246111ab98018388013785010152604435916136f0565b005b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761123590613903565b6040516005821015611248576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d7576101403660031901126105d757611276613ad1565b61127e61368c565b64ffffffffff421680825264ffffffffff6112976136dc565b166113b2575b60e43564ffffffffff811681036105d75764ffffffffff9101166040820152600435906001600160a01b038216918281036105d757506024356001600160a01b038116908181036105d757506044356001600160801b038116908181036105d757506064356001600160a01b0381168091036105d75760843591821515928381036105d7575060a43593841515948581036105d7575060405196611340886132e5565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d7576040519061137a8261336c565b61010435906001600160a01b03821682036105d757826113aa9260209452610124358482015260e0820152613c21565b604051908152f35b64ffffffffff6113c06136dc565b820116602083015261129d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d75760403660031901126105d75761143761324e565b602435908115158092036105d7576001600160a01b03169081156114a657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7575f3660031901126105d7576040515f6002548060011c906001811680156115d0575b6020831081146115bc57828552908115611598575060011461153a575b610bbb8361152681850382613388565b604051918291602083526020830190613229565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061157e57509091508101602001611526611516565b919260018160209254838588010152019101909291611566565b60ff191660208086019190915291151560051b840190910191506115269050611516565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114f9565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761166190613903565b600581101580611248576002821490811561169d575b811561168b575b6020826040519015158152f35b9050611248576004602091148261167e565b5050600381145f611677565b346105d75760203660031901126105d7576004355f6101606040516116cd81613332565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261171061368c565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260405f2060405161174b8161334f565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ea600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136aa565b61012083019081526117fb87613903565b600581101561124857600214611989575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188181613332565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180c565b346105d75760203660031901126105d75760043567ffffffffffffffff81116105d7576119c29036906004016132b4565b906119cb613ad1565b5f915b8083106119d757005b6119e2838284613668565b35926119ec613ad1565b835f52600a60205260ff600160405f20015460a81c1615611d3657835f52600a60205260ff600160405f20015460a01c165f14611a365783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2457611a6b815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57611a7981613821565b90805f52600a602052611a91600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081611ae59481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc3575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bf76001600160a01b03600160405f2001541694611bcf888588614341565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c48575b505050505060010191906119ce565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca5575b50160361049f5780808080611c39565b611cbd915060203d81116104d9576104cb8183613388565b87611c95565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b2f565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435611d64613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57611d8881613903565b60058110156112485760048103611dac5750634a5541ef60e01b5f5260045260245ffd5b60038103611dc7575063fe19f19f60e01b5f5260045260245ffd5b600214611e8357611dec815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57805f52600a60205260ff60405f205460f01c1615611e71576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d75760203660031901126105d7576004356001600160a01b0381168091036105d7576001600160a01b035f5416338103611f5c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d75760203660031901126105d757611fd761324e565b5f546001600160a01b038116338103611f5c57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d75760203660031901126105d7576001600160a01b0361204d61324e565b16801561206a575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d75760203660031901126105d75760206120b4600435613800565b6001600160a01b0360405191168152f35b346105d75760203660031901126105d7576004356120e161368c565b50805f52600a60205260ff600160405f20015460a81c161561064a57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261215184613316565b835260208301526040820152612189604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d7576101603660031901126105d7576121a5613ad1565b6040516121b1816132e5565b6121b961324e565b81526121c3613264565b60208201526121d06133c6565b60408201526064356001600160a01b03811681036105d757606082015260843580151581036105d757608082015260a43580151581036105d75760a082015260603660c31901126105d75760405161222781613316565b60c43564ffffffffff811681036105d757815260e43564ffffffffff811681036105d75760208201526101043564ffffffffff811681036105d757604082015260c08201526040610123193601126105d757604051906122868261336c565b61012435906001600160a01b03821682036105d757826113aa9260209452610144358482015260e0820152613c21565b346105d75760403660031901126105d75760043567ffffffffffffffff81116105d7576122e79036906004016132b4565b60243567ffffffffffffffff81116105d7576123079036906004016132b4565b612312939193613ad1565b80830361262e575f5b83811061232457005b61232f818585613668565b3561233b828686613668565b355f5260036020526001600160a01b0360405f2054169061235d838589613668565b356001600160801b038116908181036105d75750612379613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109cc5780156109b957815f5260036020526001600160a01b0360405f20541692838114158061261e575b612604576001600160801b036123f08461431b565b168083116125ea5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761244f90845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052612466600260405f20016136aa565b6001600160801b0361248a81602084015116928260408183511692015116906133fe565b1611156125b8575b825f52600a6020526001600160a01b03600160405f200154166124b6838383614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a2575b612527575b5050505060010161231b565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612584575b50160361049f5780808061251b565b61259c915060203d81116104d9576104cb8183613388565b89612575565b50835f52600960205260ff60405f205416612516565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612492565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061262883613b2b565b156123db565b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a84602091613b9d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f6126d082613903565b6005811015611248576002036126ee575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e1565b346105d7575f3660031901126105d75760206001600160a01b0360085416604051908152f35b346105d75760203660031901126105d75760043561274a613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c16156128c75761278981613b2b565b15611d0e57805f5260036020526001600160a01b0360405f2054161515806128c0575b806128a3575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285a575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284857005b637e27328960e01b5f5260045260245ffd5b612879835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612800565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b2565b505f6127ac565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7576111ab6129033661327a565b9060405192612913602085613388565b5f84526136f0565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d75760203660031901126105d757600435612987613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c165f146129d057634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2457612a02815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57612a1081613821565b90805f52600a602052612a28600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081612a7c9481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c1d575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b666001600160a01b03600160405f2001541694611bcf888588614341565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612ba957005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612bfe5750160361049f57005b612c17915060203d6020116104d9576104cb8183613388565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ac6565b346105d75760203660031901126105d757612c5b61324e565b6001600160a01b035f541690338203612d9a57806001600160a01b03913b15612d6e57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d3f575b5015612d1457805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d61915060203d602011612d67575b612d598183613388565b810190613650565b82612cc9565b503d612d4f565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d7576001600160a01b03612dd261324e565b165f526009602052602060ff60405f2054166040519015158152f35b346105d7576111ab612dff3661327a565b9161341e565b346105d7575f3660031901126105d7576020600754604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57612e5a90613903565b6005811015611248578060209115908115612e7b575b506040519015158152f35b600191501482612e70565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a576020905f90805f52600a835260ff60405f205460f01c1680612f1b575b612ee9575b506001600160801b0360405191168152f35b612f159150805f52600a8352612f0f6001600160801b03600260405f2001541691613821565b906133fe565b82612ed7565b50805f52600a835260ff600160405f20015460a01c1615612ed2565b346105d75760403660031901126105d757612f5061324e565b602435612f5c81613800565b33151580613029575b80612ff6575b612fca5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6b565b50336001600160a01b0382161415612f65565b346105d75760203660031901126105d75760206120b46004356133dc565b346105d7575f3660031901126105d7576040515f6001548060011c9060018116801561310b575b6020831081146115bc5782855290811561159857506001146130ad57610bbb8361152681850382613388565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f157509091508101602001611526611516565b9192600181602092548385880101520191019092916130d9565b91607f1691613081565b346105d7575f3660031901126105d757602060405167016345785d8a00008152f35b346105d75760203660031901126105d757600435906001600160e01b031982168092036105d757817f490649060000000000000000000000000000000000000000000000000000000060209314908115613193575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131de575b81156131cd575b508361318c565b6301ffc9a760e01b915014836131c6565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131bf565b5f5b8381106132195750505f910152565b818101518382015260200161320a565b9060209161324281518092818552858086019101613208565b601f01601f1916010190565b600435906001600160a01b03821682036105d757565b602435906001600160a01b03821682036105d757565b60609060031901126105d7576004356001600160a01b03811681036105d757906024356001600160a01b03811681036105d7579060443590565b9181601f840112156105d75782359167ffffffffffffffff83116105d7576020808501948460051b0101116105d757565b610100810190811067ffffffffffffffff82111761330257604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330257604052565b610180810190811067ffffffffffffffff82111761330257604052565b610140810190811067ffffffffffffffff82111761330257604052565b6040810190811067ffffffffffffffff82111761330257604052565b90601f8019910116810190811067ffffffffffffffff82111761330257604052565b67ffffffffffffffff811161330257601f01601f191660200190565b604435906001600160801b03821682036105d757565b6133e581613800565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2057815f5260036020526001600160a01b0360405f205416151580613648575b8061362b575b613618577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613563575b6001600160a01b0393508561352c575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351457505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354b825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b3565b91929050806135c1575b1561357a578282916134a3565b828461359257637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135ef575b8061356d5750825f526005602052336001600160a01b0360405f2054161461356d565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135cc565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613453565b50600161344d565b908160209103126105d7575180151581036105d75790565b91908110156136785760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369982613316565b5f6040838281528260208201520152565b906040516136b781613316565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d75790565b906136fc83828461341e565b803b613709575b50505050565b60209161374f6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613229565b03815f865af15f91816137bf575b5061378b575061376b6142ec565b805190816137865782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137ad57505f808080613703565b633250574960e11b5f5260045260245ffd5b6137d991925060203d6020116104d9576104cb8183613388565b905f61375d565b908160209103126105d757516001600160e01b0319811681036105d75790565b805f5260036020526001600160a01b0360405f205416908115612848575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138f9575b6138f357815f52600a60205264ffffffffff60405f205460c81c1690814210156138d6578061388892039042036144cf565b815f52600a6020526138ab6001600160801b03600260405f2001541680926145bb565b9081116138c0576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b5042811015613856565b805f52600a60205260ff600160405f20015460a01c165f146139255750600490565b805f52600a60205260405f205460f81c61399157805f52600a60205264ffffffffff60405f205460a01c16421061398c5761395f81613821565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398757600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613abf575b80613aa2575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6b575b1680613a53575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a0f565b613a8a835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a08565b50805f52600a60205260ff600160405f20015460b01c16156139bc565b506001600160a01b03821615156139b6565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b71575b508115613b58575090565b90506001600160a01b03613b6c33926133dc565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b4d565b805f52600a602052613bb4600260405f20016136aa565b90805f52600a60205260ff600160405f20015460a01c165f14613be25750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c045750613c0190613821565b90565b613c0191506001600160801b0360408183511692015116906133fe565b90613c426001600160801b03604084015116602060e0850151015190614398565b916001600160801b0383511660c082015190156142c45764ffffffffff8151161561429c576020810164ffffffffff81511680614210575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e257505064ffffffffff80421691511690818110156141b45750506007549280516001600160801b03169160405192613cd284613316565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d388961334f565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fb891906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614194575b50600185016007556001600160a01b036020820151168015610d2057614026866001600160a01b0392613997565b16614168576140516001600160a01b036060830151166001600160801b038451169030903390614475565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614139575b506141306001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614162906001600160a01b036060880151166001600160a01b0360e08901515116903390614475565b5f61408c565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ff8565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561426e57505064ffffffffff90511664ffffffffff60408301511690818110613c7a577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614316573d906142fd826133aa565b9161430b6040519384613388565b82523d5f602084013e565b606090565b613c019061432881613b9d565b905f52600a602052600260405f20015460801c906133fe565b614396926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614391606483613388565b614669565b565b9190916040516143a78161336c565b5f81525f6020820152926001600160801b0382169081156144585767016345785d8a00008111614421576143e36001600160801b0391836145bb565b166020850191818352111561440d576001600160801b039182614408925116906133fe565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144698161336c565b5f81525f602082015290565b9091926001600160a01b036143969481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614391608483613388565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459a578184101561456057670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145a7570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465857670de0b6b3a7640000821015614628577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469293169360208151910182865af161468b6142ec565b90836146ee565b80519081151591826146d3575b50506146a85750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146e69250602080918301019101613650565b155f8061469f565b9061472b575080511561470357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614771575b61473c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473456fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c0604052346103e457614e2e6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a20908161040e823960805181613e32015260a051818181612fa10152613edb0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461330d57508063027b6744146132eb57806306fdde0314613230578063081812fc14613212578063095ea7b31461310d5780631400ecec1461305c5780631c1cdd4c14612ff85780631e99d56914612fdb57806323b872dd14612fc45780632fe4304114612f8a578063303acc8514612f4d57806332fbe22b14612df0578063406887cb14612c8157806340e58ee5146129aa578063425d30dd1461295a57806342842e0e1461293157806342966c681461276d57806344267570146127475780634857501f146126d65780634869e12d1461269c5780634cc55e11146122f657806357404b12146122685780636352211e146122395780636d0cee751461223957806370a08231146121cf57806375829def146121615780637cad6cd1146120705780637de6b1db14611f235780637f5799f914611eca5780638659c27014611b13578063894e9a0d146117d4578063897f362b146115095780638f69b993146114895780639067b6771461143a57806395d89b4114611332578063a22cb4651461127e578063a80fc0711461122d578063ad35efd4146111ce578063b25645691461117e578063b88d4fde146110f4578063b8a3be66146110bf578063b971302a14611071578063bc2be1be14611022578063c156a11d14610c08578063c87b56dd14610afd578063d4dbd20b14610aac578063d511609f14610a61578063d975dfed14610a16578063e985e9c5146109bd578063ea5ead1914610690578063eac8f5b81461063f578063f590c176146105e4578063f851a440146105bf5763fdd46d601461026e575f80fd5b346105bb5760603660031901126105bb5760043561028a61343a565b90604435916001600160801b038316908184036105bb576102a9613e28565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614680565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146a6565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139ce565b6001600160801b036103ae8160208401511692826040818351169201511690613611565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b632187e5e760e21b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c3818361359d565b810190613b11565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b5061056a8561455b565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105bb575f3660031901126105bb5760206001600160a01b035f5416604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bb5760403660031901126105bb576004356106ac61343a565b6106b582614680565b916106be613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c166109ab576001600160a01b0382168015610998576001600160801b03841692831561098557825f5260036020526001600160a01b0360405f205416948583141580610975575b61095a576001600160801b0361074a85614680565b16808611610940575061076f90845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107a9906139ce565b6001600160801b036107cd8160208401511692826040818351169201511690613611565b16111561090e575b825f52600a6020526107f9846001600160a01b03600160405f200154169283614804565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108f8575b610869575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108d9575b5016036108c657818061085e565b50632187e5e760e21b5f5260045260245ffd5b6108f2915060203d6020116104d1576104c3818361359d565b856108b8565b50835f52600960205260ff60405f205416610859565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d5565b858563287ecaef60e21b5f5260045260245260445260645ffd5b828463b34359d360e01b5f526004523360245260445260645ffd5b5061097f8461455b565b15610735565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105bb5760403660031901126105bb576109d6613424565b6001600160a01b036109e661343a565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a50602091614680565b6001600160801b0360405191168152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a6020526020600260405f20015460801c604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bb5760203660031901126105bb57600435610b1a81613b31565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8b575b610b87906040519182916020835260208301906133ff565b0390f35b503d805f833e610b9b818361359d565b8101906020818303126105bb5780519067ffffffffffffffff82116105bb57019080601f830112156105bb57815191610bd3836135bf565b91610be1604051938461359d565b838352602084830101116105bb57610b8792610c0391602080850191016133de565b610b6f565b346105bb5760403660031901126105bb57600435610c2461343a565b610c2c613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f5260036020526001600160a01b0360405f20541690813303610ff957610c6e83614680565b906001600160801b0382169182158015610d02575b50506001600160a01b03811615610cef57610ca6846001600160a01b0392613cee565b169182610cc05783637e27328960e01b5f5260045260245ffd5b8084918403610cd457602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0a613e28565b855f52600a60205260ff600160405f20015460a81c1615610fe757855f52600a60205260ff600160405f20015460a01c16610fd4578415610fc157610fae57845f5260036020526001600160a01b0360405f205416908185141580610f9e575b610f83576001600160801b03610d7f87614680565b16808511610f695750610da490865f52600a602052600260405f20015460801c6146a6565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610dde906139ce565b6001600160801b03610e028160208401511692826040818351169201511690613611565b161115610f37575b845f52600a6020526001600160a01b03600160405f20015416610e2e848683614804565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f21575b610e99575b80610c83565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f02575b501614610e9357632187e5e760e21b5f5260045260245ffd5b610f1b915060203d6020116104d1576104c3818361359d565b88610ee9565b50805f52600960205260ff60405f205416610e8e565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0a565b848763287ecaef60e21b5f5260045260245260445260645ffd5b848663b34359d360e01b5f526004523360245260445260645ffd5b50610fa88661455b565b15610d6a565b8463d2aabcd960e01b5f5260045260245ffd5b85630ff7ee2d60e31b5f5260045260245ffd5b85634a5541ef60e01b5f5260045260245ffd5b8562b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bb5760203660031901126105bb576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bb5760803660031901126105bb5761110d613424565b61111561343a565b6064359167ffffffffffffffff83116105bb57366023840112156105bb57826004013591611142836135bf565b92611150604051948561359d565b80845236602482870101116105bb576020815f92602461117c9801838801378501015260443591613a21565b005b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761120690613c5a565b6040516005821015611219576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bb5760403660031901126105bb57611297613424565b602435908115158092036105bb576001600160a01b031690811561130657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb575f3660031901126105bb576040515f6002548060011c90600181168015611430575b60208310811461141c578285529081156113f8575060011461139a575b610b87836113868185038261359d565b6040519182916020835260208301906133ff565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113de57509091508101602001611386611376565b9192600181602092548385880101520191019092916113c6565b60ff191660208086019190915291151560051b840190910191506113869050611376565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611359565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576114c190613c5a565b60058110158061121957600282149081156114fd575b81156114eb575b6020826040519015158152f35b905061121957600460209114826114de565b5050600381145f6114d7565b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb578036036101206003198201126105bb57611544613e28565b60c482013590602219018112156105bb5781019060048201359167ffffffffffffffff83116105bb5760248101908360061b80360383136105bb57600460209161158d87613875565b9661159b604051988961359d565b875282870193010101913683116105bb57905b8282106117ba575050508151916115c483613875565b926115d2604051948561359d565b808452601f196115e182613875565b015f5b81811061179757505064ffffffffff4216916001600160801b0361160782613b52565b51511664ffffffffff80602061161c85613b52565b510151168501166040519161163083613548565b8252602082015261164086613b52565b5261164a85613b52565b5060015b8281106117225750505061166482600401613a00565b9261167160248401613a00565b9261167e6044820161392e565b916064820135936001600160a01b0385168095036105bb5760209661171a966116da966001600160801b0361170f976001600160a01b036116c160848a01613a14565b94816116cf60a48c01613a14565b976040519d8e61352b565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c3565b610100820152613e82565b604051908152f35b806001600160801b0361173760019385613b5f565b51511664ffffffffff8060206117505f1986018c613b5f565b510151168160206117618689613b5f565b5101511601166040519161177483613548565b825260208201526117858289613b5f565b526117908188613b5f565b500161164e565b6020906040516117a681613548565b5f81525f83820152828289010152016115e4565b60206040916117c9368561388d565b8152019101906115ae565b346105bb5760203660031901126105bb5760043560606101606040516117f981613564565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161183f81613581565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611aff576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b038516875261193c600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139ce565b6101208b0190815261194d89613c5a565b600581101561121957600214611af7575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119cc8c613564565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a209061395a565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b87916134cf565b5f875261195e565b634e487b7160e01b5f52604160045260245ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb57611b4490369060040161349e565b90611b4d613e28565b5f915b808310611b5957005b611b6483828461390a565b3592611b6e613e28565b835f52600a60205260ff600160405f20015460a81c1615611eb857835f52600a60205260ff600160405f20015460a01c165f14611bb85783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611ea657611bed815f52600a6020526001600160a01b0360405f205416331490565b15611e9057611bfb81613b73565b90805f52600a602052611c13600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081611c67948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e45575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d796001600160a01b03600160405f2001541694611d51888588614804565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dca575b50505050506001019190611b50565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e27575b5016036104975780808080611dbb565b611e3f915060203d81116104d1576104c3818361359d565b87611e17565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb1565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600b602052610b87611f0f60405f2061395a565b6040519182916020835260208301906134cf565b346105bb5760203660031901126105bb57600435611f3f613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57611f6381613c5a565b60058110156112195760048103611f875750634a5541ef60e01b5f5260045260245ffd5b60038103611fa2575063fe19f19f60e01b5f5260045260245ffd5b60021461205e57611fc7815f52600a6020526001600160a01b0360405f205416331490565b15611e9057805f52600a60205260ff60405f205460f01c161561204c576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105bb5760203660031901126105bb576004356001600160a01b0381168091036105bb576001600160a01b035f541633810361214b575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121375760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5761217a613424565b5f546001600160a01b03811633810361214b57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bb5760203660031901126105bb576001600160a01b036121f0613424565b16801561220d575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bb5760203660031901126105bb576020612257600435613b31565b6001600160a01b0360405191168152f35b346105bb5760203660031901126105bb57600435612284613942565b50805f52600a60205260ff600160405f20015460a81c161561062e575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122ce83613548565b825260208201526122f48251809264ffffffffff60208092828151168552015116910152565bf35b346105bb5760403660031901126105bb5760043567ffffffffffffffff81116105bb5761232790369060040161349e565b9060243567ffffffffffffffff81116105bb5761234890369060040161349e565b919092612353613e28565b82810361266c575f5b81811061236557005b61237081838561390a565b3561237c82848661390a565b355f5260036020526001600160a01b0360405f205416906123a66123a184888a61390a565b61392e565b916123af613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f52600a60205260ff600160405f20015460a01c16612659578015610998576001600160801b03831690811561098557825f5260036020526001600160a01b0360405f205416938482141580612649575b61262e576001600160801b0361243185614680565b16808411612614575061245690845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612490906139ce565b6001600160801b036124b48160208401511692826040818351169201511690613611565b1611156125e2575b825f52600a6020526001600160a01b03600160405f200154166124e0838383614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125cc575b612551575b5050505060010161235c565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125ae575b50160361049757808080612545565b6125c6915060203d81116104d1576104c3818361359d565b8961259f565b50835f52600960205260ff60405f205416612540565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124bc565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506126538461455b565b1561241c565b50634a5541ef60e01b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a506020916145cd565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f61270f82613c5a565b60058110156112195760020361272d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612720565b346105bb575f3660031901126105bb5760206001600160a01b0360085416604051908152f35b346105bb5760203660031901126105bb57600435612789613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c1615612906576127c88161455b565b15611e9057805f5260036020526001600160a01b0360405f2054161515806128ff575b806128e2575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612899575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288757005b637e27328960e01b5f5260045260245ffd5b6128b8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561283f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f1565b505f6127eb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb5761117c61294236613464565b906040519261295260208561359d565b5f8452613a21565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bb5760203660031901126105bb576004356129c6613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c165f14612a0f57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611ea657612a41815f52600a6020526001600160a01b0360405f205416331490565b15611e9057612a4f81613b73565b90805f52600a602052612a67600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081612abb948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c5c575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612ba56001600160a01b03600160405f2001541694611d51888588614804565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612be857005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c3d5750160361049757005b612c56915060203d6020116104d1576104c3818361359d565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b05565b346105bb5760203660031901126105bb57612c9a613424565b6001600160a01b035f541690338203612dd957806001600160a01b03913b15612dad57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d7e575b5015612d5357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da0915060203d602011612da6575b612d98818361359d565b8101906138f2565b82612d08565b503d612d8e565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb5761014060031982360301126105bb57612e2a613e28565b604051612e368161352b565b612e4282600401613450565b8152612e5060248301613450565b6020820152612e61604483016135db565b604082015260648201356001600160a01b03811681036105bb576060820152612e8c6084830161351e565b6080820152612e9d60a4830161351e565b60a0820152612eae60c48301613863565b60c082015260e482013567ffffffffffffffff81116105bb57820191366023840112156105bb57600483013592612ee484613875565b90612ef2604051928361359d565b848252602060048184019660061b83010101903682116105bb57602401945b818610612f3357602061171a8661170f878760e08401526101043691016138c3565b6020604091612f42368961388d565b815201950194612f11565b346105bb5760203660031901126105bb576001600160a01b03612f6e613424565b165f526009602052602060ff60405f2054166040519015158152f35b346105bb575f3660031901126105bb5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bb5761117c612fd536613464565b91613631565b346105bb575f3660031901126105bb576020600754604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761303090613c5a565b6005811015611219578060209115908115613051575b506040519015158152f35b600191501482613046565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576020905f90805f52600a835260ff60405f205460f01c16806130f1575b6130bf575b506001600160801b0360405191168152f35b6130eb9150805f52600a83526130e56001600160801b03600260405f2001541691613b73565b90613611565b826130ad565b50805f52600a835260ff600160405f20015460a01c16156130a8565b346105bb5760403660031901126105bb57613126613424565b60243561313281613b31565b331515806131ff575b806131cc575b6131a05781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613141565b50336001600160a01b038216141561313b565b346105bb5760203660031901126105bb5760206122576004356135ef565b346105bb575f3660031901126105bb576040515f6001548060011c906001811680156132e1575b60208310811461141c578285529081156113f8575060011461328357610b87836113868185038261359d565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132c757509091508101602001611386611376565b9192600181602092548385880101520191019092916132af565b91607f1691613257565b346105bb575f3660031901126105bb57602060405167016345785d8a00008152f35b346105bb5760203660031901126105bb57600435906001600160e01b031982168092036105bb57817f490649060000000000000000000000000000000000000000000000000000000060209314908115613369575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b4575b81156133a3575b5083613362565b6301ffc9a760e01b9150148361339c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613395565b5f5b8381106133ef5750505f910152565b81810151838201526020016133e0565b90602091613418815180928185528580860191016133de565b601f01601f1916010190565b600435906001600160a01b03821682036105bb57565b602435906001600160a01b03821682036105bb57565b35906001600160a01b03821682036105bb57565b60609060031901126105bb576004356001600160a01b03811681036105bb57906024356001600160a01b03811681036105bb579060443590565b9181601f840112156105bb5782359167ffffffffffffffff83116105bb576020808501948460051b0101116105bb57565b90602080835192838152019201905f5b8181106134ec5750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134df565b359081151582036105bb57565b610120810190811067ffffffffffffffff821117611aff57604052565b6040810190811067ffffffffffffffff821117611aff57604052565b610180810190811067ffffffffffffffff821117611aff57604052565b6060810190811067ffffffffffffffff821117611aff57604052565b90601f8019910116810190811067ffffffffffffffff821117611aff57604052565b67ffffffffffffffff8111611aff57601f01601f191660200190565b35906001600160801b03821682036105bb57565b6135f881613b31565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213757565b91906001600160a01b03168015610cef57815f5260036020526001600160a01b0360405f20541615158061385b575b8061383e575b61382b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613776575b6001600160a01b0393508561373f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61375e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136c6565b91929050806137d4575b1561378d578282916136b6565b82846137a557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613802575b806137805750825f526005602052336001600160a01b0360405f20541614613780565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137df565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613666565b506001613660565b359064ffffffffff821682036105bb57565b67ffffffffffffffff8111611aff5760051b60200190565b91908260409103126105bb576040516138a581613548565b60206138be8183956138b6816135db565b855201613863565b910152565b91908260409103126105bb576040516138db81613548565b60208082946138e981613450565b84520135910152565b908160209103126105bb575180151581036105bb5790565b919081101561391a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bb5790565b6040519061394f82613548565b5f6020838281520152565b90815461396681613875565b92613974604051948561359d565b81845260208401905f5260205f205f915b8383106139925750505050565b6001602081926040516139a481613548565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190613985565b906040516139db81613581565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bb5790565b3580151581036105bb5790565b90613a2d838284613631565b803b613a3a575b50505050565b602091613a806001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906133ff565b03815f865af15f9181613af0575b50613abc5750613a9c614651565b80519081613ab75782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ade57505f808080613a34565b633250574960e11b5f5260045260245ffd5b613b0a91925060203d6020116104d1576104c3818361359d565b905f613a8e565b908160209103126105bb57516001600160e01b0319811681036105bb5790565b805f5260036020526001600160a01b0360405f205416908115612887575090565b80511561391a5760200190565b805182101561391a5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9160405f2061395a565b908364ffffffffff6020613ba485613b52565b5101511611613c5357805f52600a6020528364ffffffffff60405f205460c81c161115613c3457506001600160801b03613bdd82613b52565b515116916001925b8251841015613c2d578464ffffffffff6020613c018787613b5f565b5101511611613c2d576001600160801b0360019181613c208787613b5f565b5151160116930192613be5565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c7c5750600490565b805f52600a60205260405f205460f81c613ce857805f52600a60205264ffffffffff60405f205460a01c164210613ce357613cb681613b73565b905f52600a6020526001600160801b0380600260405f200154169116105f14613cde57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e16575b80613df9575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc2575b1680613daa575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d66565b613de1835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d5f565b50805f52600a60205260ff600160405f20015460b01c1615613d13565b506001600160a01b0382161515613d0d565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5a57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea46001600160801b0360408401511660206101008501510151906146c6565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453357801561450b57815180156144e3577f000000000000000000000000000000000000000000000000000000000000000081116144b8575064ffffffffff6020613f1284613b52565b5101511681101561447457505f905f905f81515f905b8082106143ec575050505064ffffffffff804216911690818110156143be5750506001600160801b03169081810361439057505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f48751975f19890190613b5f565b51015160c81b169360a01b169116171785555f5b8181106142de575050600187016007556001600160a01b036020830151168015610cef5761413e886001600160a01b0392613cee565b166142b257868261418c6001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a3565b6001600160801b0360208401511680614282575b506001600160a01b03815116946142776142596001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141fe8b613548565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134cf565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142ac906001600160a01b036060840151166001600160a01b0361010085015151169033906147a3565b5f6141a0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142f98160e0870151613b5f565b5182549268010000000000000000841015611aff576001840180825584101561391a576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614108565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614410906001600160801b036144078588613b5f565b515116906146a6565b9364ffffffffff8060206144248685613b5f565b5101511694168085111561444057506001849301909291613f28565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448584613b52565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a1575b508115614588575090565b90506001600160a01b0361459c33926135ef565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f61457d565b805f52600a6020526145e4600260405f20016139ce565b90805f52600a60205260ff600160405f20015460a01c165f146146125750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614634575061463190613b73565b90565b61463191506001600160801b036040818351169201511690613611565b3d1561467b573d90614662826135bf565b91614670604051938461359d565b82523d5f602084013e565b606090565b6146319061468d816145cd565b905f52600a602052600260405f20015460801c90613611565b906001600160801b03809116911601906001600160801b03821161213757565b9190916040516146d581613548565b5f81525f6020820152926001600160801b0382169081156147865767016345785d8a0000811161474f576147116001600160801b0391836148d9565b166020850191818352111561473b576001600160801b03918261473692511690613611565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479781613548565b5f81525f602082015290565b9091926001600160a01b036148029481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526147fd60848361359d565b614854565b565b614802926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526147fd60648361359d565b5f806001600160a01b0361487d93169360208151910182865af1614876614651565b9083614987565b80519081151591826148be575b50506148935750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d192506020809183010191016138f2565b155f8061488a565b9091905f198382098382029182808310920391808303921461497657670de0b6b3a7640000821015614946577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c4575080511561499c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0a575b6149d5575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149cd56fea164736f6c634300081a000a"; + bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = + hex"608080604052346015576141d4908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e323876146105285780634d7c0f111461041e5763769bed201461003a575f80fd5b3461041a5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610089903690600401610a26565b6024359073ffffffffffffffffffffffffffffffffffffffff82169182810361041a5760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36011261041a57604051906100e382610972565b60443564ffffffffff8116810361041a57825260643564ffffffffff8116810361041a57602083015282519060208401511515836040860151926060870151608088015191604051806020810194602086526040820161014291610b48565b03601f1981018252610154908261098e565b60a08a01519360c08b015160405181819251908160208401916020019161017a92610b27565b81010380825261018d906020018261098e565b61019690610b6d565b9060e08c0151151592604051956020870198896101c59164ffffffffff60208092828151168552015116910152565b604087526101d460608861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161027c92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016102cb92610b27565b0160620103605501601f19810182526102e4908261098e565b51902060405161174880820182811067ffffffffffffffff8211176103ed578291610c9f83396080815261034160406103206080840189610bfe565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103e2576103a56103c7937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb89273ffffffffffffffffffffffffffffffffffffffff6020971695869560405194859460c0865260c0860190610bfe565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80fd5b3461041a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a573660238201121561041a5780600401359067ffffffffffffffff821161041a573660248360061b8301011161041a575f90815b838310156105095760248360061b830101359067ffffffffffffffff821680920361041a5767ffffffffffffffff160167ffffffffffffffff81116104dc57600190920191610492565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461041a5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610577903690600401610a26565b60243573ffffffffffffffffffffffffffffffffffffffff81169081810361041a576044359067ffffffffffffffff821161041a573660238301121561041a57816004013567ffffffffffffffff81116103ed57604051926105df60208360051b018561098e565b8184526024602085019260061b8201019036821161041a57602401915b818310610925575050505f9082515f905b8082106108cd5750508451906020860151151584604088015192606089015160808a015191604051806020810194602086526040820161064c91610b48565b03601f198101825261065e908261098e565b8b60a08101519460c082015160405181819251908160208401916020019161068592610b27565b810103808252610698906020018261098e565b6106a190610b6d565b9160e001511515926040519586602081019960208b52604082016106c491610bae565b03601f19810188526106d6908861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161077e92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016107cd92610b27565b0160620103605501601f19810182526107e6908261098e565b519020604051611de18082019082821067ffffffffffffffff8311176103ed578291610837916123e7843960608152610822606082018a610bfe565b90886020820152604081830391015286610bae565b03905ff580156103e2576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926108ac73ffffffffffffffffffffffffffffffffffffffff61089a941696879660405195869560c0875260c0870190610bfe565b918a8601528482036040860152610bae565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156108f85760019064ffffffffff6020808760051b890101510151160193019061060d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60408336031261041a576040519061093c82610972565b83359067ffffffffffffffff8216820361041a5782602092604094526109638387016109be565b838201528152019201916105fc565b6040810190811067ffffffffffffffff8211176103ed57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ed57604052565b3590811515820361041a57565b359064ffffffffff8216820361041a57565b81601f8201121561041a5780359067ffffffffffffffff82116103ed5760405192610a056020601f19601f860116018561098e565b8284526020838301011161041a57815f926020809301838601378301015290565b9190916101008184031261041a5760405190610100820182811067ffffffffffffffff8211176103ed576040528193813573ffffffffffffffffffffffffffffffffffffffff8116810361041a578352610a82602083016109b1565b6020840152610a93604083016109be565b6040840152606082013573ffffffffffffffffffffffffffffffffffffffff8116810361041a576060840152608082013567ffffffffffffffff811161041a5781610adf9184016109d0565b608084015260a082013560a084015260c08201359067ffffffffffffffff821161041a5782610b1760e09492610b22948694016109d0565b60c0860152016109b1565b910152565b5f5b838110610b385750505f910152565b8181015183820152602001610b29565b90601f19601f602093610b6681518092818752878088019101610b27565b0116010190565b602081519101519060208110610b81575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90602080835192838152019201905f5b818110610bcb5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610bbe565b9073ffffffffffffffffffffffffffffffffffffffff825116815260208201511515602082015264ffffffffff604083015116604082015273ffffffffffffffffffffffffffffffffffffffff606083015116606082015260e080610c93610c7760808601516101006080870152610100860190610b48565b60a086015160a086015260c086015185820360c0870152610b48565b93015115159101529056fe610160806040523461042857611748803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b60405161102490816107248239608051818181610481015281816106d60152610c20015260a0518181816107140152610b11015260c05181818161015f01528181610a6801528181610d8a0152610f49015260e0518181816102d3015261062201526101005181610e2801526101205181818161073e0152610ad50152610140518181816101af01526108870152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b63a52d539b60e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e12575080631686c90914610b3657806316c3549d14610afa5780631bfd681414610abe5780633bfe03a814610a905780633f31ae3f146104a55780634800d97f1461045557806349fc73dd1461031a5780634e390d3e146102f657806351e75e8b146102bc57806375829def146101ed57806390e64d13146101d35780639e93e57714610183578063bb4b573414610142578063ce516507146101025763f851a440146100cc575f80fd5b346100fe575f6003193601126100fe57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b346100fe5760206003193601126100fe57602061013860043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fe575f6003193601126100fe57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe576020610138610f41565b346100fe5760206003193601126100fe57610206610ec1565b5f5473ffffffffffffffffffffffffffffffffffffffff811633810361028d575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fe575f6003193601126100fe5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fe575f6003193601126100fe57602064ffffffffff60035416604051908152f35b346100fe575f6003193601126100fe576040515f6001548060011c9060018116801561044b575b60208310811461041e578285529081156103dc575060011461037e575b61037a8361036e81850382610f00565b60405191829182610e5b565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106103c25750909150810160200161036e61035e565b9192600181602092548385880101520191019092916103aa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b8401909101915061036e905061035e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610341565b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe5760806003193601126100fe5760043560243573ffffffffffffffffffffffffffffffffffffffff81168091036100fe57604435916fffffffffffffffffffffffffffffffff83168093036100fe576064359067ffffffffffffffff82116100fe57366023830112156100fe57816004013567ffffffffffffffff81116100fe578060051b92602484820101903682116100fe57604051602081019085825287604082015288606082015260608152610563608082610f00565b519020604051602081019182526020815261057f604082610f00565b5190209261058b610f41565b610a39576105b08560ff6001918060081c5f526002602052161b60405f205416151590565b610a0d576105c46020604051970187610f00565b8552602401602085015b8282106109fd57505050935f945b835186101561061e5760208660051b85010151908181105f1461060d575f52602052600160405f205b9501946105dc565b905f52602052600160405f20610605565b84907f0000000000000000000000000000000000000000000000000000000000000000036109d55760035464ffffffffff8116156109a1575b508260081c5f52600260205260405f20600160ff85161b815417905573ffffffffffffffffffffffffffffffffffffffff5f54169160405161069881610ee4565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176109745760405284526020840183815260408501838152606086017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f0000000000000000000000000000000000000000000000000000000000000000151584526040519461076e86610ee4565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b525173ffffffffffffffffffffffffffffffffffffffff1660048b01525173ffffffffffffffffffffffffffffffffffffffff1660248a0152516fffffffffffffffffffffffffffffffff1660448901525173ffffffffffffffffffffffffffffffffffffffff166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e485015251805173ffffffffffffffffffffffffffffffffffffffff166101048501526020015161012484015282807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165a925f61014492602095f1928315610969575f93610911575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610961575b8161092e60209383610f00565b810103126100fe5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6108d5565b3d9150610921565b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff161760035583610657565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016105ce565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100fe575f6003193601126100fe57604060045464ffffffffff825191818116835260281c166020820152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe5760406003193601126100fe57610b4f610ec1565b6024356fffffffffffffffffffffffffffffffff81168091036100fe5773ffffffffffffffffffffffffffffffffffffffff5f541633810361028d575064ffffffffff6003541680151580610dc4575b80610db5575b610d5b57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610c09606485610f00565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d4f573d67ffffffffffffffff811161097457610ca79160405191610c9760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f00565b82523d5f602084013e5b83610f7e565b8051908115159182610d2b575b5050610d0057507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fe57602001518015908115036100fe578480610cb4565b610ca790606090610ca1565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610dbe610f41565b15610ba5565b5062093a80810164ffffffffff8111610de55764ffffffffff164211610b9f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b346100fe575f6003193601126100fe5761037a907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036e604082610f00565b919091602081528251928360208301525f5b848110610eab5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201610e6d565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100fe57565b6040810190811067ffffffffffffffff82111761097457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761097457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f76575090565b905042101590565b90610fbb5750805115610f9357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061100e575b610fcc575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610fc456fea164736f6c634300081a000a610180806040523461044857611de1803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b60405161155e908161088382396080518181816105d10152818161095d0152611061015260a0518181816109870152610f52015260c0518181816102bb01528181610eac015281816111cb015261135d015260e05181818161042301526107b40152610100518161123c0152610120518181816109c20152610f160152610140518181816101390152610ac20152610160518181816102ff01526106980152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b63a52d539b60e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611226575080631686c90914610f7757806316c3549d14610f3b5780631bfd681414610eff5780633f31ae3f146105f55780634800d97f146105a557806349fc73dd1461046a5780634e390d3e1461044657806351e75e8b1461040c57806375829def1461033d57806390e64d1314610323578063936c63d9146102df578063bb4b57341461029e578063bf4ed03f1461019d578063ce5165071461015d578063da7924681461010d5763f851a440146100d7575f80fd5b34610109575f60031936011261010957602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461010957602060031936011261010957602061019360043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610109575f600319360112610109576004546101b981611392565b906101c76040519283611314565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610261578486604051918291602083019060208452518091526040830191905f5b81811061022b575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff16818601528695506040909401939092019160010161021d565b600160208192604051610273816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101f9565b34610109575f60031936011261010957602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f60031936011261010957602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f600319360112610109576020610193611355565b34610109576020600319360112610109576103566112d5565b5f5473ffffffffffffffffffffffffffffffffffffffff81163381036103dd575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610109575f6003193601126101095760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610109575f60031936011261010957602064ffffffffff60035416604051908152f35b34610109575f600319360112610109576040515f6001548060011c9060018116801561059b575b60208310811461056e5782855290811561052c57506001146104ce575b6104ca836104be81850382611314565b6040519182918261126f565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610512575090915081016020016104be6104ae565b9192600181602092548385880101520191019092916104fa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506104be90506104ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610491565b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109576080600319360112610109576004356024359073ffffffffffffffffffffffffffffffffffffffff821680920361010957604435916fffffffffffffffffffffffffffffffff831691828403610109576064359367ffffffffffffffff851161010957366023860112156101095784600401359467ffffffffffffffff86116101095760248660051b8201013681116101095767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ed457506040516020810190858252866040820152876060820152606081526106ee608082611314565b519020604051602081019182526020815261070a604082611314565b51902091610716611355565b610e7d5761073b8560ff6001918060081c5f526002602052161b60405f205416151590565b610e515761074888611392565b97610756604051998a611314565b8852602401602088015b828210610e4157505050925f935b86518510156107b05761078185886113aa565b51908181101561079f575f52602052600160405f205b94019361076e565b905f52602052600160405f20610797565b85907f000000000000000000000000000000000000000000000000000000000000000003610e195760035464ffffffffff811615610de5575b50600454926107f784611392565b936108056040519586611314565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610da857505050505f845161084b81611392565b956108596040519788611314565b8187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061088683611392565b015f5b818110610d855750505f905b828210610c7c5750506fffffffffffffffffffffffffffffffff8216848111610c4f578411610bfc575b5050508360081c5f52600260205260405f20600160ff86161b815417905573ffffffffffffffffffffffffffffffffffffffff5f541692604051610902816112f8565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610bcf5773ffffffffffffffffffffffffffffffffffffffff9660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526fffffffffffffffffffffffffffffffff60a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610b91575050508190602080945173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015203815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610b86575f93610b2e575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610b7e575b81610b4b60209383611314565b810103126101095792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af2565b3d9150610b3e565b6040513d5f823e3d90fd5b825180516fffffffffffffffffffffffffffffffff16855260209081015164ffffffffff168186015289955060409094019390920191600101610a71565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6fffffffffffffffffffffffffffffffff91610c3b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff849301886113aa565b5193031681835116011690528480806108bf565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b9092610c9d67ffffffffffffffff610c9486856113aa565b515116876113eb565b6fffffffffffffffffffffffffffffffff8111610d5a576fffffffffffffffffffffffffffffffff8091169164ffffffffff6020610cdb88876113aa565b5101511660405190610cec826112f8565b8482526020820152610cfe878c6113aa565b52610d09868b6113aa565b5016016fffffffffffffffffffffffffffffffff8111610d2d579260010190610895565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610d94816112f8565b5f81525f8382015282828c01015201610889565b600160208192604051610dba816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c1683820152815201920192019190610834565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff1617600355846107e9565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610760565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f4557880f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461010957604060031936011261010957610f906112d5565b6024356fffffffffffffffffffffffffffffffff81168091036101095773ffffffffffffffffffffffffffffffffffffffff5f54163381036103dd575064ffffffffff6003541680151580611205575b806111f6575b61119c57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb00000000000000000000000000000000000000000000000000000000875216948560248501528460448501526044845261104a606485611314565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15611190573d67ffffffffffffffff8111610bcf576110e891604051916110d860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611314565b82523d5f602084013e5b836114b8565b805190811515918261116c575b505061114157507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b819250906020918101031261010957602001518015908115036101095784806110f5565b6110e8906060906110e2565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506111ff611355565b15610fe6565b5062093a80810164ffffffffff8111610d2d5764ffffffffff164211610fe0565b34610109575f600319360112610109576104ca907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104be604082611314565b919091602081528251928360208301525f5b8481106112bf5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201611281565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361010957565b6040810190811067ffffffffffffffff821117610bcf57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bcf57604052565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161138a575090565b905042101590565b67ffffffffffffffff8111610bcf5760051b60200190565b80518210156113be5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146114a757670de0b6b3a7640000821015611477577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906114f557508051156114cd57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611548575b611506575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156114fe56fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615eaf908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a60646105438188066158b3565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906159b4565b60b76106ed5f615ca7565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615ca7565b98601b6028610a1a8c615db2565b610a2384615e2a565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615ca7565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615ca7565b9660b7610ac189615db2565b610aca8b615e2a565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615979565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615979565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615979565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615979565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bf8565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bf8565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c62565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c62565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b916158b3565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615889575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161585e575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615833575b8415615809575b508315615801575b5082156157f9575b5081156157f1575b50156157ea57600101615715565b5050505f90565b90505f6157dc565b91505f6157d4565b92505f6157cc565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6157c4565b7f7a0000000000000000000000000000000000000000000000000000000000000081111593506157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b806158c757506040516156cc602082614713565b600a81101561592d576158d990615408565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b81010301601f198101835282614713565b61593690615408565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b60405190615988604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615be8576159c2615979565b9061271003906127108211614b1157602e60619160506159e461482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a71815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615af882518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b59825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615c1b88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c5182518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c8588945180928580880191016146cd565b830164010714051160dd1b83820152615c5182518093856025850191016146cd565b6004811015614dc75780615cf15750604051615cc4604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d355750604051615d08604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d7757604051615d4a604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d85604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157ea5790600d915f925f925b828410615dd85750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e0c88856156ff565b511614615e22575b820194600101929190615dc5565b859450615e14565b5f90805180156157ea57906010915f925f925b828410615e50575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e8488856156ff565b511614615e9a575b820194600101929190615e3d565b859450615e8c56fea164736f6c634300081a000a"; + uint256 public constant MAX_SEGMENT_COUNT = 500; + uint256 public constant MAX_TRANCHE_COUNT = 500; + + /*////////////////////////////////////////////////////////////////////////// + CORE + //////////////////////////////////////////////////////////////////////////*/ + /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode, passing a default value for the /// `maxSegmentCount` parameter. /// @dev Notes: @@ -201,11 +205,6 @@ contract Precompiles { PERIPHERY //////////////////////////////////////////////////////////////////////////*/ - bytes public constant BYTECODE_BATCH_LOCKUP = - hex"60808060405234601557611e0a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd3146111a357806349a32c4014610e3e578063606ef87514610b025780639e743f29146107a6578063a514f83e1461040c5763f7ca34eb1461005b575f80fd5b3461033c5761006936611512565b91909282156103e4575f905f5b8481106103b057506001600160a01b036100939116918383611a7a565b61009c83611758565b926001600160a01b035f9316925b8181106100c357604051806100bf8782611587565b0390f35b6100ce818388611a17565b6100d7906117a7565b90826100e482828a611a17565b6020016100f0906117a7565b6100fb83838b611a17565b60400161010790611643565b9389610114858583611a17565b606001610120906117bb565b61012b868684611a17565b608001610137906117bb565b610142878785611a17565b60a00161014e90611a57565b918761015b818987611a17565b60c0810161016891611926565b98610174929196611a17565b60e0019360405195610185876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101ec9261197a565b9360e08601948552366101fe916118c8565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610353575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610312575b6001925061030b8288611901565b52016100aa565b506020823d8211610340575b8161032b602093836116ff565b8101031261033c57600191516102fd565b5f80fd5b3d915061031e565b6040513d5f823e3d90fd5b919493509160206060826103a1600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102be565b916001906fffffffffffffffffffffffffffffffff6103db60406103d5878a8c611a17565b01611643565b16019201610076565b7ff8bf106c000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c576104436115c0565b61044b6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610140870201011161033c5783156103e45790915f9190825b85811061077457506001600160a01b036104be9116928484611a7a565b6104c784611758565b926001600160a01b03165f5b8581106104e857604051806100bf8782611587565b6104fb6104f6828886611a69565b6117a7565b90610512602061050c838a88611a69565b016117a7565b878561052460406103d5868585611a69565b61053a6060610534878686611a69565b016117bb565b906101006105648761055d8188610557608061053484848d611a69565b98611a69565b968c611a69565b01906001600160a01b036040519861057b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c57604051956105fa876116e3565b61060660a08201611839565b875261061460c08201611839565b602088015260e00161062590611839565b604087015260c089019586523661063b916118c8565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff1661010484015251610124830161071291602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610348575f90610742575b6001925061073b8288611901565b52016104d3565b506020823d821161076c575b8161075b602093836116ff565b8101031261033c576001915161072d565b3d915061074e565b93926001906fffffffffffffffffffffffffffffffff61079a60406103d5898b89611a69565b160194019392936104a1565b3461033c576107b436611512565b91909282156103e4575f905f5b848110610ad457506001600160a01b036107de9116918383611a7a565b6107e783611758565b926001600160a01b035f9316925b81811061080a57604051806100bf8782611587565b610815818388611a17565b61081e906117a7565b908261082b82828a611a17565b602001610837906117a7565b61084283838b611a17565b60400161084e90611643565b938961085b858583611a17565b606001610867906117bb565b610872868684611a17565b60800161087e906117bb565b610889878785611a17565b60a00161089590611a57565b91876108a2818987611a17565b60c081016108af916117c8565b986108bb929196611a17565b60e00193604051956108cc876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906109339261184b565b9360e0860194855236610945916118c8565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610a8b575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610a59575b60019250610a528288611901565b52016107f5565b506020823d8211610a83575b81610a72602093836116ff565b8101031261033c5760019151610a44565b3d9150610a65565b91949350916020604082610ac5600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291610a05565b916001906fffffffffffffffffffffffffffffffff610af960406103d5878a8c611a17565b160192016107c1565b3461033c57610b1036611512565b91909282156103e4575f905f5b848110610e1057506001600160a01b03610b3a9116918383611a7a565b610b4383611758565b926001600160a01b035f9316925b818110610b6657604051806100bf8782611587565b610b718183886115d6565b610b7a906117a7565b9082610b8782828a6115d6565b602001610b93906117a7565b610b9e83838b6115d6565b604001610baa90611643565b9389610bb78585836115d6565b606001610bc3906117bb565b610bce8686846115d6565b608001610bda906117bb565b9086610be78188866115d6565b60a08101610bf491611926565b97610c009291956115d6565b60c0019260405194610c1186611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a0860193151584523690610c6a9261197a565b9260c0850193845236610c7c916118c8565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610db3575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90610d81575b60019250610d7a8288611901565b5201610b51565b506020823d8211610dab575b81610d9a602093836116ff565b8101031261033c5760019151610d6c565b3d9150610d8d565b91949350916020606082610e01600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610d2d565b916001906fffffffffffffffffffffffffffffffff610e3560406103d5878a8c6115d6565b16019201610b1d565b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c57610e756115c0565b610e7d6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610120870201011161033c5783156103e45790915f9190825b85811061117157506001600160a01b03610ef09116928484611a7a565b610ef984611758565b926001600160a01b03165f5b858110610f1a57604051806100bf8782611587565b610f286104f6828886611915565b90610f39602061050c838a88611915565b8785610f4b60406103d5868585611915565b610f5b6060610534878686611915565b9060e0610f8487610f7d8188610f77608061053484848d611915565b98611915565b968c611915565b01906001600160a01b0360405198610f9b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c576040519561101a876116aa565b61102660a08201611839565b875260c00161103490611839565b602087015260c089019586523661104a916118c8565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e484015251610104830161110f91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610348575f9061113f575b600192506111388288611901565b5201610f05565b506020823d8211611169575b81611158602093836116ff565b8101031261033c576001915161112a565b3d915061114b565b93926001906fffffffffffffffffffffffffffffffff61119760406103d5898b89611915565b16019401939293610ed3565b3461033c576111b136611512565b91909282156103e4575f905f5b84811061149d57506001600160a01b036111db9116918383611a7a565b6111e483611758565b926001600160a01b035f9316925b81811061120757604051806100bf8782611587565b6112128183886115d6565b61121b906117a7565b908261122882828a6115d6565b602001611234906117a7565b61123f83838b6115d6565b60400161124b90611643565b93896112588585836115d6565b606001611264906117bb565b61126f8686846115d6565b60800161127b906117bb565b90866112888188866115d6565b60a08101611295916117c8565b976112a19291956115d6565b60c00192604051946112b286611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a086019315158452369061130b9261184b565b9260c085019384523661131d916118c8565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611454575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90611422575b6001925061141b8288611901565b52016111f2565b506020823d821161144c575b8161143b602093836116ff565b8101031261033c576001915161140d565b3d915061142e565b9194935091602060408261148e600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b019501920186939492916113ce565b916001906fffffffffffffffffffffffffffffffff6114c260406103d5878a8c6115d6565b160192016111be565b602435906001600160a01b038216820361033c57565b9181601f8401121561033c5782359167ffffffffffffffff831161033c576020808501948460051b01011161033c57565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261033c576004356001600160a01b038116810361033c57916024356001600160a01b038116810361033c57916044359067ffffffffffffffff821161033c57611583916004016114e1565b9091565b60206040818301928281528451809452019201905f5b8181106115aa5750505090565b825184526020938401939092019160010161159d565b600435906001600160a01b038216820361033c57565b91908110156116165760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018136030182121561033c570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356fffffffffffffffffffffffffffffffff8116810361033c5790565b610100810190811067ffffffffffffffff82111761167d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761167d57604052565b610120810190811067ffffffffffffffff82111761167d57604052565b6060810190811067ffffffffffffffff82111761167d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761167d57604052565b67ffffffffffffffff811161167d5760051b60200190565b9061176282611740565b61176f60405191826116ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061179d8294611740565b0190602036910137565b356001600160a01b038116810361033c5790565b35801515810361033c5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c57602001918160061b3603831361033c57565b35906fffffffffffffffffffffffffffffffff8216820361033c57565b359064ffffffffff8216820361033c57565b92919261185782611740565b9361186560405195866116ff565b602085848152019260061b82019181831161033c57925b8284106118895750505050565b60408483031261033c57602060409182516118a3816116aa565b6118ac8761181c565b81526118b9838801611839565b8382015281520193019261187c565b919082604091031261033c576040516118e0816116aa565b809280356001600160a01b038116810361033c578252602090810135910152565b80518210156116165760209160051b010190565b919081101561161657610120020190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c5760200191606082023603831361033c57565b92919261198682611740565b9361199460405195866116ff565b606060208685815201930282019181831161033c57925b8284106119b85750505050565b60608483031261033c57604051906119cf826116e3565b6119d88561181c565b825260208501359067ffffffffffffffff8216820361033c5782602092836060950152611a0760408801611839565b60408201528152019301926119ab565b91908110156116165760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18136030182121561033c570190565b3564ffffffffff8116810361033c5790565b919081101561161657610140020190565b9190611acf6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015233602482015230604482015283606482015260648152611ac96084826116ff565b82611c8f565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103485784915f91611c42575b5010611b3b575b50505050565b5f806040519460208601907f095ea7b3000000000000000000000000000000000000000000000000000000008252876024880152604487015260448652611b836064876116ff565b85519082855af190611b93611d14565b82611c10575b5081611c05575b5015611bad575b80611b35565b611bf8611bfd93604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152611ac96064826116ff565b611c8f565b5f8080611ba7565b90503b15155f611ba0565b80519192508115918215611c28575b5050905f611b99565b611c3b9250602080918301019101611c77565b5f80611c1f565b9150506020813d602011611c6f575b81611c5e602093836116ff565b8101031261033c578390515f611b2e565b3d9150611c51565b9081602091031261033c5751801515810361033c5790565b5f806001600160a01b03611cb893169360208151910182865af1611cb1611d14565b9083611d71565b8051908115159182611cf9575b5050611cce5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611d0c9250602080918301019101611c77565b155f80611cc5565b3d15611d6c573d9067ffffffffffffffff821161167d5760405191611d6160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846116ff565b82523d5f602084013e565b606090565b90611dae5750805115611d8657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611df4575b611dbf575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611db756fea164736f6c634300081a000a"; - bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = - hex"608080604052346015576141d4908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e323876146105285780634d7c0f111461041e5763769bed201461003a575f80fd5b3461041a5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610089903690600401610a26565b6024359073ffffffffffffffffffffffffffffffffffffffff82169182810361041a5760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36011261041a57604051906100e382610972565b60443564ffffffffff8116810361041a57825260643564ffffffffff8116810361041a57602083015282519060208401511515836040860151926060870151608088015191604051806020810194602086526040820161014291610b48565b03601f1981018252610154908261098e565b60a08a01519360c08b015160405181819251908160208401916020019161017a92610b27565b81010380825261018d906020018261098e565b61019690610b6d565b9060e08c0151151592604051956020870198896101c59164ffffffffff60208092828151168552015116910152565b604087526101d460608861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161027c92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016102cb92610b27565b0160620103605501601f19810182526102e4908261098e565b51902060405161174880820182811067ffffffffffffffff8211176103ed578291610c9f83396080815261034160406103206080840189610bfe565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103e2576103a56103c7937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb89273ffffffffffffffffffffffffffffffffffffffff6020971695869560405194859460c0865260c0860190610bfe565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80fd5b3461041a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a573660238201121561041a5780600401359067ffffffffffffffff821161041a573660248360061b8301011161041a575f90815b838310156105095760248360061b830101359067ffffffffffffffff821680920361041a5767ffffffffffffffff160167ffffffffffffffff81116104dc57600190920191610492565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461041a5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610577903690600401610a26565b60243573ffffffffffffffffffffffffffffffffffffffff81169081810361041a576044359067ffffffffffffffff821161041a573660238301121561041a57816004013567ffffffffffffffff81116103ed57604051926105df60208360051b018561098e565b8184526024602085019260061b8201019036821161041a57602401915b818310610925575050505f9082515f905b8082106108cd5750508451906020860151151584604088015192606089015160808a015191604051806020810194602086526040820161064c91610b48565b03601f198101825261065e908261098e565b8b60a08101519460c082015160405181819251908160208401916020019161068592610b27565b810103808252610698906020018261098e565b6106a190610b6d565b9160e001511515926040519586602081019960208b52604082016106c491610bae565b03601f19810188526106d6908861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161077e92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016107cd92610b27565b0160620103605501601f19810182526107e6908261098e565b519020604051611de18082019082821067ffffffffffffffff8311176103ed578291610837916123e7843960608152610822606082018a610bfe565b90886020820152604081830391015286610bae565b03905ff580156103e2576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926108ac73ffffffffffffffffffffffffffffffffffffffff61089a941696879660405195869560c0875260c0870190610bfe565b918a8601528482036040860152610bae565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156108f85760019064ffffffffff6020808760051b890101510151160193019061060d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60408336031261041a576040519061093c82610972565b83359067ffffffffffffffff8216820361041a5782602092604094526109638387016109be565b838201528152019201916105fc565b6040810190811067ffffffffffffffff8211176103ed57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ed57604052565b3590811515820361041a57565b359064ffffffffff8216820361041a57565b81601f8201121561041a5780359067ffffffffffffffff82116103ed5760405192610a056020601f19601f860116018561098e565b8284526020838301011161041a57815f926020809301838601378301015290565b9190916101008184031261041a5760405190610100820182811067ffffffffffffffff8211176103ed576040528193813573ffffffffffffffffffffffffffffffffffffffff8116810361041a578352610a82602083016109b1565b6020840152610a93604083016109be565b6040840152606082013573ffffffffffffffffffffffffffffffffffffffff8116810361041a576060840152608082013567ffffffffffffffff811161041a5781610adf9184016109d0565b608084015260a082013560a084015260c08201359067ffffffffffffffff821161041a5782610b1760e09492610b22948694016109d0565b60c0860152016109b1565b910152565b5f5b838110610b385750505f910152565b8181015183820152602001610b29565b90601f19601f602093610b6681518092818752878088019101610b27565b0116010190565b602081519101519060208110610b81575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90602080835192838152019201905f5b818110610bcb5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610bbe565b9073ffffffffffffffffffffffffffffffffffffffff825116815260208201511515602082015264ffffffffff604083015116604082015273ffffffffffffffffffffffffffffffffffffffff606083015116606082015260e080610c93610c7760808601516101006080870152610100860190610b48565b60a086015160a086015260c086015185820360c0870152610b48565b93015115159101529056fe610160806040523461042857611748803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b60405161102490816107248239608051818181610481015281816106d60152610c20015260a0518181816107140152610b11015260c05181818161015f01528181610a6801528181610d8a0152610f49015260e0518181816102d3015261062201526101005181610e2801526101205181818161073e0152610ad50152610140518181816101af01526108870152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b63a52d539b60e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e12575080631686c90914610b3657806316c3549d14610afa5780631bfd681414610abe5780633bfe03a814610a905780633f31ae3f146104a55780634800d97f1461045557806349fc73dd1461031a5780634e390d3e146102f657806351e75e8b146102bc57806375829def146101ed57806390e64d13146101d35780639e93e57714610183578063bb4b573414610142578063ce516507146101025763f851a440146100cc575f80fd5b346100fe575f6003193601126100fe57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b346100fe5760206003193601126100fe57602061013860043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fe575f6003193601126100fe57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe576020610138610f41565b346100fe5760206003193601126100fe57610206610ec1565b5f5473ffffffffffffffffffffffffffffffffffffffff811633810361028d575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fe575f6003193601126100fe5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fe575f6003193601126100fe57602064ffffffffff60035416604051908152f35b346100fe575f6003193601126100fe576040515f6001548060011c9060018116801561044b575b60208310811461041e578285529081156103dc575060011461037e575b61037a8361036e81850382610f00565b60405191829182610e5b565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106103c25750909150810160200161036e61035e565b9192600181602092548385880101520191019092916103aa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b8401909101915061036e905061035e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610341565b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe5760806003193601126100fe5760043560243573ffffffffffffffffffffffffffffffffffffffff81168091036100fe57604435916fffffffffffffffffffffffffffffffff83168093036100fe576064359067ffffffffffffffff82116100fe57366023830112156100fe57816004013567ffffffffffffffff81116100fe578060051b92602484820101903682116100fe57604051602081019085825287604082015288606082015260608152610563608082610f00565b519020604051602081019182526020815261057f604082610f00565b5190209261058b610f41565b610a39576105b08560ff6001918060081c5f526002602052161b60405f205416151590565b610a0d576105c46020604051970187610f00565b8552602401602085015b8282106109fd57505050935f945b835186101561061e5760208660051b85010151908181105f1461060d575f52602052600160405f205b9501946105dc565b905f52602052600160405f20610605565b84907f0000000000000000000000000000000000000000000000000000000000000000036109d55760035464ffffffffff8116156109a1575b508260081c5f52600260205260405f20600160ff85161b815417905573ffffffffffffffffffffffffffffffffffffffff5f54169160405161069881610ee4565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176109745760405284526020840183815260408501838152606086017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f0000000000000000000000000000000000000000000000000000000000000000151584526040519461076e86610ee4565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b525173ffffffffffffffffffffffffffffffffffffffff1660048b01525173ffffffffffffffffffffffffffffffffffffffff1660248a0152516fffffffffffffffffffffffffffffffff1660448901525173ffffffffffffffffffffffffffffffffffffffff166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e485015251805173ffffffffffffffffffffffffffffffffffffffff166101048501526020015161012484015282807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165a925f61014492602095f1928315610969575f93610911575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610961575b8161092e60209383610f00565b810103126100fe5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6108d5565b3d9150610921565b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff161760035583610657565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016105ce565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100fe575f6003193601126100fe57604060045464ffffffffff825191818116835260281c166020820152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe5760406003193601126100fe57610b4f610ec1565b6024356fffffffffffffffffffffffffffffffff81168091036100fe5773ffffffffffffffffffffffffffffffffffffffff5f541633810361028d575064ffffffffff6003541680151580610dc4575b80610db5575b610d5b57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610c09606485610f00565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d4f573d67ffffffffffffffff811161097457610ca79160405191610c9760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f00565b82523d5f602084013e5b83610f7e565b8051908115159182610d2b575b5050610d0057507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fe57602001518015908115036100fe578480610cb4565b610ca790606090610ca1565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610dbe610f41565b15610ba5565b5062093a80810164ffffffffff8111610de55764ffffffffff164211610b9f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b346100fe575f6003193601126100fe5761037a907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036e604082610f00565b919091602081528251928360208301525f5b848110610eab5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201610e6d565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100fe57565b6040810190811067ffffffffffffffff82111761097457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761097457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f76575090565b905042101590565b90610fbb5750805115610f9357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061100e575b610fcc575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610fc456fea164736f6c634300081a000a610180806040523461044857611de1803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b60405161155e908161088382396080518181816105d10152818161095d0152611061015260a0518181816109870152610f52015260c0518181816102bb01528181610eac015281816111cb015261135d015260e05181818161042301526107b40152610100518161123c0152610120518181816109c20152610f160152610140518181816101390152610ac20152610160518181816102ff01526106980152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b63a52d539b60e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611226575080631686c90914610f7757806316c3549d14610f3b5780631bfd681414610eff5780633f31ae3f146105f55780634800d97f146105a557806349fc73dd1461046a5780634e390d3e1461044657806351e75e8b1461040c57806375829def1461033d57806390e64d1314610323578063936c63d9146102df578063bb4b57341461029e578063bf4ed03f1461019d578063ce5165071461015d578063da7924681461010d5763f851a440146100d7575f80fd5b34610109575f60031936011261010957602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461010957602060031936011261010957602061019360043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610109575f600319360112610109576004546101b981611392565b906101c76040519283611314565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610261578486604051918291602083019060208452518091526040830191905f5b81811061022b575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff16818601528695506040909401939092019160010161021d565b600160208192604051610273816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101f9565b34610109575f60031936011261010957602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f60031936011261010957602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f600319360112610109576020610193611355565b34610109576020600319360112610109576103566112d5565b5f5473ffffffffffffffffffffffffffffffffffffffff81163381036103dd575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610109575f6003193601126101095760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610109575f60031936011261010957602064ffffffffff60035416604051908152f35b34610109575f600319360112610109576040515f6001548060011c9060018116801561059b575b60208310811461056e5782855290811561052c57506001146104ce575b6104ca836104be81850382611314565b6040519182918261126f565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610512575090915081016020016104be6104ae565b9192600181602092548385880101520191019092916104fa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506104be90506104ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610491565b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109576080600319360112610109576004356024359073ffffffffffffffffffffffffffffffffffffffff821680920361010957604435916fffffffffffffffffffffffffffffffff831691828403610109576064359367ffffffffffffffff851161010957366023860112156101095784600401359467ffffffffffffffff86116101095760248660051b8201013681116101095767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ed457506040516020810190858252866040820152876060820152606081526106ee608082611314565b519020604051602081019182526020815261070a604082611314565b51902091610716611355565b610e7d5761073b8560ff6001918060081c5f526002602052161b60405f205416151590565b610e515761074888611392565b97610756604051998a611314565b8852602401602088015b828210610e4157505050925f935b86518510156107b05761078185886113aa565b51908181101561079f575f52602052600160405f205b94019361076e565b905f52602052600160405f20610797565b85907f000000000000000000000000000000000000000000000000000000000000000003610e195760035464ffffffffff811615610de5575b50600454926107f784611392565b936108056040519586611314565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610da857505050505f845161084b81611392565b956108596040519788611314565b8187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061088683611392565b015f5b818110610d855750505f905b828210610c7c5750506fffffffffffffffffffffffffffffffff8216848111610c4f578411610bfc575b5050508360081c5f52600260205260405f20600160ff86161b815417905573ffffffffffffffffffffffffffffffffffffffff5f541692604051610902816112f8565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610bcf5773ffffffffffffffffffffffffffffffffffffffff9660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526fffffffffffffffffffffffffffffffff60a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610b91575050508190602080945173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015203815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610b86575f93610b2e575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610b7e575b81610b4b60209383611314565b810103126101095792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af2565b3d9150610b3e565b6040513d5f823e3d90fd5b825180516fffffffffffffffffffffffffffffffff16855260209081015164ffffffffff168186015289955060409094019390920191600101610a71565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6fffffffffffffffffffffffffffffffff91610c3b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff849301886113aa565b5193031681835116011690528480806108bf565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b9092610c9d67ffffffffffffffff610c9486856113aa565b515116876113eb565b6fffffffffffffffffffffffffffffffff8111610d5a576fffffffffffffffffffffffffffffffff8091169164ffffffffff6020610cdb88876113aa565b5101511660405190610cec826112f8565b8482526020820152610cfe878c6113aa565b52610d09868b6113aa565b5016016fffffffffffffffffffffffffffffffff8111610d2d579260010190610895565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610d94816112f8565b5f81525f8382015282828c01015201610889565b600160208192604051610dba816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c1683820152815201920192019190610834565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff1617600355846107e9565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610760565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f4557880f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461010957604060031936011261010957610f906112d5565b6024356fffffffffffffffffffffffffffffffff81168091036101095773ffffffffffffffffffffffffffffffffffffffff5f54163381036103dd575064ffffffffff6003541680151580611205575b806111f6575b61119c57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb00000000000000000000000000000000000000000000000000000000875216948560248501528460448501526044845261104a606485611314565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15611190573d67ffffffffffffffff8111610bcf576110e891604051916110d860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611314565b82523d5f602084013e5b836114b8565b805190811515918261116c575b505061114157507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b819250906020918101031261010957602001518015908115036101095784806110f5565b6110e8906060906110e2565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506111ff611355565b15610fe6565b5062093a80810164ffffffffff8111610d2d5764ffffffffff164211610fe0565b34610109575f600319360112610109576104ca907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104be604082611314565b919091602081528251928360208301525f5b8481106112bf5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201611281565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361010957565b6040810190811067ffffffffffffffff821117610bcf57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bcf57604052565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161138a575090565b905042101590565b67ffffffffffffffff8111610bcf5760051b60200190565b80518210156113be5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146114a757670de0b6b3a7640000821015611477577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906114f557508051156114cd57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611548575b611506575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156114fe56fea164736f6c634300081a000aa164736f6c634300081a000a"; - /// @notice Deploys {SablierV2BatchLockup} from precompiled bytecode. function deployBatchLockup() public returns (ISablierV2BatchLockup batchLockup) { bytes memory creationBytecode = BYTECODE_BATCH_LOCKUP; diff --git a/remappings.txt b/remappings.txt index b384a1744..8f1a7a740 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,7 +1,5 @@ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @prb/math/=node_modules/@prb/math/ -core/=src/core/ forge-std/=node_modules/forge-std/ -periphery/=src/periphery/ solady/=node_modules/solady/ -solarray/=node_modules/solarray/ \ No newline at end of file +solarray/=node_modules/solarray/ diff --git a/test/core/Base.t.sol b/test/Base.t.sol similarity index 70% rename from test/core/Base.t.sol rename to test/Base.t.sol index 4e22a7d83..9908c0445 100644 --- a/test/core/Base.t.sol +++ b/test/Base.t.sol @@ -3,14 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { ISablierV2MerkleLockupFactory } from "src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ISablierV2BatchLockup } from "src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { SablierV2BatchLockup } from "src/periphery/SablierV2BatchLockup.sol"; +import { SablierV2MerkleLockupFactory } from "src/periphery/SablierV2MerkleLockupFactory.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; @@ -37,14 +41,16 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ + ISablierV2BatchLockup internal batchLockup; ERC20Mock internal dai; Defaults internal defaults; - RecipientGood internal recipientGood; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; ISablierV2LockupTranched internal lockupTranched; + ISablierV2MerkleLockupFactory internal merkleLockupFactory; ISablierV2NFTDescriptor internal nftDescriptor; Noop internal noop; + RecipientGood internal recipientGood; ERC20MissingReturn internal usdt; /*////////////////////////////////////////////////////////////////////////// @@ -64,44 +70,53 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.label({ account: address(noop), newLabel: "Noop" }); vm.label({ account: address(usdt), newLabel: "USDT" }); - // Deploy the defaults contract. - defaults = new Defaults(); - defaults.setAsset(dai); - // Create the protocol admin. users.admin = payable(makeAddr({ name: "Admin" })); vm.startPrank({ msgSender: users.admin }); - // Deploy the V2 Core contracts. - deployCoreConditionally(); + // Deploy the defaults contract. + defaults = new Defaults(); + defaults.setAsset(dai); + + // Deploy the protocol. + deployProtocolConditionally(); // Create users for testing. users.alice = createUser("Alice"); users.broker = createUser("Broker"); users.eve = createUser("Eve"); users.operator = createUser("Operator"); - users.recipient = createUser("Recipient"); + users.recipient0 = createUser("Recipient0"); + users.recipient1 = createUser("Recipient1"); + users.recipient2 = createUser("Recipient2"); + users.recipient3 = createUser("Recipient3"); + users.recipient4 = createUser("Recipient4"); users.sender = createUser("Sender"); defaults.setUsers(users); + defaults.initMerkleTree(); - // Warp to May 1, 2024 at 00:00 GMT to provide a more realistic testing environment. - vm.warp({ newTimestamp: MAY_1_2024 }); + // Warp to July 1, 2024 at 00:00 UTC to provide a more realistic testing environment. + vm.warp({ newTimestamp: JULY_1_2024 }); } /*////////////////////////////////////////////////////////////////////////// HELPERS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Approves all V2 Core contracts to spend assets from the address passed. + /// @dev Approves all contracts to spend assets from the address passed. function approveProtocol(address from) internal { resetPrank({ msgSender: from }); + dai.approve({ spender: address(batchLockup), value: MAX_UINT256 }); dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + dai.approve({ spender: address(merkleLockupFactory), value: MAX_UINT256 }); + usdt.approve({ spender: address(batchLockup), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + usdt.approve({ spender: address(merkleLockupFactory), value: MAX_UINT256 }); } /// @dev Generates a user, labels its address, funds it with test assets, and approves the protocol contracts. @@ -114,25 +129,29 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi return user; } - /// @dev Conditionally deploys V2 Core normally or from an optimized source compiled with `--via-ir`. - /// We cannot use the {DeployCore} script because some tests rely on hard coded addresses for the + /// @dev Conditionally deploys the protocol normally or from an optimized source compiled with `--via-ir`. + /// We cannot use the {DeployProtocol} script because some tests rely on hard coded addresses for the /// deployed contracts. Since the script itself would have to be deployed, using it would bump the /// deployer's nonce, which would in turn lead to different addresses (recall that the addresses /// for contracts deployed via `CREATE` are based on the caller-and-nonce-hash). - function deployCoreConditionally() internal { + function deployProtocolConditionally() internal { if (!isBenchmarkProfile() && !isTestOptimizedProfile()) { + batchLockup = new SablierV2BatchLockup(); nftDescriptor = new SablierV2NFTDescriptor(); lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); lockupTranched = new SablierV2LockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); + merkleLockupFactory = new SablierV2MerkleLockupFactory(); } else { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = - deployOptimizedCore(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); + (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor, batchLockup, merkleLockupFactory) = + deployOptimizedProtocol(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); } + vm.label({ account: address(batchLockup), newLabel: "BatchLockup" }); vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); + vm.label({ account: address(merkleLockupFactory), newLabel: "MerkleLockupFactory" }); vm.label({ account: address(nftDescriptor), newLabel: "NFTDescriptor" }); } diff --git a/test/core/fork/Fork.t.sol b/test/core/fork/Fork.t.sol index 93fd79188..dd76cd5fc 100644 --- a/test/core/fork/Fork.t.sol +++ b/test/core/fork/Fork.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import { Base_Test } from "../Base.t.sol"; +import { Base_Test } from "../../Base.t.sol"; /// @notice Common logic needed by all fork tests. abstract contract Fork_Test is Base_Test { diff --git a/test/core/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol index d325a520b..14b18495b 100644 --- a/test/core/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/core/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol index 5fb558779..18dcd40ac 100644 --- a/test/core/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -5,7 +5,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; +import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/core/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol index 9d2d637c0..5ab8bb50c 100644 --- a/test/core/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/core/fork/NFTDescriptor.t.sol b/test/core/fork/NFTDescriptor.t.sol index c0c5dd374..4a55cb355 100644 --- a/test/core/fork/NFTDescriptor.t.sol +++ b/test/core/fork/NFTDescriptor.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; import { Fork_Test } from "./Fork.t.sol"; diff --git a/test/core/integration/Integration.t.sol b/test/core/integration/Integration.t.sol index 873211cd5..469165d0f 100644 --- a/test/core/integration/Integration.t.sol +++ b/test/core/integration/Integration.t.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; -import { Base_Test } from "../Base.t.sol"; +import { Base_Test } from "../../Base.t.sol"; import { RecipientInterfaceIDIncorrect, RecipientInterfaceIDMissing, RecipientInvalidSelector, RecipientReentrant, RecipientReverting -} from "../mocks/Hooks.sol"; +} from "../../mocks/Hooks.sol"; /// @notice Common logic needed by all integration tests, both concrete and fuzz tests. @@ -19,11 +19,11 @@ abstract contract Integration_Test is Base_Test { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - RecipientInterfaceIDIncorrect internal recipientInterfaceIDIncorrect = new RecipientInterfaceIDIncorrect(); - RecipientInterfaceIDMissing internal recipientInterfaceIDMissing = new RecipientInterfaceIDMissing(); - RecipientInvalidSelector internal recipientInvalidSelector = new RecipientInvalidSelector(); - RecipientReentrant internal recipientReentrant = new RecipientReentrant(); - RecipientReverting internal recipientReverting = new RecipientReverting(); + RecipientInterfaceIDIncorrect internal recipientInterfaceIDIncorrect; + RecipientInterfaceIDMissing internal recipientInterfaceIDMissing; + RecipientInvalidSelector internal recipientInvalidSelector; + RecipientReentrant internal recipientReentrant; + RecipientReverting internal recipientReverting; /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION @@ -32,11 +32,16 @@ abstract contract Integration_Test is Base_Test { function setUp() public virtual override { Base_Test.setUp(); - // Label the contracts. - labelContracts(); - - // Make the Admin the default caller in this test suite. - resetPrank({ msgSender: users.admin }); + recipientInterfaceIDIncorrect = new RecipientInterfaceIDIncorrect(); + recipientInterfaceIDMissing = new RecipientInterfaceIDMissing(); + recipientInvalidSelector = new RecipientInvalidSelector(); + recipientReentrant = new RecipientReentrant(); + recipientReverting = new RecipientReverting(); + vm.label({ account: address(recipientInterfaceIDIncorrect), newLabel: "Recipient Interface ID Incorrect" }); + vm.label({ account: address(recipientInterfaceIDMissing), newLabel: "Recipient Interface ID Missing" }); + vm.label({ account: address(recipientInvalidSelector), newLabel: "Recipient Invalid Selector" }); + vm.label({ account: address(recipientReentrant), newLabel: "Recipient Reentrant" }); + vm.label({ account: address(recipientReverting), newLabel: "Recipient Reverting" }); } /*////////////////////////////////////////////////////////////////////////// @@ -44,13 +49,7 @@ abstract contract Integration_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ /// @dev Labels the most relevant contracts. - function labelContracts() internal { - vm.label({ account: address(recipientInterfaceIDIncorrect), newLabel: "Recipient Interface ID Incorrect" }); - vm.label({ account: address(recipientInterfaceIDMissing), newLabel: "Recipient Interface ID Missing" }); - vm.label({ account: address(recipientInvalidSelector), newLabel: "Recipient Invalid Selector" }); - vm.label({ account: address(recipientReentrant), newLabel: "Recipient Reentrant" }); - vm.label({ account: address(recipientReverting), newLabel: "Recipient Reverting" }); - } + function labelContracts() internal { } /*////////////////////////////////////////////////////////////////////////// EXPECT CALLS diff --git a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index 7adc4ccb2..5f115da8b 100644 --- a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol index 3f9742355..8bbfd69f4 100644 --- a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupDynamic } from "core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupDynamic } from "src/core/SablierV2LockupDynamic.sol"; import { LockupDynamic_Integration_Concrete_Test } from "./LockupDynamic.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 3fe80fedd..5d7baf4c2 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; @@ -146,7 +146,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -179,7 +179,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 069a2b8a1..d076dfada 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -4,12 +4,12 @@ pragma solidity >=0.8.22 <0.9.0; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; @@ -217,7 +217,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentTimestampsOrdered whenEndTimeInTheFuture { - UD60x18 brokerFee = ZERO; resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. @@ -225,8 +224,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: brokerFee }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.totalAmount = depositAmount; // Expect the relevant error to be thrown. @@ -355,7 +353,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), segments: defaults.segments(), asset: IERC20(asset), @@ -386,7 +384,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol index 47026fad5..972f9df07 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupDynamic } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol index 68b77c6bf..75e3505e3 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupDynamic } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol index 1f3f1df3b..1d573d2b3 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupDynamic } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol index dd9affc2f..675d03ddb 100644 --- a/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupDynamic } from "core/types/DataTypes.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; diff --git a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol index 2362e29d9..04e1370ed 100644 --- a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -67,7 +67,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); diff --git a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol index 895121535..7fe2bf7cf 100644 --- a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/constructor.t.sol b/test/core/integration/concrete/lockup-linear/constructor.t.sol index eec4dcad9..d51a1e113 100644 --- a/test/core/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/core/integration/concrete/lockup-linear/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupLinear } from "core/SablierV2LockupLinear.sol"; +import { SablierV2LockupLinear } from "src/core/SablierV2LockupLinear.sol"; import { LockupLinear_Integration_Concrete_Test } from "./LockupLinear.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index e7e0139de..039d06d58 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; @@ -109,7 +109,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -141,7 +141,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index a4a409680..45435e9be 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -6,9 +6,9 @@ import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093 import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; @@ -103,7 +103,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } @@ -260,7 +260,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), asset: IERC20(asset), cancelable: true, @@ -290,7 +290,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol index ee13ca50e..4aa27d570 100644 --- a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol index 62e1034ad..c511f0e4b 100644 --- a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupLinear } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol index 26f400997..4fd3a2aa4 100644 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupLinear } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol index 69d3eff06..e5b2c5c6f 100644 --- a/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "core/types/DataTypes.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; diff --git a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol index c5a6d9d44..a65fa35c4 100644 --- a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -47,7 +47,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test is } modifier givenPreviousWithdrawals() { - lockupLinear.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockupLinear.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); _; } diff --git a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol index 463c8d176..48c052a22 100644 --- a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup-tranched/constructor.t.sol b/test/core/integration/concrete/lockup-tranched/constructor.t.sol index 668ac7883..ed3549a60 100644 --- a/test/core/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/core/integration/concrete/lockup-tranched/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupTranched } from "core/SablierV2LockupTranched.sol"; +import { SablierV2LockupTranched } from "src/core/SablierV2LockupTranched.sol"; import { LockupTranched_Integration_Concrete_Test } from "./LockupTranched.t.sol"; diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index f5c990fd5..08b50dc23 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; @@ -140,7 +140,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -173,7 +173,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 2e10b625b..471125ae8 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -4,12 +4,12 @@ pragma solidity >=0.8.22 <0.9.0; import { Address } from "@openzeppelin/contracts/utils/Address.sol"; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; @@ -217,7 +217,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheTimestampsOrdered whenEndTimeInTheFuture { - UD60x18 brokerFee = ZERO; resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. @@ -225,8 +224,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); - params.broker = Broker({ account: address(0), fee: brokerFee }); + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLT(); params.totalAmount = depositAmount; // Expect the relevant error to be thrown. @@ -355,7 +353,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), tranches: defaults.tranches(), asset: IERC20(asset), @@ -386,7 +384,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol index 18eea60ed..0a422bbd3 100644 --- a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupTranched } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol index 246d9d138..70c53323c 100644 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupTranched } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol index 999b7572c..0b3a8dc05 100644 --- a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { LockupTranched } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; diff --git a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol index 0f1ea9bd2..a7ae4d8f6 100644 --- a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -66,7 +66,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Make the withdrawal. - lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); + lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.CLIFF_AMOUNT() }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); diff --git a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol index fe3277531..3de46aedc 100644 --- a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol +++ b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/burn/burn.t.sol b/test/core/integration/concrete/lockup/burn/burn.t.sol index 3b088a575..437e3f5f8 100644 --- a/test/core/integration/concrete/lockup/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup/burn/burn.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -18,7 +18,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int notTransferableStreamId = createDefaultStreamNotTransferable(); // Make the Recipient (owner of the NFT) the caller in this test suite. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } function test_RevertWhen_DelegateCalled() external { @@ -87,14 +87,14 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); resetPrank({ msgSender: users.sender }); lockup.cancel(streamId); - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } modifier givenStreamHasBeenDepleted(uint256 streamId_) { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: streamId_, to: users.recipient }); + lockup.withdrawMax({ streamId: streamId_, to: users.recipient0 }); _; } diff --git a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index 4d4070fb9..e5cf0114e 100644 --- a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; import { CancelMultiple_Integration_Shared_Test } from "../../../shared/lockup/cancelMultiple.t.sol"; @@ -81,11 +81,11 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient0) ); lockup.cancelMultiple(testStreamIds); } @@ -120,11 +120,11 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient0) ); lockup.cancelMultiple(testStreamIds); } @@ -181,7 +181,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is emit CancelLockupStream({ streamId: testStreamIds[0], sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, asset: dai, senderAmount: senderAmount0, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 @@ -190,7 +190,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is emit CancelLockupStream({ streamId: testStreamIds[1], sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, asset: dai, senderAmount: senderAmount1, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1 @@ -213,7 +213,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is assertEq(lockup.getRefundedAmount(testStreamIds[1]), senderAmount1, "refundedAmount1"); // Assert that the NFTs have not been burned. - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(lockup.getRecipient(testStreamIds[0]), expectedNFTOwner, "NFT owner0"); assertEq(lockup.getRecipient(testStreamIds[1]), expectedNFTOwner, "NFT owner1"); } diff --git a/test/core/integration/concrete/lockup/cancel/cancel.t.sol b/test/core/integration/concrete/lockup/cancel/cancel.t.sol index d9ceab13d..0aec17acc 100644 --- a/test/core/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup/cancel/cancel.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Cancel_Integration_Shared_Test } from "../../../shared/lockup/cancel.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -29,7 +29,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenNotNull givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } @@ -72,11 +72,11 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient0) ); lockup.cancel(defaultStreamId); } diff --git a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol index 493415714..ac0dc7346 100644 --- a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol +++ b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol index 4bca8251c..053daa048 100644 --- a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol index 7667d95e2..ccfe7d643 100644 --- a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol +++ b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol index 8bfcd06ae..13b38625c 100644 --- a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol @@ -28,10 +28,10 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Deplete the stream. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Burn the NFT. lockup.burn(defaultStreamId); @@ -47,7 +47,7 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo function test_GetRecipient() external view givenNotNull givenNFTNotBurned { address actualRecipient = lockup.getRecipient(defaultStreamId); - address expectedRecipient = users.recipient; + address expectedRecipient = users.recipient0; assertEq(actualRecipient, expectedRecipient, "recipient"); } } diff --git a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index 1b023fe19..86b56cde8 100644 --- a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -45,7 +45,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); @@ -78,7 +78,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes function test_GetRefundedAmount_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); diff --git a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol index f38bf95bc..d8cf16469 100644 --- a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol +++ b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol index ebb36a2cc..21eabfdfb 100644 --- a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol +++ b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index 8a577c704..fd6198386 100644 --- a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { GetWithdrawnAmount_Integration_Shared_Test } from "../../../shared/lockup/getWithdrawnAmount.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -38,7 +38,7 @@ abstract contract GetWithdrawnAmount_Integration_Concrete_Test is uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol index 746d469d1..5cb73a2db 100644 --- a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol index 9d7c5e4dd..657a73e6e 100644 --- a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -49,7 +49,7 @@ abstract contract IsCold_Integration_Concrete_Test is Integration_Test, Lockup_I function test_IsCold_StatusDepleted() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); bool isCold = lockup.isCold(defaultStreamId); assertTrue(isCold, "isCold"); } diff --git a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 2ebf0d1b0..6404a05e8 100644 --- a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -29,7 +29,7 @@ abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test, Lock modifier givenStreamDepleted() { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); _; } diff --git a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol index edd6344f5..8686ff1c5 100644 --- a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol +++ b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol index cf7576c4c..06b017503 100644 --- a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -49,7 +49,7 @@ abstract contract IsWarm_Integration_Concrete_Test is Integration_Test, Lockup_I function test_IsWarm_StatusDepleted() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); bool isWarm = lockup.isWarm(defaultStreamId); assertFalse(isWarm, "isWarm"); } diff --git a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index 402d8e97e..b6f1a419d 100644 --- a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -60,7 +60,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedRefundableAmount = 0; @@ -114,7 +114,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = 0; assertEq(actualRefundableAmount, expectedReturnableAmount, "refundableAmount"); diff --git a/test/core/integration/concrete/lockup/renounce/renounce.t.sol b/test/core/integration/concrete/lockup/renounce/renounce.t.sol index 024cb3d71..66cc4e4e7 100644 --- a/test/core/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup/renounce/renounce.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -40,7 +40,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } diff --git a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol index d15459774..0b7a57f7a 100644 --- a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; +import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol index f24d64701..4f7d34151 100644 --- a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -25,7 +25,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup function test_StatusOf_AssetsFullyWithdrawn() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.DEPLETED; assertEq(actualStatus, expectedStatus); diff --git a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index b431e8afe..3de2649f5 100644 --- a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../../shared/lockup/streamedAmountOf.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -40,7 +40,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); @@ -63,7 +63,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is function test_StreamedAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); diff --git a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 699aa0573..a63c105fb 100644 --- a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } function test_RevertGiven_StreamNotTransferable() external { @@ -16,7 +16,7 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) ); - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: notTransferableStreamId }); + lockup.transferFrom({ from: users.recipient0, to: users.alice, tokenId: notTransferableStreamId }); } modifier givenStreamTransferable() { @@ -31,10 +31,10 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient, to: users.alice, tokenId: streamId }); + emit Transfer({ from: users.recipient0, to: users.alice, tokenId: streamId }); // Transfer the NFT. - lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: streamId }); + lockup.transferFrom({ from: users.recipient0, to: users.alice, tokenId: streamId }); // Assert that Alice is the new stream recipient (and NFT owner). address actualRecipient = lockup.getRecipient(streamId); diff --git a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol index 6d4abfd1d..9875a113d 100644 --- a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol +++ b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; diff --git a/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol index 6f31b4a3d..f7b2157a5 100644 --- a/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; import { Integration_Test } from "../../../Integration.t.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; diff --git a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 27f0179a7..3f2c26638 100644 --- a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { WithdrawMaxAndTransfer_Integration_Shared_Test } from "../../../shared/lockup/withdrawMaxAndTransfer.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -24,7 +24,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient }); + lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient0 }); } function test_RevertWhen_CallerNotCurrentRecipient() external whenNotDelegateCalled givenNotNull { @@ -41,14 +41,14 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertGiven_NFTBurned() external whenNotDelegateCalled givenNotNull whenCallerCurrentRecipient { // Deplete the stream. vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Burn the NFT. lockup.burn({ streamId: defaultStreamId }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient0) ); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -61,7 +61,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is givenNFTNotBurned { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -77,7 +77,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) ); - lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient }); + lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient0 }); } function test_WithdrawMaxAndTransfer() @@ -96,20 +96,20 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); + expectCallToTransfer({ to: users.recipient0, value: expectedWithdrawnAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, amount: expectedWithdrawnAmount, asset: dai }); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: defaultStreamId }); vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId }); + emit Transfer({ from: users.recipient0, to: users.alice, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. uint128 actualWithdrawnAmount = diff --git a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index 4f730f28c..260128e87 100644 --- a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { WithdrawMax_Integration_Shared_Test } from "../../../shared/lockup/withdrawMax.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -16,19 +16,19 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient0, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, amount: defaults.DEPOSIT_AMOUNT(), asset: dai }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -46,7 +46,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -58,19 +58,19 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); + expectCallToTransfer({ to: users.recipient0, value: expectedWithdrawnAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, amount: expectedWithdrawnAmount, asset: dai }); // Make the max withdrawal. - uint128 actualWithdrawnAmount = lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + uint128 actualWithdrawnAmount = lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Assert that the withdrawn amount has been updated. assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); diff --git a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index 0ceff35f7..dc47ab507 100644 --- a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { WithdrawMultiple_Integration_Shared_Test } from "../../../shared/lockup/withdrawMultiple.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -97,7 +97,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. - lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); + lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient0 }); // Expect the relevant error to be thrown. vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); @@ -117,7 +117,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. - lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); + lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient0 }); // Expect the relevant error to be thrown. vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); @@ -190,29 +190,29 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is resetPrank({ msgSender: caller }); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient, value: testAmounts[0] }); - expectCallToTransfer({ to: users.recipient, value: testAmounts[1] }); - expectCallToTransfer({ to: users.recipient, value: testAmounts[2] }); + expectCallToTransfer({ to: users.recipient0, value: testAmounts[0] }); + expectCallToTransfer({ to: users.recipient0, value: testAmounts[1] }); + expectCallToTransfer({ to: users.recipient0, value: testAmounts[2] }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[0], - to: users.recipient, + to: users.recipient0, asset: dai, amount: testAmounts[0] }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[1], - to: users.recipient, + to: users.recipient0, asset: dai, amount: testAmounts[1] }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[2], - to: users.recipient, + to: users.recipient0, asset: dai, amount: testAmounts[2] }); @@ -231,8 +231,8 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is assertEq(lockup.getWithdrawnAmount(testStreamIds[2]), testAmounts[2], "withdrawnAmount2"); // Assert that the stream NFTs have not been burned. - assertEq(lockup.getRecipient(testStreamIds[0]), users.recipient, "NFT owner0"); - assertEq(lockup.getRecipient(testStreamIds[1]), users.recipient, "NFT owner1"); - assertEq(lockup.getRecipient(testStreamIds[2]), users.recipient, "NFT owner2"); + assertEq(lockup.getRecipient(testStreamIds[0]), users.recipient0, "NFT owner0"); + assertEq(lockup.getRecipient(testStreamIds[1]), users.recipient0, "NFT owner1"); + assertEq(lockup.getRecipient(testStreamIds[2]), users.recipient0, "NFT owner2"); } } diff --git a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol index 4acd47016..d14bef221 100644 --- a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupRecipient } from "core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Withdraw_Integration_Shared_Test } from "../../../shared/lockup/withdraw.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -22,7 +22,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = - abi.encodeCall(ISablierV2Lockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); + abi.encodeCall(ISablierV2Lockup.withdraw, (defaultStreamId, users.recipient0, withdrawAmount)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -31,16 +31,16 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint256 nullStreamId = 1729; uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockup.withdraw({ streamId: nullStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: nullStreamId, to: users.recipient0, amount: withdrawAmount }); } function test_RevertGiven_StreamDepleted() external whenNotDelegateCalled givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); } function test_RevertWhen_ToZeroAddress() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { @@ -57,7 +57,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenToNonZeroAddress { vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: 0 }); } function test_RevertWhen_Overdraw() @@ -74,7 +74,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr Errors.SablierV2Lockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: MAX_UINT128 }); } function test_RevertWhen_CallerUnknown() @@ -139,7 +139,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawalAddressNotRecipient { // Transfer the stream to Alice. - lockup.transferFrom(users.recipient, users.alice, defaultStreamId); + lockup.transferFrom(users.recipient0, users.alice, defaultStreamId); // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -147,11 +147,11 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr abi.encodeWithSelector( Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, - users.recipient, - users.recipient + users.recipient0, + users.recipient0 ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); } function test_Withdraw_CallerApprovedOperator() @@ -233,7 +233,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -255,7 +255,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -278,7 +278,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.DEPOSIT_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.DEPOSIT_AMOUNT() }); // Assert that the stream's status is "DEPLETED". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -291,7 +291,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -314,7 +314,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); // Assert that the stream's status is "DEPLETED". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -328,7 +328,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index 3b426e740..f038c2b3e 100644 --- a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../../shared/lockup/withdrawableAmountOf.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -40,7 +40,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; @@ -63,7 +63,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is function test_WithdrawableAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); diff --git a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol index d064e9c3f..6e2e65231 100644 --- a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -8,7 +8,7 @@ contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integrat // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. // Note: the address of `noop` depends on the order of the state variables in {Base_Test}. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); - string memory expectedColor = "hsl(302,69%,44%)"; + string memory expectedColor = "hsl(182,56%,46%)"; assertEq(actualColor, expectedColor, "accentColor"); } } diff --git a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 1c4cda800..7f201dc66 100644 --- a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import { MockERC721 } from "forge-std/src/mocks/MockERC721.sol"; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; diff --git a/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol b/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol index f2e1e9a10..098546b13 100644 --- a/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol +++ b/test/core/integration/concrete/nft-descriptor/safe-asset-symbol/safeAssetSymbol.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ERC20Mock } from "../../../../mocks/erc20/ERC20Mock.sol"; -import { ERC20Bytes32 } from "../../../../mocks/erc20/ERC20Bytes32.sol"; +import { ERC20Mock } from "test/mocks/erc20/ERC20Mock.sol"; +import { ERC20Bytes32 } from "test/mocks/erc20/ERC20Bytes32.sol"; import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { diff --git a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index e9ad097f4..1d21f46be 100644 --- a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 748c86951..7d359064c 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; @@ -48,7 +48,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is fuzzSegmentDurations(segments); // Fuzz the segment amounts and calculate the total and create amounts (deposit and broker fee). - (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(segments); + (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(segments, defaults.BROKER_FEE()); // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; @@ -77,7 +77,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is streamId: streamId, funder: vars.funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: vars.createAmounts, asset: dai, cancelable: true, @@ -108,7 +108,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, users.recipient, "recipient"); + assertEq(actualStream.recipient, users.recipient0, "recipient"); assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); assertEq(actualStream.startTime, timestamps.start, "startTime"); @@ -126,7 +126,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is // Assert that the NFT has been minted. vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - vars.expectedNFTOwner = users.recipient; + vars.expectedNFTOwner = users.recipient0; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index be9cf8c4e..c715db7bd 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; @@ -101,7 +101,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); - UD60x18 brokerFee = ZERO; resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. @@ -109,8 +108,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: brokerFee }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.totalAmount = depositAmount; // Expect the relevant error to be thrown. diff --git a/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 903c2a1de..54b73fc9c 100644 --- a/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; @@ -50,19 +50,17 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: segment.amount }); // Create the stream with the fuzzed segment. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.segments = segments; params.totalAmount = segment.amount; uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForOneSegment(blockTimestamp, segment); + uint128 expectedStreamedAmount = calculateStreamedAmountForOneSegment(segment, defaults.START_TIME()); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -111,20 +109,18 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.segments = segments; params.totalAmount = totalAmount; uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); uint128 expectedStreamedAmount = - calculateStreamedAmountForMultipleSegments(blockTimestamp, segments, totalAmount); + calculateStreamedAmountForMultipleSegments(segments, defaults.START_TIME(), totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -160,8 +156,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.segments = segments; params.totalAmount = totalAmount; uint256 streamId = lockupDynamic.createWithTimestamps(params); diff --git a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index ad9fe96b9..9c5fe5399 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; @@ -59,7 +59,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is fuzzSegmentTimestamps(params.segments, defaults.START_TIME()); // Fuzz the segment amounts. - (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(params.segments); + (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts(params.segments, defaults.BROKER_FEE()); // Bound the time jump. vars.totalDuration = params.segments[params.segments.length - 1].timestamp - defaults.START_TIME(); @@ -102,7 +102,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is emit MetadataUpdate({ _tokenId: vars.streamId }); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); diff --git a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 75e072380..1f3b672d3 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupDynamic_Integration_Fuzz_Test } from "./LockupDynamic.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; @@ -39,9 +37,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: ZERO }); - params.totalAmount = defaults.DEPOSIT_AMOUNT(); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); uint256 streamId = lockupDynamic.createWithTimestamps(params); // Simulate the passage of time. @@ -50,8 +46,9 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); - uint128 expectedWithdrawableAmount = - calculateStreamedAmountForMultipleSegments(blockTimestamp, defaults.segments(), defaults.DEPOSIT_AMOUNT()); + uint128 expectedWithdrawableAmount = calculateStreamedAmountForMultipleSegments( + defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT() + ); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -77,28 +74,25 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is whenStartTimeInThePast whenWithWithdrawals { - timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); - - // Define the block timestamp. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - - // Bound the withdraw amount. - uint128 streamedAmount = - calculateStreamedAmountForMultipleSegments(blockTimestamp, defaults.segments(), defaults.DEPOSIT_AMOUNT()); - withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); - // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsLD(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); params.totalAmount = defaults.DEPOSIT_AMOUNT(); uint256 streamId = lockupDynamic.createWithTimestamps(params); + timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); + // Simulate the passage of time. - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); + + // Bound the withdraw amount. + uint128 streamedAmount = calculateStreamedAmountForMultipleSegments( + defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT() + ); + withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockupDynamic.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol index 4fd89a475..2ad974487 100644 --- a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol index 99110ea36..50613f004 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; -import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; @@ -79,7 +79,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -111,7 +111,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index ed21c874c..8f46bdebb 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; diff --git a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index dfbebb5f7..40a02712d 100644 --- a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Broker, LockupLinear } from "core/types/DataTypes.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; @@ -64,18 +62,17 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); params.totalAmount = depositAmount; uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmount(blockTimestamp, depositAmount); + uint128 expectedStreamedAmount = + calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -98,7 +95,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); params.totalAmount = depositAmount; uint256 streamId = lockupLinear.createWithTimestamps(params); diff --git a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index bd2215173..ed871061e 100644 --- a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -1,9 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ZERO } from "@prb/math/src/UD60x18.sol"; - -import { Broker, LockupLinear } from "core/types/DataTypes.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupLinear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; @@ -61,18 +59,17 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); params.totalAmount = depositAmount; uint256 streamId = lockupLinear.createWithTimestamps(params); // Simulate the passage of time. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); - uint128 expectedWithdrawableAmount = calculateStreamedAmount(blockTimestamp, depositAmount); + uint128 expectedWithdrawableAmount = + calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -102,30 +99,27 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is whenCliffTimeNotInTheFuture givenPreviousWithdrawals { - timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); depositAmount = boundUint128(depositAmount, 10_000, MAX_UINT128); - // Define the block timestamp. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - - // Bound the withdraw amount. - uint128 streamedAmount = calculateStreamedAmount(blockTimestamp, depositAmount); - withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); - // Mint enough assets to the Sender. deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); - params.broker = Broker({ account: address(0), fee: ZERO }); + LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); params.totalAmount = depositAmount; uint256 streamId = lockupLinear.createWithTimestamps(params); + timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); + // Simulate the passage of time. - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); + + // Bound the withdraw amount. + uint128 streamedAmount = calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); + withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupLinear.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockupLinear.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol index 2d382dc05..3b9d4565b 100644 --- a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 0e4c32ad5..eadeff6ab 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { CreateWithDurations_Integration_Shared_Test } from "../../shared/lockup/createWithDurations.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; @@ -48,7 +48,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is fuzzTrancheDurations(tranches); // Fuzz the tranche amounts and calculate the total and create amounts (deposit and broker fee). - (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(tranches); + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(tranches, defaults.BROKER_FEE()); // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; @@ -77,7 +77,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is streamId: streamId, funder: vars.funder, sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, amounts: vars.createAmounts, asset: dai, cancelable: true, @@ -126,7 +126,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is // Assert that the NFT has been minted. vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - vars.expectedNFTOwner = users.recipient; + vars.expectedNFTOwner = users.recipient0; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 93b378073..308768340 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MAX_UD60x18, UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; +import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { Errors } from "core/libraries/Errors.sol"; -import { Broker, Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { CreateWithTimestamps_Integration_Shared_Test } from "../../shared/lockup/createWithTimestamps.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; @@ -101,7 +101,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); - UD60x18 brokerFee = ZERO; resetPrank({ msgSender: users.sender }); // Adjust the default deposit amount. @@ -109,8 +108,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); - params.broker = Broker({ account: address(0), fee: brokerFee }); + LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLT(); params.totalAmount = depositAmount; // Expect the relevant error to be thrown. diff --git a/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index c098248b7..468366ea9 100644 --- a/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "core/types/DataTypes.sol"; +import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Shared_Test } from "../../shared/lockup/streamedAmountOf.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; @@ -79,7 +79,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is // Run the test. uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(blockTimestamp, tranches, totalAmount); + uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(tranches, totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 0e365247b..1bc5349e2 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; @@ -59,7 +59,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is fuzzTrancheTimestamps(params.tranches, defaults.START_TIME()); // Fuzz the tranche amounts. - (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(params.tranches); + (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts(params.tranches, defaults.BROKER_FEE()); // Bound the time jump. vars.totalDuration = params.tranches[params.tranches.length - 1].timestamp - defaults.START_TIME(); @@ -93,7 +93,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Expect the assets to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); diff --git a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index c29fbfded..868e2b014 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "core/types/DataTypes.sol"; +import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupTranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; import { WithdrawableAmountOf_Integration_Shared_Test } from "../../shared/lockup/withdrawableAmountOf.t.sol"; @@ -51,7 +51,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = - calculateStreamedAmountForTranches(blockTimestamp, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + calculateStreamedAmountForTranches(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -77,16 +77,6 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is whenStartTimeInThePast whenWithWithdrawals { - timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); - - // Define the block timestamp. - uint40 blockTimestamp = defaults.START_TIME() + timeJump; - - // Bound the withdraw amount. - uint128 streamedAmount = - calculateStreamedAmountForTranches(blockTimestamp, defaults.tranches(), defaults.DEPOSIT_AMOUNT()); - withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); - // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); @@ -94,11 +84,17 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is params.totalAmount = defaults.DEPOSIT_AMOUNT(); uint256 streamId = lockupTranched.createWithTimestamps(params); + timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); + // Simulate the passage of time. - vm.warp({ newTimestamp: blockTimestamp }); + vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); + + // Bound the withdraw amount. + uint128 streamedAmount = calculateStreamedAmountForTranches(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockupTranched.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup/cancel.t.sol b/test/core/integration/fuzz/lockup/cancel.t.sol index dd3bfbac3..1208bcdbc 100644 --- a/test/core/integration/fuzz/lockup/cancel.t.sol +++ b/test/core/integration/fuzz/lockup/cancel.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Cancel_Integration_Shared_Test } from "../../shared/lockup/cancel.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; diff --git a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol index e48874d9c..9e0957777 100644 --- a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; import { CancelMultiple_Integration_Shared_Test } from "../../shared/lockup/cancelMultiple.t.sol"; @@ -47,7 +47,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc emit CancelLockupStream({ streamId: streamIds[0], sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, asset: dai, senderAmount: senderAmount0, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 @@ -56,7 +56,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc emit CancelLockupStream({ streamId: streamIds[1], sender: users.sender, - recipient: users.recipient, + recipient: users.recipient0, asset: dai, senderAmount: senderAmount1, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1 @@ -84,7 +84,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc assertEq(lockup.getRefundedAmount(streamIds[1]), expectedRefundedAmount1, "refundedAmount1"); // Assert that the NFTs have not been burned. - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(lockup.getRecipient(streamIds[0]), expectedNFTOwner, "NFT owner0"); assertEq(lockup.getRecipient(streamIds[1]), expectedNFTOwner, "NFT owner1"); } diff --git a/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol index 71da96105..3b8bdfded 100644 --- a/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol +++ b/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol @@ -42,7 +42,7 @@ abstract contract GetWithdrawnAmount_Integration_Fuzz_Test is withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/fuzz/lockup/withdraw.t.sol b/test/core/integration/fuzz/lockup/withdraw.t.sol index 3f2936013..594a1ff4d 100644 --- a/test/core/integration/fuzz/lockup/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup/withdraw.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Withdraw_Integration_Shared_Test } from "../../shared/lockup/withdraw.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -22,7 +22,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I whenWithdrawAmountNotZero whenNoOverdraw { - vm.assume(caller != users.sender && caller != users.recipient); + vm.assume(caller != users.sender && caller != users.recipient0); // Make the fuzzed address the caller in this test. resetPrank({ msgSender: caller }); @@ -31,7 +31,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -108,7 +108,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Cancel the stream. resetPrank({ msgSender: users.sender }); lockup.cancel({ streamId: defaultStreamId }); - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); // Bound the withdraw amount. uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); @@ -142,7 +142,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -212,7 +212,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup/withdrawMax.t.sol b/test/core/integration/fuzz/lockup/withdrawMax.t.sol index b65902e2c..41760fb22 100644 --- a/test/core/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { WithdrawMax_Integration_Shared_Test } from "../../shared/lockup/withdrawMax.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -18,19 +18,19 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient0, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, asset: dai, amount: defaults.DEPOSIT_AMOUNT() }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -48,7 +48,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient; + address expectedNFTOwner = users.recipient0; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -62,19 +62,19 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient0, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, asset: dai, amount: withdrawAmount }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol index ecde8780a..cd4fb11e2 100644 --- a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol @@ -38,13 +38,13 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is if (withdrawAmount > 0) { // Expect the assets to be transferred to the fuzzed recipient. - expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient0, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient, + to: users.recipient0, asset: dai, amount: withdrawAmount }); @@ -52,7 +52,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient, to: newRecipient, tokenId: defaultStreamId }); + emit Transfer({ from: users.recipient0, to: newRecipient, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: newRecipient }); diff --git a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol index f26f14bb5..ab72262a4 100644 --- a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { WithdrawMultiple_Integration_Shared_Test } from "../../shared/lockup/withdrawMultiple.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -52,21 +52,21 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is ongoingWithdrawAmount = boundUint128(ongoingWithdrawAmount, 1, ongoingWithdrawableAmount); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient, value: ongoingWithdrawAmount }); - expectCallToTransfer({ to: users.recipient, value: settledWithdrawAmount }); + expectCallToTransfer({ to: users.recipient0, value: ongoingWithdrawAmount }); + expectCallToTransfer({ to: users.recipient0, value: settledWithdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: ongoingStreamId, - to: users.recipient, + to: users.recipient0, asset: dai, amount: ongoingWithdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: settledStreamId, - to: users.recipient, + to: users.recipient0, asset: dai, amount: settledWithdrawAmount }); @@ -85,7 +85,7 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is assertEq(lockup.getWithdrawnAmount(streamIds[1]), amounts[1], "withdrawnAmount1"); // Assert that the stream NFTs have not been burned. - assertEq(lockup.getRecipient(streamIds[0]), users.recipient, "NFT owner0"); - assertEq(lockup.getRecipient(streamIds[1]), users.recipient, "NFT owner1"); + assertEq(lockup.getRecipient(streamIds[0]), users.recipient0, "NFT owner0"); + assertEq(lockup.getRecipient(streamIds[1]), users.recipient0, "NFT owner1"); } } diff --git a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol index f8e0d9cc4..0bdcfaaa3 100644 --- a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupDynamic } from "core/types/DataTypes.sol"; +import { Broker, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; @@ -22,7 +22,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh Lockup_Integration_Shared_Test.setUp(); _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient; + _params.createWithDurations.recipient = users.recipient0; _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithDurations.asset = dai; _params.createWithDurations.cancelable = true; @@ -30,7 +30,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh _params.createWithDurations.broker = defaults.broker(); _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient; + _params.createWithTimestamps.recipient = users.recipient0; _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithTimestamps.asset = dai; _params.createWithTimestamps.cancelable = true; diff --git a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol index ea7972452..2e5451cc8 100644 --- a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupLinear } from "core/types/DataTypes.sol"; +import { Broker, LockupLinear } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; diff --git a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol index b89a1d766..90a675ffa 100644 --- a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Broker, LockupTranched } from "core/types/DataTypes.sol"; +import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; @@ -22,7 +22,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S Lockup_Integration_Shared_Test.setUp(); _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient; + _params.createWithDurations.recipient = users.recipient0; _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithDurations.asset = dai; _params.createWithDurations.cancelable = true; @@ -30,7 +30,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S _params.createWithDurations.broker = defaults.broker(); _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient; + _params.createWithTimestamps.recipient = users.recipient0; _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithTimestamps.asset = dai; _params.createWithTimestamps.cancelable = true; diff --git a/test/core/integration/shared/lockup/Lockup.t.sol b/test/core/integration/shared/lockup/Lockup.t.sol index 52bedf3f9..1600c47cc 100644 --- a/test/core/integration/shared/lockup/Lockup.t.sol +++ b/test/core/integration/shared/lockup/Lockup.t.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Broker } from "core/types/DataTypes.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Broker } from "src/core/types/DataTypes.sol"; -import { Base_Test } from "test/core/Base.t.sol"; +import { Base_Test } from "test/Base.t.sol"; /// @dev This contracts avoids duplicating test logic for {SablierV2LockupLinear} and {SablierV2LockupDynamic}; /// both of these contracts inherit from {SablierV2Lockup}. @@ -24,8 +24,7 @@ abstract contract Lockup_Integration_Shared_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public virtual override { - // Make the Sender the default caller in this test suite. - resetPrank({ msgSender: users.sender }); + Base_Test.setUp(); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol b/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol index e7a3985ca..dfce20e73 100644 --- a/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol +++ b/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol @@ -7,7 +7,7 @@ abstract contract GetWithdrawnAmount_Integration_Shared_Test is Lockup_Integrati uint256 internal defaultStreamId; function setUp() public virtual override { - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } modifier givenNotNull() { diff --git a/test/core/integration/shared/lockup/withdraw.t.sol b/test/core/integration/shared/lockup/withdraw.t.sol index 75fe7fa5e..d5c53369c 100644 --- a/test/core/integration/shared/lockup/withdraw.t.sol +++ b/test/core/integration/shared/lockup/withdraw.t.sol @@ -8,7 +8,7 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } modifier givenEndTimeInTheFuture() { diff --git a/test/core/integration/shared/lockup/withdrawMax.t.sol b/test/core/integration/shared/lockup/withdrawMax.t.sol index f19c3323c..0ce0623a6 100644 --- a/test/core/integration/shared/lockup/withdrawMax.t.sol +++ b/test/core/integration/shared/lockup/withdrawMax.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMax_Integration_Shared_Test is Lockup_Integration_Shar function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } modifier givenEndTimeInTheFuture() { diff --git a/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol index 222cb78eb..03c5bd4b0 100644 --- a/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Shared_Test is Lockup_Integ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); } modifier givenNFTNotBurned() { diff --git a/test/core/integration/shared/lockup/withdrawMultiple.t.sol b/test/core/integration/shared/lockup/withdrawMultiple.t.sol index ca236ecff..cd5e98baf 100644 --- a/test/core/integration/shared/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/shared/lockup/withdrawMultiple.t.sol @@ -58,12 +58,12 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration caller = users.sender; _; createTestStreams(); - caller = users.recipient; - resetPrank({ msgSender: users.recipient }); + caller = users.recipient0; + resetPrank({ msgSender: users.recipient0 }); _; createTestStreams(); caller = users.operator; - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); lockup.setApprovalForAll({ operator: users.operator, approved: true }); caller = users.operator; resetPrank({ msgSender: users.operator }); diff --git a/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol b/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol index d7dd5099f..2af3595c3 100644 --- a/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol +++ b/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "../../Integration.t.sol"; -import { NFTDescriptorMock } from "../../../mocks/NFTDescriptorMock.sol"; +import { NFTDescriptorMock } from "test/mocks/NFTDescriptorMock.sol"; abstract contract NFTDescriptor_Integration_Shared_Test is Integration_Test { NFTDescriptorMock internal nftDescriptorMock; diff --git a/test/core/invariant/Invariant.t.sol b/test/core/invariant/Invariant.t.sol index df5b9fe67..36981f2d0 100644 --- a/test/core/invariant/Invariant.t.sol +++ b/test/core/invariant/Invariant.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { StdInvariant } from "forge-std/src/StdInvariant.sol"; -import { Base_Test } from "../Base.t.sol"; +import { Base_Test } from "../../Base.t.sol"; /// @notice Common logic needed by all invariant tests. abstract contract Invariant_Test is Base_Test, StdInvariant { diff --git a/test/core/invariant/Lockup.t.sol b/test/core/invariant/Lockup.t.sol index 494b4087e..f4df1aad5 100644 --- a/test/core/invariant/Lockup.t.sol +++ b/test/core/invariant/Lockup.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Invariant_Test } from "./Invariant.t.sol"; import { LockupHandler } from "./handlers/LockupHandler.sol"; diff --git a/test/core/invariant/LockupDynamic.t.sol b/test/core/invariant/LockupDynamic.t.sol index 0f26354db..6a3550a35 100644 --- a/test/core/invariant/LockupDynamic.t.sol +++ b/test/core/invariant/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupDynamic } from "core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupDynamicCreateHandler } from "./handlers/LockupDynamicCreateHandler.sol"; diff --git a/test/core/invariant/LockupLinear.t.sol b/test/core/invariant/LockupLinear.t.sol index edc236569..cf96445ae 100644 --- a/test/core/invariant/LockupLinear.t.sol +++ b/test/core/invariant/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupLinearHandler } from "./handlers/LockupLinearHandler.sol"; diff --git a/test/core/invariant/LockupTranched.t.sol b/test/core/invariant/LockupTranched.t.sol index ed1ab2b7f..586516132 100644 --- a/test/core/invariant/LockupTranched.t.sol +++ b/test/core/invariant/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupTranchedCreateHandler } from "./handlers/LockupTranchedCreateHandler.sol"; diff --git a/test/core/invariant/handlers/BaseHandler.sol b/test/core/invariant/handlers/BaseHandler.sol index fdd804cdb..1abd58e39 100644 --- a/test/core/invariant/handlers/BaseHandler.sol +++ b/test/core/invariant/handlers/BaseHandler.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { StdCheats } from "forge-std/src/StdCheats.sol"; -import { Constants } from "../../utils/Constants.sol"; -import { Fuzzers } from "../../utils/Fuzzers.sol"; +import { Constants } from "../../../utils/Constants.sol"; +import { Fuzzers } from "../../../utils/Fuzzers.sol"; /// @notice Base contract with common logic needed by all handler contracts. abstract contract BaseHandler is Constants, Fuzzers, StdCheats { @@ -45,7 +45,7 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @param timeJumpSeed A fuzzed value needed for generating random time warps. modifier adjustTimestamp(uint256 timeJumpSeed) { uint256 timeJump = _bound(timeJumpSeed, 2 minutes, 40 days); - vm.warp(block.timestamp + timeJump); + vm.warp(getBlockTimestamp() + timeJump); _; } diff --git a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol index ff40a6a7b..5206a7a85 100644 --- a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { LockupDynamic } from "core/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/core/invariant/handlers/LockupDynamicHandler.sol b/test/core/invariant/handlers/LockupDynamicHandler.sol index 19fb1c660..5d60b6528 100644 --- a/test/core/invariant/handlers/LockupDynamicHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/core/invariant/handlers/LockupHandler.sol b/test/core/invariant/handlers/LockupHandler.sol index 42b899a61..1f46c404e 100644 --- a/test/core/invariant/handlers/LockupHandler.sol +++ b/test/core/invariant/handlers/LockupHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "core/interfaces/ISablierV2Lockup.sol"; -import { Lockup } from "core/types/DataTypes.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/core/invariant/handlers/LockupLinearCreateHandler.sol b/test/core/invariant/handlers/LockupLinearCreateHandler.sol index 1d7330ec6..1086cd5e2 100644 --- a/test/core/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/core/invariant/handlers/LockupLinearCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { LockupLinear } from "core/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/core/invariant/handlers/LockupLinearHandler.sol b/test/core/invariant/handlers/LockupLinearHandler.sol index 9c3499bfb..4e54aea47 100644 --- a/test/core/invariant/handlers/LockupLinearHandler.sol +++ b/test/core/invariant/handlers/LockupLinearHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol index 011cb99aa..618f86473 100644 --- a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { LockupTranched } from "core/types/DataTypes.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; diff --git a/test/core/invariant/handlers/LockupTranchedHandler.sol b/test/core/invariant/handlers/LockupTranchedHandler.sol index 6b7b098f3..59887c84c 100644 --- a/test/core/invariant/handlers/LockupTranchedHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; diff --git a/test/core/invariant/stores/LockupStore.sol b/test/core/invariant/stores/LockupStore.sol index eeff3d3e1..8d108d1aa 100644 --- a/test/core/invariant/stores/LockupStore.sol +++ b/test/core/invariant/stores/LockupStore.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; /// @dev Storage variables needed by all lockup handlers. contract LockupStore { diff --git a/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol b/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol index f8e66d503..522cd2e29 100644 --- a/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol +++ b/test/core/unit/concrete/adminable/transfer-admin/transferAdmin.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Adminable_Unit_Shared_Test } from "../../../shared/Adminable.t.sol"; diff --git a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol index fd0481713..bddd59d4b 100644 --- a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "core/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; -import { NFTDescriptorMock } from "../../../mocks/NFTDescriptorMock.sol"; -import { Base_Test } from "../../../Base.t.sol"; +import { NFTDescriptorMock } from "test/mocks/NFTDescriptorMock.sol"; +import { Base_Test } from "test/Base.t.sol"; contract NFTDescriptor_Unit_Concrete_Test is Base_Test, SablierV2NFTDescriptor { NFTDescriptorMock internal nftDescriptorMock; diff --git a/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol index f6fb17bc3..f271568ba 100644 --- a/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol +++ b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "core/libraries/SVGElements.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol index e121c5563..e1a97aeae 100644 --- a/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol +++ b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "core/libraries/SVGElements.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { function test_CalculateDurationInDays_Zero() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 1 days - 1 seconds; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = string.concat(SVGElements.SIGN_LT, " 1 Day"); @@ -15,7 +15,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre } function test_CalculateDurationInDays_One() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 1 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = "1 Day"; @@ -23,7 +23,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre } function test_CalculateDurationInDays_FortyTwo() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 42 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = "42 Days"; @@ -31,7 +31,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre } function test_CalculateDurationInDays_Leet() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 1337 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = "1337 Days"; @@ -39,7 +39,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre } function test_CalculateDurationInDays_TenThousand() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 10_000 days; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = string.concat(SVGElements.SIGN_GT, " 9999 Days"); @@ -47,7 +47,7 @@ contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concre } function test_CalculateDurationInDays_Overflow() external view { - uint256 startTime = block.timestamp; + uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime - 1 seconds; string memory actualDurationInDays = nftDescriptorMock.calculateDurationInDays_(startTime, endTime); string memory expectedDurationInDays = string.concat(SVGElements.SIGN_GT, " 9999 Days"); diff --git a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol index ae2c4f7f9..74158df39 100644 --- a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -2,8 +2,8 @@ // solhint-disable max-line-length pragma solidity >=0.8.22 <0.9.0; -import { NFTSVG } from "core/libraries/NFTSVG.sol"; -import { SVGElements } from "core/libraries/SVGElements.sol"; +import { NFTSVG } from "src/core/libraries/NFTSVG.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/core/unit/concrete/nft-descriptor/hourglass.t.sol b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol index 9bae9e29d..5a52295f2 100644 --- a/test/core/unit/concrete/nft-descriptor/hourglass.t.sol +++ b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; -import { SVGElements } from "core/libraries/SVGElements.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol index 7fd16f1c4..f9760302f 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SVGElements } from "core/libraries/SVGElements.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol index d1ba9eab6..5c95970cc 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; diff --git a/test/core/unit/fuzz/transferAdmin.t.sol b/test/core/unit/fuzz/transferAdmin.t.sol index 523e2b99a..c25e962aa 100644 --- a/test/core/unit/fuzz/transferAdmin.t.sol +++ b/test/core/unit/fuzz/transferAdmin.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "core/libraries/Errors.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; import { Adminable_Unit_Shared_Test } from "../shared/Adminable.t.sol"; diff --git a/test/core/unit/shared/Adminable.t.sol b/test/core/unit/shared/Adminable.t.sol index 9a0ffe2b8..c78a4f94b 100644 --- a/test/core/unit/shared/Adminable.t.sol +++ b/test/core/unit/shared/Adminable.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Base_Test } from "../../Base.t.sol"; -import { AdminableMock } from "../../mocks/AdminableMock.sol"; +import { Base_Test } from "../../../Base.t.sol"; +import { AdminableMock } from "../../../mocks/AdminableMock.sol"; abstract contract Adminable_Unit_Shared_Test is Base_Test { AdminableMock internal adminableMock; diff --git a/test/core/utils/Defaults.sol b/test/core/utils/Defaults.sol deleted file mode 100644 index 2eb383399..000000000 --- a/test/core/utils/Defaults.sol +++ /dev/null @@ -1,284 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; - -import { Constants } from "./Constants.sol"; -import { Users } from "./Types.sol"; - -/// @notice Contract with default values used throughout the tests. -contract Defaults is Constants { - /*////////////////////////////////////////////////////////////////////////// - STATE VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - - UD60x18 public constant BROKER_FEE = UD60x18.wrap(0.003e18); // 0.3% - uint128 public constant BROKER_FEE_AMOUNT = 30.090270812437311935e18; // 0.3% of total amount - uint128 public constant CLIFF_AMOUNT = 2500e18; - uint40 public immutable CLIFF_TIME; - uint40 public constant CLIFF_DURATION = 2500 seconds; - uint128 public constant DEPOSIT_AMOUNT = 10_000e18; - uint40 public immutable END_TIME; - uint256 public constant MAX_SEGMENT_COUNT = 10_000; - uint40 public immutable MAX_SEGMENT_DURATION; - uint256 public constant MAX_TRANCHE_COUNT = 10_000; - uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; - uint256 public SEGMENT_COUNT; - uint40 public immutable START_TIME; - uint128 public constant TOTAL_AMOUNT = 10_030.090270812437311935e18; // deposit + broker fee - uint40 public constant TOTAL_DURATION = 10_000 seconds; - uint256 public TRANCHE_COUNT; - uint128 public constant WITHDRAW_AMOUNT = 2600e18; - uint40 public immutable WARP_26_PERCENT; // 26% of the way through the stream - - IERC20 private asset; - Users private users; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor() { - START_TIME = uint40(MAY_1_2024) + 2 days; - CLIFF_TIME = START_TIME + CLIFF_DURATION; - END_TIME = START_TIME + TOTAL_DURATION; - MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); - SEGMENT_COUNT = 2; - TRANCHE_COUNT = 3; - WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; - } - - /*////////////////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////////////////*/ - - function setAsset(IERC20 asset_) public { - asset = asset_; - } - - function setUsers(Users memory users_) public { - users = users_; - } - - /*////////////////////////////////////////////////////////////////////////// - STRUCTS - //////////////////////////////////////////////////////////////////////////*/ - - function broker() public view returns (Broker memory) { - return Broker({ account: users.broker, fee: BROKER_FEE }); - } - - function durations() public pure returns (LockupLinear.Durations memory) { - return LockupLinear.Durations({ cliff: CLIFF_DURATION, total: TOTAL_DURATION }); - } - - function lockupAmounts() public pure returns (Lockup.Amounts memory) { - return Lockup.Amounts({ deposited: DEPOSIT_AMOUNT, refunded: 0, withdrawn: 0 }); - } - - function lockupCreateAmounts() public pure returns (Lockup.CreateAmounts memory) { - return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); - } - - function lockupDynamicStream() public view returns (LockupDynamic.StreamLD memory) { - return LockupDynamic.StreamLD({ - amounts: lockupAmounts(), - asset: asset, - endTime: END_TIME, - isCancelable: true, - isDepleted: false, - isStream: true, - isTransferable: true, - recipient: users.recipient, - segments: segments(), - sender: users.sender, - startTime: START_TIME, - wasCanceled: false - }); - } - - function lockupDynamicTimestamps() public view returns (LockupDynamic.Timestamps memory) { - return LockupDynamic.Timestamps({ start: START_TIME, end: END_TIME }); - } - - function lockupLinearStream() public view returns (LockupLinear.StreamLL memory) { - return LockupLinear.StreamLL({ - amounts: lockupAmounts(), - asset: asset, - cliffTime: CLIFF_TIME, - endTime: END_TIME, - isCancelable: true, - isTransferable: true, - isDepleted: false, - isStream: true, - recipient: users.recipient, - sender: users.sender, - startTime: START_TIME, - wasCanceled: false - }); - } - - function lockupLinearTimestamps() public view returns (LockupLinear.Timestamps memory) { - return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); - } - - function lockupTranchedStream() public view returns (LockupTranched.StreamLT memory) { - return LockupTranched.StreamLT({ - amounts: lockupAmounts(), - asset: asset, - endTime: END_TIME, - isCancelable: true, - isDepleted: false, - isStream: true, - isTransferable: true, - recipient: users.recipient, - sender: users.sender, - startTime: START_TIME, - tranches: tranches(), - wasCanceled: false - }); - } - - function lockupTranchedTimestamps() public view returns (LockupTranched.Timestamps memory) { - return LockupTranched.Timestamps({ start: START_TIME, end: END_TIME }); - } - - function segments() public view returns (LockupDynamic.Segment[] memory segments_) { - segments_ = new LockupDynamic.Segment[](2); - segments_[0] = ( - LockupDynamic.Segment({ amount: 2500e18, exponent: ud2x18(3.14e18), timestamp: START_TIME + CLIFF_DURATION }) - ); - segments_[1] = ( - LockupDynamic.Segment({ amount: 7500e18, exponent: ud2x18(0.5e18), timestamp: START_TIME + TOTAL_DURATION }) - ); - } - - function segmentsWithDurations() - public - view - returns (LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations_) - { - LockupDynamic.Segment[] memory segments_ = segments(); - segmentsWithDurations_ = new LockupDynamic.SegmentWithDuration[](2); - segmentsWithDurations_[0] = ( - LockupDynamic.SegmentWithDuration({ - amount: segments_[0].amount, - exponent: segments_[0].exponent, - duration: 2500 seconds - }) - ); - segmentsWithDurations_[1] = ( - LockupDynamic.SegmentWithDuration({ - amount: segments_[1].amount, - exponent: segments_[1].exponent, - duration: 7500 seconds - }) - ); - } - - function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { - tranches_ = new LockupTranched.Tranche[](3); - tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: START_TIME + CLIFF_DURATION }); - tranches_[1] = LockupTranched.Tranche({ amount: 100e18, timestamp: WARP_26_PERCENT }); - tranches_[2] = LockupTranched.Tranche({ amount: 7400e18, timestamp: START_TIME + TOTAL_DURATION }); - } - - function tranchesWithDurations() - public - pure - returns (LockupTranched.TrancheWithDuration[] memory tranchesWithDurations_) - { - tranchesWithDurations_ = new LockupTranched.TrancheWithDuration[](3); - tranchesWithDurations_[0] = LockupTranched.TrancheWithDuration({ amount: 2500e18, duration: 2500 seconds }); - tranchesWithDurations_[1] = LockupTranched.TrancheWithDuration({ amount: 100e18, duration: 100 seconds }); - tranchesWithDurations_[2] = LockupTranched.TrancheWithDuration({ amount: 7400e18, duration: 7400 seconds }); - } - - /*////////////////////////////////////////////////////////////////////////// - PARAMS - //////////////////////////////////////////////////////////////////////////*/ - - function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { - return LockupDynamic.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - segments: segmentsWithDurations(), - broker: broker() - }); - } - - function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { - return LockupLinear.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - durations: durations(), - broker: broker() - }); - } - - function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { - return LockupTranched.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - tranches: tranchesWithDurations(), - broker: broker() - }); - } - - function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { - return LockupDynamic.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - startTime: START_TIME, - segments: segments(), - broker: broker() - }); - } - - function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { - return LockupLinear.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - timestamps: lockupLinearTimestamps(), - broker: broker() - }); - } - - function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { - return LockupTranched.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - startTime: START_TIME, - tranches: tranches(), - broker: broker() - }); - } -} diff --git a/test/core/utils/DeployOptimized.sol b/test/core/utils/DeployOptimized.sol deleted file mode 100644 index a6142c21d..000000000 --- a/test/core/utils/DeployOptimized.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { StdCheats } from "forge-std/src/StdCheats.sol"; - -import { ISablierV2LockupDynamic } from "../../../src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../../src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../../src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; - -abstract contract DeployOptimized is StdCheats { - /// @dev Deploys {SablierV2LockupDynamic} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupDynamic( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_, - uint256 maxSegmentCount - ) - internal - returns (ISablierV2LockupDynamic) - { - return ISablierV2LockupDynamic( - deployCode( - "out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json", - abi.encode(initialAdmin, address(nftDescriptor_), maxSegmentCount) - ) - ); - } - - /// @dev Deploys {SablierV2LockupLinear} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupLinear( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_ - ) - internal - returns (ISablierV2LockupLinear) - { - return ISablierV2LockupLinear( - deployCode( - "out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json", - abi.encode(initialAdmin, address(nftDescriptor_)) - ) - ); - } - - /// @dev Deploys {SablierV2LockupTranched} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupTranched( - address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_, - uint256 maxTrancheCount - ) - internal - returns (ISablierV2LockupTranched) - { - return ISablierV2LockupTranched( - deployCode( - "out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json", - abi.encode(initialAdmin, address(nftDescriptor_), maxTrancheCount) - ) - ); - } - - /// @dev Deploys {SablierV2NFTDescriptor} from an optimized source compiled with `--via-ir`. - function deployOptimizedNFTDescriptor() internal returns (ISablierV2NFTDescriptor) { - return - ISablierV2NFTDescriptor(deployCode("out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json")); - } - - function deployOptimizedCore( - address initialAdmin, - uint256 maxSegmentCount, - uint256 maxTrancheCount - ) - internal - returns ( - ISablierV2LockupDynamic lockupDynamic_, - ISablierV2LockupLinear lockupLinear_, - ISablierV2LockupTranched lockupTranched_, - ISablierV2NFTDescriptor nftDescriptor_ - ) - { - nftDescriptor_ = deployOptimizedNFTDescriptor(); - lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxSegmentCount); - lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, nftDescriptor_); - lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxTrancheCount); - } -} diff --git a/test/core/mocks/AdminableMock.sol b/test/mocks/AdminableMock.sol similarity index 65% rename from test/core/mocks/AdminableMock.sol rename to test/mocks/AdminableMock.sol index 70c7633be..f8359a2b6 100644 --- a/test/core/mocks/AdminableMock.sol +++ b/test/mocks/AdminableMock.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { Adminable } from "../../../src/core/abstracts/Adminable.sol"; -import { IAdminable } from "../../../src/core/interfaces/IAdminable.sol"; +import { Adminable } from "src/core/abstracts/Adminable.sol"; +import { IAdminable } from "src/core/interfaces/IAdminable.sol"; contract AdminableMock is Adminable { constructor(address initialAdmin) { diff --git a/test/core/mocks/Hooks.sol b/test/mocks/Hooks.sol similarity index 96% rename from test/core/mocks/Hooks.sol rename to test/mocks/Hooks.sol index 9f9a89917..9e8235b16 100644 --- a/test/core/mocks/Hooks.sol +++ b/test/mocks/Hooks.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22; import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import { ISablierLockupRecipient } from "../../../src/core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "../../../src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; +import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; contract RecipientGood is ISablierLockupRecipient, ERC165 { function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { diff --git a/test/core/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol similarity index 92% rename from test/core/mocks/NFTDescriptorMock.sol rename to test/mocks/NFTDescriptorMock.sol index 7b9b6c8c7..9192c29b5 100644 --- a/test/core/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -import { NFTSVG } from "../../../src/core/libraries/NFTSVG.sol"; -import { SVGElements } from "../../../src/core/libraries/SVGElements.sol"; -import { Lockup } from "../../../src/core/types/DataTypes.sol"; -import { SablierV2NFTDescriptor } from "../../../src/core/SablierV2NFTDescriptor.sol"; +import { NFTSVG } from "src/core/libraries/NFTSVG.sol"; +import { SVGElements } from "src/core/libraries/SVGElements.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; +import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; /// @dev This mock is needed for: /// - Running the tests against the `--via-ir` precompiles diff --git a/test/core/mocks/Noop.sol b/test/mocks/Noop.sol similarity index 100% rename from test/core/mocks/Noop.sol rename to test/mocks/Noop.sol diff --git a/test/core/mocks/erc20/ERC20Bytes32.sol b/test/mocks/erc20/ERC20Bytes32.sol similarity index 100% rename from test/core/mocks/erc20/ERC20Bytes32.sol rename to test/mocks/erc20/ERC20Bytes32.sol diff --git a/test/core/mocks/erc20/ERC20MissingReturn.sol b/test/mocks/erc20/ERC20MissingReturn.sol similarity index 100% rename from test/core/mocks/erc20/ERC20MissingReturn.sol rename to test/mocks/erc20/ERC20MissingReturn.sol diff --git a/test/core/mocks/erc20/ERC20Mock.sol b/test/mocks/erc20/ERC20Mock.sol similarity index 100% rename from test/core/mocks/erc20/ERC20Mock.sol rename to test/mocks/erc20/ERC20Mock.sol diff --git a/test/periphery/Base.t.sol b/test/periphery/Periphery.t.sol similarity index 54% rename from test/periphery/Base.t.sol rename to test/periphery/Periphery.t.sol index 1fbd3dbdc..87f114cf6 100644 --- a/test/periphery/Base.t.sol +++ b/test/periphery/Periphery.t.sol @@ -1,83 +1,29 @@ // SPDX-License-Identifier: UNLICENSED -// solhint-disable max-states-count pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; -import { Assertions as V2CoreAssertions } from "../core/utils/Assertions.sol"; -import { Constants as V2CoreConstants } from "../core/utils/Constants.sol"; -import { Utils as V2CoreUtils } from "../core/utils/Utils.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { SablierV2MerkleLL } from "src/periphery/SablierV2MerkleLL.sol"; +import { SablierV2MerkleLT } from "src/periphery/SablierV2MerkleLT.sol"; -import { ISablierV2BatchLockup } from "periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLockupFactory } from "periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; -import { SablierV2BatchLockup } from "periphery/SablierV2BatchLockup.sol"; -import { SablierV2MerkleLL } from "periphery/SablierV2MerkleLL.sol"; -import { SablierV2MerkleLockupFactory } from "periphery/SablierV2MerkleLockupFactory.sol"; -import { SablierV2MerkleLT } from "periphery/SablierV2MerkleLT.sol"; +import { Base_Test } from "../Base.t.sol"; -import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; -import { Assertions } from "./utils/Assertions.sol"; -import { Defaults } from "./utils/Defaults.sol"; -import { DeployOptimized } from "./utils/DeployOptimized.sol"; -import { Events } from "./utils/Events.sol"; -import { Merkle } from "./utils/Murky.sol"; -import { Users } from "./utils/Types.sol"; - -/// @notice Base test contract with common logic needed by all tests. -abstract contract Base_Test is - Assertions, - DeployOptimized, - Events, - Merkle, - V2CoreConstants, - V2CoreAssertions, - V2CoreUtils -{ - /*////////////////////////////////////////////////////////////////////////// - VARIABLES - //////////////////////////////////////////////////////////////////////////*/ - - Users internal users; - - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierV2BatchLockup internal batchLockup; - IERC20 internal dai; - Defaults internal defaults; - ISablierV2LockupDynamic internal lockupDynamic; - ISablierV2LockupLinear internal lockupLinear; - ISablierV2LockupTranched internal lockupTranched; - ISablierV2MerkleLockupFactory internal merkleLockupFactory; +contract Periphery_Test is Base_Test { ISablierV2MerkleLL internal merkleLL; ISablierV2MerkleLT internal merkleLT; /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION + SET-UP //////////////////////////////////////////////////////////////////////////*/ - function setUp() public virtual { - // Deploy the default test asset. - dai = new ERC20Mock("DAI Stablecoin", "DAI"); - - // Create users for testing. - users.alice = createUser("Alice"); - users.admin = createUser("Admin"); - users.broker = createUser("Broker"); - users.eve = createUser("Eve"); - users.recipient0 = createUser("Recipient"); - users.recipient1 = createUser("Recipient1"); - users.recipient2 = createUser("Recipient2"); - users.recipient3 = createUser("Recipient3"); - users.recipient4 = createUser("Recipient4"); + function setUp() public virtual override { + Base_Test.setUp(); } /*////////////////////////////////////////////////////////////////////////// @@ -91,60 +37,10 @@ abstract contract Base_Test is success; } - /// @dev Generates a user, labels its address, and funds it with ETH. - function createUser(string memory name) internal returns (address payable) { - address user = makeAddr(name); - vm.deal({ account: user, newBalance: 100_000 ether }); - deal({ token: address(dai), to: user, give: 1_000_000e18 }); - return payable(user); - } - - /// @dev Conditionally deploy V2 Periphery normally or from an optimized source compiled with `--via-ir`. - function deployPeripheryConditionally() internal { - if (!isTestOptimizedProfile()) { - batchLockup = new SablierV2BatchLockup(); - merkleLockupFactory = new SablierV2MerkleLockupFactory(); - } else { - (batchLockup, merkleLockupFactory) = deployOptimizedPeriphery(); - } - } - - /// @dev Labels the most relevant contracts. - function labelContracts(IERC20 asset_) internal { - vm.label({ account: address(asset_), newLabel: IERC20Metadata(address(asset_)).symbol() }); - vm.label({ account: address(defaults), newLabel: "Defaults" }); - vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); - vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); - vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); - vm.label({ account: address(merkleLL), newLabel: "MerkleLL" }); - vm.label({ account: address(merkleLockupFactory), newLabel: "MerkleLockupFactory" }); - vm.label({ account: address(merkleLT), newLabel: "MerkleLT" }); - } - /*////////////////////////////////////////////////////////////////////////// - CALL EXPECTS + EXPECT-CALLS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Expects a call to {IERC20.transfer}. - function expectCallToTransfer(address to, uint256 amount) internal { - expectCallToTransfer(address(dai), to, amount); - } - - /// @dev Expects a call to {IERC20.transfer}. - function expectCallToTransfer(address asset_, address to, uint256 amount) internal { - vm.expectCall({ callee: asset_, data: abi.encodeCall(IERC20.transfer, (to, amount)) }); - } - - /// @dev Expects a call to {IERC20.transferFrom}. - function expectCallToTransferFrom(address from, address to, uint256 amount) internal { - expectCallToTransferFrom(address(dai), from, to, amount); - } - - /// @dev Expects a call to {IERC20.transferFrom}. - function expectCallToTransferFrom(address asset_, address from, address to, uint256 amount) internal { - vm.expectCall({ callee: asset_, data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); - } - /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithDurations}, each with the specified /// `params`. function expectMultipleCallsToCreateWithDurationsLD( @@ -236,26 +132,30 @@ abstract contract Base_Test is } /// @dev Expects multiple calls to {IERC20.transfer}. - function expectMultipleCallsToTransfer(uint64 count, address to, uint256 amount) internal { - vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, amount)) }); + function expectMultipleCallsToTransfer(uint64 count, address to, uint256 value) internal { + vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, value)) }); } /// @dev Expects multiple calls to {IERC20.transferFrom}. - function expectMultipleCallsToTransferFrom(uint64 count, address from, address to, uint256 amount) internal { - expectMultipleCallsToTransferFrom(address(dai), count, from, to, amount); + function expectMultipleCallsToTransferFrom(uint64 count, address from, address to, uint256 value) internal { + expectMultipleCallsToTransferFrom(dai, count, from, to, value); } /// @dev Expects multiple calls to {IERC20.transferFrom}. function expectMultipleCallsToTransferFrom( - address asset_, + IERC20 asset, uint64 count, address from, address to, - uint256 amount + uint256 value ) internal { - vm.expectCall({ callee: asset_, count: count, data: abi.encodeCall(IERC20.transferFrom, (from, to, amount)) }); + vm.expectCall({ + callee: address(asset), + count: count, + data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) + }); } /*////////////////////////////////////////////////////////////////////////// @@ -263,18 +163,7 @@ abstract contract Base_Test is //////////////////////////////////////////////////////////////////////////*/ function computeMerkleLLAddress( - address admin, - bytes32 merkleRoot, - uint40 expiration - ) - internal - view - returns (address) - { - return computeMerkleLLAddress(admin, dai, merkleRoot, expiration); - } - - function computeMerkleLLAddress( + address caller, address admin, IERC20 asset_, bytes32 merkleRoot, @@ -286,7 +175,7 @@ abstract contract Base_Test is { bytes32 salt = keccak256( abi.encodePacked( - users.alice, + caller, address(asset_), defaults.CANCELABLE(), expiration, @@ -308,18 +197,7 @@ abstract contract Base_Test is } function computeMerkleLTAddress( - address admin, - bytes32 merkleRoot, - uint40 expiration - ) - internal - view - returns (address) - { - return computeMerkleLTAddress(admin, dai, merkleRoot, expiration); - } - - function computeMerkleLTAddress( + address caller, address admin, IERC20 asset_, bytes32 merkleRoot, @@ -331,7 +209,7 @@ abstract contract Base_Test is { bytes32 salt = keccak256( abi.encodePacked( - users.alice, + caller, address(asset_), defaults.CANCELABLE(), expiration, diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index 5209d66c1..617e254c5 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -3,17 +3,15 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { Precompiles } from "precompiles/Precompiles.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; -import { Fuzzers as V2CoreFuzzers } from "../../core/utils/Fuzzers.sol"; -import { Defaults } from "../utils/Defaults.sol"; -import { Base_Test } from "../Base.t.sol"; +import { Periphery_Test } from "../Periphery.t.sol"; +import { Merkle } from "../../utils/Murky.sol"; /// @notice Common logic needed by all fork tests. -abstract contract Fork_Test is Base_Test, V2CoreFuzzers { +abstract contract Fork_Test is Periphery_Test, Merkle { /*////////////////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ @@ -37,23 +35,10 @@ abstract contract Fork_Test is Base_Test, V2CoreFuzzers { vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); // Set up the base test contract. - Base_Test.setUp(); + Periphery_Test.setUp(); // Load the external dependencies. loadDependencies(); - - // Deploy the defaults contract and allow it to access cheatcodes. - defaults = new Defaults({ users_: users, asset_: FORK_ASSET }); - vm.allowCheatcodes(address(defaults)); - - // Deploy V2 Periphery. - deployPeripheryConditionally(); - - // Label the contracts. - labelContracts(FORK_ASSET); - - // Approve the BatchLockup contract. - approveContract({ asset_: FORK_ASSET, from: users.alice, spender: address(batchLockup) }); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol index 98edbab08..969f0e600 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol @@ -2,12 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic } from "core/types/DataTypes.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; -import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. @@ -35,7 +35,7 @@ abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fo (params.perStreamAmount,) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128 / params.batchSize, segments: params.segments, - brokerFee: defaults.BROKER_FEE() + brokerFee: defaults.brokerNull().fee }); checkUsers(params.sender, params.recipient); @@ -55,24 +55,24 @@ abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fo transferable: true, startTime: params.startTime, segments: params.segments, - broker: defaults.broker() + broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLD[] memory batchParams = BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); expectCallToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, from: params.sender, to: address(batchLockup), - amount: totalTransferAmount + value: totalTransferAmount }); expectMultipleCallsToCreateWithTimestampsLD({ count: uint64(params.batchSize), params: createWithTimestamps }); expectMultipleCallsToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), to: address(lockupDynamic), - amount: params.perStreamAmount + value: params.perStreamAmount }); uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLD(lockupDynamic, FORK_ASSET, batchParams); diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol index efe940fb1..d2ff4e673 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol @@ -2,12 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupLinear } from "core/types/DataTypes.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; -import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. @@ -53,25 +53,25 @@ abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is For cancelable: true, transferable: true, timestamps: params.timestamps, - broker: defaults.broker() + broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLL[] memory batchParams = BatchLockupBuilder.fillBatch(createParams, params.batchSize); // Asset flow: sender → batch → Sablier expectCallToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, from: params.sender, to: address(batchLockup), - amount: totalTransferAmount + value: totalTransferAmount }); expectMultipleCallsToCreateWithTimestampsLL({ count: uint64(params.batchSize), params: createParams }); expectMultipleCallsToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), to: address(lockupLinear), - amount: params.perStreamAmount + value: params.perStreamAmount }); uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLL(lockupLinear, FORK_ASSET, batchParams); diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol index edba2be4a..7f4c97c80 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol @@ -2,12 +2,12 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupTranched } from "core/types/DataTypes.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; -import { BatchLockupBuilder } from "../../utils/BatchLockupBuilder.sol"; +import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; +import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. @@ -35,7 +35,7 @@ abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is F (params.perStreamAmount,) = fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128 / params.batchSize, tranches: params.tranches, - brokerFee: defaults.BROKER_FEE() + brokerFee: defaults.brokerNull().fee }); checkUsers(params.sender, params.recipient); @@ -55,24 +55,24 @@ abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is F transferable: true, startTime: params.startTime, tranches: params.tranches, - broker: defaults.broker() + broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLT[] memory batchParams = BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); expectCallToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, from: params.sender, to: address(batchLockup), - amount: totalTransferAmount + value: totalTransferAmount }); expectMultipleCallsToCreateWithTimestampsLT({ count: uint64(params.batchSize), params: createWithTimestamps }); expectMultipleCallsToTransferFrom({ - asset_: address(FORK_ASSET), + asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), to: address(lockupTranched), - amount: params.perStreamAmount + value: params.perStreamAmount }); uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLT(lockupTranched, FORK_ASSET, batchParams); diff --git a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol index 4f34724db..62ccfec60 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol @@ -3,12 +3,12 @@ pragma solidity >=0.8.22 <0.9.0; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; -import { MerkleLockup } from "periphery/types/DataTypes.sol"; +import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; -import { MerkleBuilder } from "../../utils/MerkleBuilder.sol"; +import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; abstract contract MerkleLL_Fork_Test is Fork_Test { @@ -95,7 +95,11 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { MerkleBuilder.sortLeaves(leaves); vars.merkleRoot = getRoot(leaves.toBytes32()); - vars.expectedLL = computeMerkleLLAddress(params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + // Make the caller the admin. + resetPrank({ msgSender: params.admin }); + + vars.expectedLL = + computeMerkleLLAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); vars.baseParams = defaults.baseParams({ admin: params.admin, @@ -183,8 +187,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleLL))); vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); - resetPrank({ msgSender: params.admin }); - expectCallToTransfer({ asset_: address(FORK_ASSET), to: params.admin, amount: vars.clawbackAmount }); + expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); vm.expectEmit({ emitter: address(vars.merkleLL) }); emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); vars.merkleLL.clawback({ to: params.admin, amount: vars.clawbackAmount }); diff --git a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol index 451fb02d3..e8b50fbcc 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol @@ -3,12 +3,12 @@ pragma solidity >=0.8.22 <0.9.0; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; -import { MerkleLockup } from "periphery/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; -import { MerkleBuilder } from "../../utils/MerkleBuilder.sol"; +import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; abstract contract MerkleLT_Fork_Test is Fork_Test { @@ -96,7 +96,11 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { MerkleBuilder.sortLeaves(leaves); vars.merkleRoot = getRoot(leaves.toBytes32()); - vars.expectedLT = computeMerkleLTAddress(params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + // Make the caller the admin. + resetPrank({ msgSender: params.admin }); + + vars.expectedLT = + computeMerkleLTAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); vars.baseParams = defaults.baseParams({ admin: params.admin, @@ -169,7 +173,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { recipient: vars.recipients[params.posBeforeSort], sender: params.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranches({ totalAmount: vars.amounts[params.posBeforeSort] }), + tranches: defaults.tranchesMerkleLockup({ totalAmount: vars.amounts[params.posBeforeSort] }), wasCanceled: false }); @@ -186,7 +190,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); resetPrank({ msgSender: params.admin }); - expectCallToTransfer({ asset_: address(FORK_ASSET), to: params.admin, amount: vars.clawbackAmount }); + expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); vm.expectEmit({ emitter: address(vars.merkleLT) }); emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); vars.merkleLT.clawback({ to: params.admin, amount: vars.clawbackAmount }); diff --git a/test/periphery/integration/Integration.t.sol b/test/periphery/integration/Integration.t.sol deleted file mode 100644 index 5f96c6ad1..000000000 --- a/test/periphery/integration/Integration.t.sol +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Precompiles } from "precompiles/Precompiles.sol"; - -import { Defaults } from "../utils/Defaults.sol"; -import { Base_Test } from "../Base.t.sol"; - -/// @notice Common logic needed by all integration tests. -abstract contract Integration_Test is Base_Test { - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - // Set up the base test contract. - Base_Test.setUp(); - - // Deploy the external dependencies. - deployDependencies(); - - // Deploy the defaults contract. - defaults = new Defaults({ users_: users, asset_: dai }); - - // Deploy V2 Periphery. - deployPeripheryConditionally(); - - // Label the contracts. - labelContracts(dai); - - // Approve the BatchLockup contract. - approveContract({ asset_: dai, from: users.alice, spender: address(batchLockup) }); - } - - /*////////////////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////////////////*/ - - function deployDependencies() private { - (lockupDynamic, lockupLinear, lockupTranched,) = new Precompiles().deployCore(users.admin); - } -} diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 31d18c04e..57c38e914 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithDurationsLD_Integration_Test is Integration_Test { +contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithDurationsLD_Integration_Test is Integration_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithDurationsLD({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsLD() + params: defaults.createWithDurationsBrokerNullLD() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupDynamic), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index e83a9ffa1..1938152c6 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithDurationsLL_Integration_Test is Integration_Test { +contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithDurationsLL_Integration_Test is Integration_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithDurationsLL({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsLL() + params: defaults.createWithDurationsBrokerNullLL() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupLinear), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index bbbb49f71..b84c5ff0f 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithDurationsLT_Integration_Test is Integration_Test { +contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithDurationsLT_Integration_Test is Integration_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithDurationsLT({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsLT() + params: defaults.createWithDurationsBrokerNullLT() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupTranched), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index f8210ea5f..e9b6a8be2 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithTimestampsLD_Integration_Test is Integration_Test { +contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithTimestampsLD_Integration_Test is Integration_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithTimestampsLD({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsLD() + params: defaults.createWithTimestampsBrokerNullLD() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupDynamic), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index c72bf2663..f03d63159 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithTimestampsLL_Integration_Test is Integration_Test { +contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithTimestampsLL_Integration_Test is Integration_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithTimestampsLL({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsLL() + params: defaults.createWithTimestampsBrokerNullLL() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupLinear), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index 1eca76efb..fdb4331be 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -1,14 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { BatchLockup } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Periphery_Test } from "../../../Periphery.t.sol"; -contract CreateWithTimestampsLT_Integration_Test is Integration_Test { +contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + resetPrank({ msgSender: users.sender }); } function test_RevertWhen_BatchSizeZero() external { @@ -22,22 +23,22 @@ contract CreateWithTimestampsLT_Integration_Test is Integration_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Alice → batchLockup → Sablier + // Asset flow: Sender → batchLockup → Sablier // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. expectCallToTransferFrom({ - from: users.alice, + from: users.sender, to: address(batchLockup), - amount: defaults.TOTAL_TRANSFER_AMOUNT() + value: defaults.TOTAL_TRANSFER_AMOUNT() }); expectMultipleCallsToCreateWithTimestampsLT({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsLT() + params: defaults.createWithTimestampsBrokerNullLT() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), to: address(lockupTranched), - amount: defaults.PER_STREAM_AMOUNT() + value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. diff --git a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol index dcad44c14..0dd426bd1 100644 --- a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol +++ b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol @@ -1,14 +1,17 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; -import { Integration_Test } from "../Integration.t.sol"; +import { Periphery_Test } from "../../Periphery.t.sol"; -abstract contract MerkleLockup_Integration_Test is Integration_Test { +abstract contract MerkleLockup_Integration_Test is Periphery_Test { function setUp() public virtual override { - Integration_Test.setUp(); + Periphery_Test.setUp(); + + // Make Alice the caller. + resetPrank(users.alice); // Create the default MerkleLockup contracts. merkleLL = createMerkleLL(); @@ -48,6 +51,18 @@ abstract contract MerkleLockup_Integration_Test is Integration_Test { return computeMerkleLLAddress(admin, merkleRoot, defaults.EXPIRATION()); } + function computeMerkleLLAddress( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + return computeMerkleLLAddress(users.alice, admin, dai, merkleRoot, expiration); + } + function createMerkleLL() internal returns (ISablierV2MerkleLL) { return createMerkleLL(users.admin, defaults.EXPIRATION()); } @@ -99,6 +114,18 @@ abstract contract MerkleLockup_Integration_Test is Integration_Test { return computeMerkleLTAddress(admin, merkleRoot, defaults.EXPIRATION()); } + function computeMerkleLTAddress( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + return computeMerkleLTAddress(users.alice, admin, dai, merkleRoot, expiration); + } + function createMerkleLT() internal returns (ISablierV2MerkleLT) { return createMerkleLT(users.admin, defaults.EXPIRATION()); } diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol index 277822741..381adc135 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol @@ -1,22 +1,14 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "core/types/DataTypes.sol"; - -import { Errors } from "periphery/libraries/Errors.sol"; -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; -import { MerkleLockup } from "periphery/types/DataTypes.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public override { - MerkleLockup_Integration_Test.setUp(); - - // Make alice the caller of createMerkleLT. - resetPrank(users.alice); - } - function test_RevertWhen_CampaignNameTooLong() external { MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); LockupLinear.Durations memory streamDurations = defaults.durations(); diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol index b7699617b..596f9c64e 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol @@ -1,20 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "periphery/libraries/Errors.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public override { - MerkleLockup_Integration_Test.setUp(); - - // Make alice the caller of createMerkleLT. - resetPrank(users.alice); - } - function test_RevertWhen_CampaignNameTooLong() external { MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); diff --git a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol index 70b2255d4..60f753642 100644 --- a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol +++ b/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD2x18, ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { MerkleLT } from "periphery/types/DataTypes.sol"; +import { MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol index 1af5a3e37..3889ddbee 100644 --- a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupLinear } from "core/types/DataTypes.sol"; - -import { Errors } from "periphery/libraries/Errors.sol"; +import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol index 8d8abbd6b..586f5d6b9 100644 --- a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors as V2CoreErrors } from "core/libraries/Errors.sol"; - -import { Errors } from "periphery/libraries/Errors.sol"; +import { Errors as V2CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -34,12 +33,12 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { } function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: block.timestamp + 6 days }); + vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); test_Clawback(users.admin); } modifier postGracePeriod() { - vm.warp({ newTimestamp: block.timestamp + 8 days }); + vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); _; } @@ -47,7 +46,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, - block.timestamp, + getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() ) @@ -77,7 +76,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_Clawback(address to) internal { uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLL))); - expectCallToTransfer({ to: to, amount: clawbackAmount }); + expectCallToTransfer({ to: to, value: clawbackAmount }); vm.expectEmit({ emitter: address(merkleLL) }); emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); merkleLL.clawback({ to: to, amount: clawbackAmount }); diff --git a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol index dc50b46a2..62ab53417 100644 --- a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "core/types/DataTypes.sol"; - -import { SablierV2MerkleLL } from "periphery/SablierV2MerkleLL.sol"; +import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { SablierV2MerkleLL } from "src/periphery/SablierV2MerkleLL.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol index bd61c2e11..75351bf69 100644 --- a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol @@ -21,6 +21,6 @@ contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { function test_GetFirstClaimTime() external afterFirstClaim { uint256 firstClaimTime = merkleLL.getFirstClaimTime(); - assertEq(firstClaimTime, block.timestamp); + assertEq(firstClaimTime, getBlockTimestamp()); } } diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol index e482fc65c..7e32d35c8 100644 --- a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol index d33b7cd03..1d35b1a1d 100644 --- a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol @@ -3,14 +3,14 @@ pragma solidity >=0.8.22 <0.9.0; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { Lockup, LockupTranched } from "core/types/DataTypes.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; -import { Errors } from "periphery/libraries/Errors.sol"; -import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleBuilder } from "../../../../utils/MerkleBuilder.sol"; -import { Merkle } from "../../../../utils/Murky.sol"; +import { MerkleBuilder } from "test/utils/MerkleBuilder.sol"; +import { Merkle } from "test/utils/Murky.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -232,7 +232,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { recipient: users.recipient1, sender: users.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranches(claimAmount), + tranches: defaults.tranchesMerkleLockup(claimAmount), wasCanceled: false }); @@ -270,7 +270,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { recipient: users.recipient1, sender: users.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranches(), + tranches: defaults.tranchesMerkleLockup(), wasCanceled: false }); diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol index 653c80eea..77502d4ed 100644 --- a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol @@ -1,9 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors as V2CoreErrors } from "core/libraries/Errors.sol"; - -import { Errors } from "periphery/libraries/Errors.sol"; +import { Errors as V2CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -33,12 +32,12 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { } function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: block.timestamp + 6 days }); + vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); test_Clawback(users.admin); } modifier postGracePeriod() { - vm.warp({ newTimestamp: block.timestamp + 8 days }); + vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); _; } @@ -46,7 +45,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, - block.timestamp, + getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() ) @@ -76,7 +75,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_Clawback(address to) internal { uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLT))); - expectCallToTransfer({ to: to, amount: clawbackAmount }); + expectCallToTransfer({ to: to, value: clawbackAmount }); vm.expectEmit({ emitter: address(merkleLT) }); emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); merkleLT.clawback({ to: to, amount: clawbackAmount }); diff --git a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol index bb4d143fc..3fef28fa0 100644 --- a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SablierV2MerkleLT } from "periphery/SablierV2MerkleLT.sol"; -import { MerkleLT } from "periphery/types/DataTypes.sol"; +import { SablierV2MerkleLT } from "src/periphery/SablierV2MerkleLT.sol"; +import { MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol index 3e286f81c..bcc624434 100644 --- a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol @@ -21,6 +21,6 @@ contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { function test_GetFirstClaimTime() external afterFirstClaim { uint256 firstClaimTime = merkleLT.getFirstClaimTime(); - assertEq(firstClaimTime, block.timestamp); + assertEq(firstClaimTime, getBlockTimestamp()); } } diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol index a13724264..64c7c0760 100644 --- a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; diff --git a/test/periphery/mocks/erc20/ERC20Mock.sol b/test/periphery/mocks/erc20/ERC20Mock.sol deleted file mode 100644 index 8cf2389dd..000000000 --- a/test/periphery/mocks/erc20/ERC20Mock.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract ERC20Mock is ERC20 { - constructor(string memory name, string memory symbol) ERC20(name, symbol) { } -} diff --git a/test/periphery/utils/.npmignore b/test/periphery/utils/.npmignore deleted file mode 100644 index c607d373a..000000000 --- a/test/periphery/utils/.npmignore +++ /dev/null @@ -1 +0,0 @@ -*.t.sol diff --git a/test/periphery/utils/Assertions.sol b/test/periphery/utils/Assertions.sol deleted file mode 100644 index 2f61dbec4..000000000 --- a/test/periphery/utils/Assertions.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -// solhint-disable event-name-camelcase -pragma solidity >=0.8.22; - -import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; - -import { MerkleLT } from "periphery/types/DataTypes.sol"; - -abstract contract Assertions is PRBMathAssertions { - event log_named_array(string key, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages); - - /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. - function assertEq(MerkleLT.TrancheWithPercentage[] memory a, MerkleLT.TrancheWithPercentage[] memory b) internal { - if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit log("Error: a == b not satisfied [MerkleLT.TrancheWithPercentage[]]"); - emit log_named_array(" Left", a); - emit log_named_array(" Right", b); - fail(); - } - } - - /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. - function assertEq( - MerkleLT.TrancheWithPercentage[] memory a, - MerkleLT.TrancheWithPercentage[] memory b, - string memory err - ) - internal - { - if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { - emit log_named_string("Error", err); - assertEq(a, b); - } - } -} diff --git a/test/periphery/utils/BaseScript.t.sol b/test/periphery/utils/BaseScript.t.sol deleted file mode 100644 index 6fa78951a..000000000 --- a/test/periphery/utils/BaseScript.t.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { StdAssertions } from "forge-std/src/StdAssertions.sol"; - -import { BaseScript } from "script/Base.s.sol"; - -contract BaseScript_Test is StdAssertions { - using Strings for uint256; - - BaseScript internal baseScript = new BaseScript(); - - function test_ConstructCreate2Salt() public view { - string memory chainId = block.chainid.toString(); - string memory version = "1.2.0"; - string memory salt = string.concat("ChainID ", chainId, ", Version ", version); - - bytes32 actualSalt = baseScript.constructCreate2Salt(); - bytes32 expectedSalt = bytes32(abi.encodePacked(salt)); - assertEq(actualSalt, expectedSalt, "CREATE2 salt mismatch"); - } -} diff --git a/test/periphery/utils/DeployOptimized.sol b/test/periphery/utils/DeployOptimized.sol deleted file mode 100644 index 1eb192765..000000000 --- a/test/periphery/utils/DeployOptimized.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { StdCheats } from "forge-std/src/StdCheats.sol"; - -import { ISablierV2BatchLockup } from "../../../src/periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLockupFactory } from "../../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; - -abstract contract DeployOptimized is StdCheats { - /// @dev Deploys {SablierV2BatchLockup} from an optimized source compiled with `--via-ir`. - function deployOptimizedBatchLockup() internal returns (ISablierV2BatchLockup) { - return ISablierV2BatchLockup(deployCode("out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json")); - } - - /// @dev Deploys {SablierV2MerkleLockupFactory} from an optimized source compiled with `--via-ir`. - function deployOptimizedMerkleLockupFactory() internal returns (ISablierV2MerkleLockupFactory) { - return ISablierV2MerkleLockupFactory( - deployCode("out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json") - ); - } - - /// @notice Deploys all V2 Periphery contracts from an optimized source in the following order: - /// - /// 1. {SablierV2BatchLockup} - /// 2. {SablierV2MerkleLockupFactory} - function deployOptimizedPeriphery() internal returns (ISablierV2BatchLockup, ISablierV2MerkleLockupFactory) { - return (deployOptimizedBatchLockup(), deployOptimizedMerkleLockupFactory()); - } -} diff --git a/test/periphery/utils/Events.sol b/test/periphery/utils/Events.sol deleted file mode 100644 index aad3d28da..000000000 --- a/test/periphery/utils/Events.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22; - -import { LockupLinear } from "core/types/DataTypes.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; - -import { ISablierV2MerkleLL } from "periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "periphery/interfaces/ISablierV2MerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; - -/// @notice Abstract contract containing all the events emitted by the protocol. -abstract contract Events { - event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); - event Clawback(address indexed admin, address indexed to, uint128 amount); - event CreateMerkleLL( - ISablierV2MerkleLL indexed merkleLL, - MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupLinear lockupLinear, - LockupLinear.Durations streamDurations, - uint256 aggregateAmount, - uint256 recipientCount - ); - event CreateMerkleLT( - ISablierV2MerkleLT indexed merkleLT, - MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupTranched lockupTranched, - MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, - uint256 totalDuration, - uint256 aggregateAmount, - uint256 recipientCount - ); -} diff --git a/test/periphery/utils/Precompiles.t.sol b/test/periphery/utils/Precompiles.t.sol deleted file mode 100644 index f296d6aff..000000000 --- a/test/periphery/utils/Precompiles.t.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Precompiles } from "precompiles/Precompiles.sol"; -import { ISablierV2BatchLockup } from "periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLockupFactory } from "periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; - -import { Base_Test } from "../Base.t.sol"; - -contract Precompiles_Test is Base_Test { - Precompiles internal precompiles = new Precompiles(); - - modifier onlyTestOptimizedProfile() { - if (isTestOptimizedProfile()) { - _; - } - } - - function test_DeployBatchLockup() external onlyTestOptimizedProfile { - address actualBatchLockup = address(precompiles.deployBatchLockup()); - address expectedBatchLockup = address(deployOptimizedBatchLockup()); - assertEq(actualBatchLockup.code, expectedBatchLockup.code, "bytecodes mismatch"); - } - - function test_DeployMerkleLockupFactory() external onlyTestOptimizedProfile { - address actualFactory = address(precompiles.deployMerkleLockupFactory()); - address expectedFactory = address(deployOptimizedMerkleLockupFactory()); - assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); - } - - function test_DeployPeriphery() external onlyTestOptimizedProfile { - (ISablierV2BatchLockup actualBatchLockup, ISablierV2MerkleLockupFactory actualMerkleLockupFactory) = - precompiles.deployPeriphery(); - - (ISablierV2BatchLockup expectedBatchLockup, ISablierV2MerkleLockupFactory expectedMerkleLockupFactory) = - deployOptimizedPeriphery(); - - assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); - assertEq( - address(actualMerkleLockupFactory).code, address(expectedMerkleLockupFactory).code, "bytecodes mismatch" - ); - } -} diff --git a/test/periphery/utils/Types.sol b/test/periphery/utils/Types.sol deleted file mode 100644 index 39fdda5af..000000000 --- a/test/periphery/utils/Types.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -struct Users { - address alice; - address admin; - address broker; - address eve; - address recipient0; - address recipient1; - address recipient2; - address recipient3; - address recipient4; -} diff --git a/test/core/utils/.npmignore b/test/utils/.npmignore similarity index 100% rename from test/core/utils/.npmignore rename to test/utils/.npmignore diff --git a/test/periphery/utils/ArrayBuilder.sol b/test/utils/ArrayBuilder.sol similarity index 100% rename from test/periphery/utils/ArrayBuilder.sol rename to test/utils/ArrayBuilder.sol diff --git a/test/core/utils/Assertions.sol b/test/utils/Assertions.sol similarity index 86% rename from test/core/utils/Assertions.sol rename to test/utils/Assertions.sol index 6669fcc63..d88b24ea9 100644 --- a/test/core/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -5,7 +5,8 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; -import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { MerkleLT } from "../../src/periphery/types/DataTypes.sol"; abstract contract Assertions is PRBMathAssertions { /*////////////////////////////////////////////////////////////////////////// @@ -16,12 +17,14 @@ abstract contract Assertions is PRBMathAssertions { event log_named_array(string key, LockupTranched.Tranche[] tranches); + event log_named_array(string key, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages); + event log_named_uint128(string key, uint128 value); event log_named_uint40(string key, uint40 value); /*////////////////////////////////////////////////////////////////////////// - ASSERTIONS + CORE //////////////////////////////////////////////////////////////////////////*/ /// @dev Compares two {Lockup.Amounts} struct entities. @@ -203,4 +206,32 @@ abstract contract Assertions is PRBMathAssertions { function assertNotEq(Lockup.Status a, Lockup.Status b, string memory err) internal pure { assertNotEq(uint256(a), uint256(b), err); } + + /*////////////////////////////////////////////////////////////////////////// + PERIPHERY + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. + function assertEq(MerkleLT.TrancheWithPercentage[] memory a, MerkleLT.TrancheWithPercentage[] memory b) internal { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [MerkleLT.TrancheWithPercentage[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + /// @dev Compares two {MerkleLT.TrancheWithPercentage} arrays. + function assertEq( + MerkleLT.TrancheWithPercentage[] memory a, + MerkleLT.TrancheWithPercentage[] memory b, + string memory err + ) + internal + { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } } diff --git a/test/core/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol similarity index 100% rename from test/core/utils/BaseScript.t.sol rename to test/utils/BaseScript.t.sol diff --git a/test/periphery/utils/BatchLockupBuilder.sol b/test/utils/BatchLockupBuilder.sol similarity index 98% rename from test/periphery/utils/BatchLockupBuilder.sol rename to test/utils/BatchLockupBuilder.sol index cc2210903..642eb8052 100644 --- a/test/periphery/utils/BatchLockupBuilder.sol +++ b/test/utils/BatchLockupBuilder.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; -import { BatchLockup } from "../../../src/periphery/types/DataTypes.sol"; +import { BatchLockup } from "src/periphery/types/DataTypes.sol"; library BatchLockupBuilder { /// @notice Generates an array containing `batchSize` copies of `batchSingle`. diff --git a/test/core/utils/Calculations.sol b/test/utils/Calculations.sol similarity index 82% rename from test/core/utils/Calculations.sol rename to test/utils/Calculations.sol index e18aa9153..320faf1f6 100644 --- a/test/core/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -6,16 +6,12 @@ import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uin import { SD59x18 } from "@prb/math/src/SD59x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; - -import { Defaults } from "./Defaults.sol"; +import { LockupDynamic, LockupTranched } from "../../src/core/types/DataTypes.sol"; abstract contract Calculations { using CastingUint128 for uint128; using CastingUint40 for uint40; - Defaults private defaults = new Defaults(); - /// @dev Calculates the deposit amount by calculating and subtracting the broker fee amount from the total amount. function calculateDepositAmount(uint128 totalAmount, UD60x18 brokerFee) internal pure returns (uint128) { uint128 brokerFeeAmount = ud(totalAmount).mul(brokerFee).intoUint128(); @@ -23,13 +19,22 @@ abstract contract Calculations { } /// @dev Helper function that replicates the logic of {SablierV2LockupLinear.streamedAmountOf}. - function calculateStreamedAmount(uint40 blockTimestamp, uint128 depositAmount) internal view returns (uint128) { - if (blockTimestamp > defaults.END_TIME()) { + function calculateStreamedAmount( + uint40 startTime, + uint40 endTime, + uint128 depositAmount + ) + internal + view + returns (uint128) + { + uint40 blockTimestamp = uint40(block.timestamp); + if (blockTimestamp >= endTime) { return depositAmount; } unchecked { - UD60x18 elapsedTime = ud(blockTimestamp - defaults.START_TIME()); - UD60x18 totalDuration = ud(defaults.TOTAL_DURATION()); + UD60x18 elapsedTime = ud(blockTimestamp - startTime); + UD60x18 totalDuration = ud(endTime - startTime); UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); return elapsedTimePercentage.mul(ud(depositAmount)).intoUint128(); } @@ -37,14 +42,15 @@ abstract contract Calculations { /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForMultipleSegments}. function calculateStreamedAmountForMultipleSegments( - uint40 blockTimestamp, LockupDynamic.Segment[] memory segments, + uint40 startTime, uint128 depositAmount ) internal view returns (uint128) { + uint40 blockTimestamp = uint40(block.timestamp); if (blockTimestamp >= segments[segments.length - 1].timestamp) { return depositAmount; } @@ -67,7 +73,7 @@ abstract contract Calculations { if (index > 0) { previousTimestamp = segments[index - 1].timestamp; } else { - previousTimestamp = defaults.START_TIME(); + previousTimestamp = startTime; } SD59x18 elapsedTime = (blockTimestamp - previousTimestamp).intoSD59x18(); @@ -82,19 +88,21 @@ abstract contract Calculations { /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForOneSegment}. function calculateStreamedAmountForOneSegment( - uint40 blockTimestamp, - LockupDynamic.Segment memory segment + LockupDynamic.Segment memory segment, + uint40 startTime ) internal view returns (uint128) { + uint40 blockTimestamp = uint40(block.timestamp); + if (blockTimestamp >= segment.timestamp) { return segment.amount; } unchecked { - SD59x18 elapsedTime = (blockTimestamp - defaults.START_TIME()).intoSD59x18(); - SD59x18 totalDuration = (segment.timestamp - defaults.START_TIME()).intoSD59x18(); + SD59x18 elapsedTime = (blockTimestamp - startTime).intoSD59x18(); + SD59x18 totalDuration = (segment.timestamp - startTime).intoSD59x18(); SD59x18 elapsedTimePercentage = elapsedTime.div(totalDuration); SD59x18 multiplier = elapsedTimePercentage.pow(segment.exponent.intoSD59x18()); @@ -105,14 +113,14 @@ abstract contract Calculations { /// @dev Helper function that replicates the logic of {SablierV2LockupTranched._calculateStreamedAmount}. function calculateStreamedAmountForTranches( - uint40 blockTimestamp, LockupTranched.Tranche[] memory tranches, uint128 depositAmount ) internal - pure + view returns (uint128) { + uint40 blockTimestamp = uint40(block.timestamp); if (blockTimestamp >= tranches[tranches.length - 1].timestamp) { return depositAmount; } diff --git a/test/core/utils/Constants.sol b/test/utils/Constants.sol similarity index 89% rename from test/core/utils/Constants.sol rename to test/utils/Constants.sol index e9d11f6eb..592eaacfc 100644 --- a/test/core/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -9,5 +9,5 @@ abstract contract Constants { uint256 internal constant MAX_UINT256 = type(uint256).max; uint40 internal constant MAX_UINT40 = type(uint40).max; uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 - uint40 internal constant MAY_1_2024 = 1_714_518_000; + uint40 internal constant JULY_1_2024 = 1_719_792_000; } diff --git a/test/periphery/utils/Defaults.sol b/test/utils/Defaults.sol similarity index 57% rename from test/periphery/utils/Defaults.sol rename to test/utils/Defaults.sol index 318fce80b..8704d6177 100644 --- a/test/periphery/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -1,22 +1,23 @@ // SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; +pragma solidity >=0.8.22; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud2x18, uUNIT } from "@prb/math/src/UD2x18.sol"; -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic, LockupLinear, LockupTranched } from "core/types/DataTypes.sol"; +import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; -import { BatchLockup, MerkleLockup, MerkleLT } from "periphery/types/DataTypes.sol"; +import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { BatchLockup, MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; import { ArrayBuilder } from "./ArrayBuilder.sol"; +import { Constants } from "./Constants.sol"; import { BatchLockupBuilder } from "./BatchLockupBuilder.sol"; import { Merkle } from "./Murky.sol"; import { MerkleBuilder } from "./MerkleBuilder.sol"; import { Users } from "./Types.sol"; -/// @notice Contract with default values for testing. -contract Defaults is Merkle { +/// @notice Contract with default values used throughout the tests. +contract Defaults is Constants, Merkle { using MerkleBuilder for uint256[]; /*////////////////////////////////////////////////////////////////////////// @@ -24,17 +25,25 @@ contract Defaults is Merkle { //////////////////////////////////////////////////////////////////////////*/ uint64 public constant BATCH_SIZE = 10; - UD60x18 public constant BROKER_FEE = UD60x18.wrap(0); - uint40 public constant CLIFF_DURATION = 2500 seconds; + UD60x18 public constant BROKER_FEE = UD60x18.wrap(0.003e18); // 0.3% + uint128 public constant BROKER_FEE_AMOUNT = 30.090270812437311935e18; // 0.3% of total amount + uint128 public constant CLIFF_AMOUNT = 2500e18; uint40 public immutable CLIFF_TIME; + uint40 public constant CLIFF_DURATION = 2500 seconds; + uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - uint256 public constant ETHER_AMOUNT = 10_000 ether; - uint128 public constant PER_STREAM_AMOUNT = 10_000e18; - uint128 public constant REFUND_AMOUNT = 7500e18; // deposit - cliff amount + uint256 public constant MAX_SEGMENT_COUNT = 10_000; + uint40 public immutable MAX_SEGMENT_DURATION; + uint256 public constant MAX_TRANCHE_COUNT = 10_000; + uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; + uint256 public SEGMENT_COUNT; uint40 public immutable START_TIME; + uint128 public constant TOTAL_AMOUNT = 10_030.090270812437311935e18; // deposit + broker fee uint40 public constant TOTAL_DURATION = 10_000 seconds; - uint128 public constant TOTAL_TRANSFER_AMOUNT = PER_STREAM_AMOUNT * uint128(BATCH_SIZE); - uint128 public constant WITHDRAW_AMOUNT = 2500e18; + uint256 public TRANCHE_COUNT; + uint128 public constant TOTAL_TRANSFER_AMOUNT = DEPOSIT_AMOUNT * uint128(BATCH_SIZE); + uint128 public constant WITHDRAW_AMOUNT = 2600e18; + uint40 public immutable WARP_26_PERCENT; // 26% of the way through the stream /*////////////////////////////////////////////////////////////////////////// MERKLE-LOCKUP @@ -52,7 +61,7 @@ contract Defaults is Merkle { string public constant IPFS_CID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; uint256[] public LEAVES = new uint256[](RECIPIENT_COUNT); uint256 public constant RECIPIENT_COUNT = 4; - bytes32 public immutable MERKLE_ROOT; + bytes32 public MERKLE_ROOT; string public constant NAME = "Airdrop Campaign"; bytes32 public constant NAME_BYTES32 = bytes32(abi.encodePacked("Airdrop Campaign")); uint64 public constant TOTAL_PERCENTAGE = uUNIT; @@ -69,18 +78,26 @@ contract Defaults is Merkle { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(Users memory users_, IERC20 asset_) { - users = users_; - asset = asset_; - - // Initialize the immutables. - START_TIME = uint40(block.timestamp) + 100 seconds; + constructor() { + START_TIME = JULY_1_2024 + 2 days; CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; - EXPIRATION = uint40(block.timestamp) + 12 weeks; - FIRST_CLAIM_TIME = uint40(block.timestamp); + MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); + SEGMENT_COUNT = 2; + TRANCHE_COUNT = 3; + WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; + + EXPIRATION = JULY_1_2024 + 12 weeks; + FIRST_CLAIM_TIME = JULY_1_2024; + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ - // Initialize the Merkle tree. + /// @dev We need a separate function to initialize the Merkle tree because, at the construction time, the users are + /// not yet set. + function initMerkleTree() public { LEAVES[0] = MerkleBuilder.computeLeaf(INDEX1, users.recipient1, CLAIM_AMOUNT); LEAVES[1] = MerkleBuilder.computeLeaf(INDEX2, users.recipient2, CLAIM_AMOUNT); LEAVES[2] = MerkleBuilder.computeLeaf(INDEX3, users.recipient3, CLAIM_AMOUNT); @@ -89,198 +106,182 @@ contract Defaults is Merkle { MERKLE_ROOT = getRoot(LEAVES.toBytes32()); } - function getLeaves() public view returns (uint256[] memory) { - return LEAVES; + function setAsset(IERC20 asset_) public { + asset = asset_; + } + + function setUsers(Users memory users_) public { + users = users_; } /*////////////////////////////////////////////////////////////////////////// - MERKLE-LOCKUP + STRUCTS //////////////////////////////////////////////////////////////////////////*/ - function index1Proof() public view returns (bytes32[] memory) { - uint256 leaf = MerkleBuilder.computeLeaf(INDEX1, users.recipient1, CLAIM_AMOUNT); - uint256 pos = Arrays.findUpperBound(LEAVES, leaf); - return getProof(LEAVES.toBytes32(), pos); + function broker() public view returns (Broker memory) { + return Broker({ account: users.broker, fee: BROKER_FEE }); } - function index2Proof() public view returns (bytes32[] memory) { - uint256 leaf = MerkleBuilder.computeLeaf(INDEX2, users.recipient2, CLAIM_AMOUNT); - uint256 pos = Arrays.findUpperBound(LEAVES, leaf); - return getProof(LEAVES.toBytes32(), pos); + function brokerNull() public pure returns (Broker memory) { + return Broker({ account: address(0), fee: ZERO }); } - function index3Proof() public view returns (bytes32[] memory) { - uint256 leaf = MerkleBuilder.computeLeaf(INDEX3, users.recipient3, CLAIM_AMOUNT); - uint256 pos = Arrays.findUpperBound(LEAVES, leaf); - return getProof(LEAVES.toBytes32(), pos); + function durations() public pure returns (LockupLinear.Durations memory) { + return LockupLinear.Durations({ cliff: CLIFF_DURATION, total: TOTAL_DURATION }); } - function index4Proof() public view returns (bytes32[] memory) { - uint256 leaf = MerkleBuilder.computeLeaf(INDEX4, users.recipient4, CLAIM_AMOUNT); - uint256 pos = Arrays.findUpperBound(LEAVES, leaf); - return getProof(LEAVES.toBytes32(), pos); + function lockupAmounts() public pure returns (Lockup.Amounts memory) { + return Lockup.Amounts({ deposited: DEPOSIT_AMOUNT, refunded: 0, withdrawn: 0 }); } - function baseParams() public view returns (MerkleLockup.ConstructorParams memory) { - return baseParams(users.admin, asset, EXPIRATION, MERKLE_ROOT); + function lockupCreateAmounts() public pure returns (Lockup.CreateAmounts memory) { + return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } - function baseParams( - address admin, - IERC20 asset_, - uint40 expiration, - bytes32 merkleRoot - ) - public - pure - returns (MerkleLockup.ConstructorParams memory) - { - return MerkleLockup.ConstructorParams({ - asset: asset_, - cancelable: CANCELABLE, - expiration: expiration, - initialAdmin: admin, - ipfsCID: IPFS_CID, - merkleRoot: merkleRoot, - name: NAME, - transferable: TRANSFERABLE + function lockupDynamicStream() public view returns (LockupDynamic.StreamLD memory) { + return LockupDynamic.StreamLD({ + amounts: lockupAmounts(), + asset: asset, + endTime: END_TIME, + isCancelable: true, + isDepleted: false, + isStream: true, + isTransferable: true, + recipient: users.recipient0, + segments: segments(), + sender: users.sender, + startTime: START_TIME, + wasCanceled: false }); } - function tranchesWithPercentages() - public - pure - returns (MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages_) - { - tranchesWithPercentages_ = new MerkleLT.TrancheWithPercentage[](2); - tranchesWithPercentages_[0] = - MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.25e18), duration: 2500 seconds }); - tranchesWithPercentages_[1] = - MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.75e18), duration: 7500 seconds }); + function lockupDynamicTimestamps() public view returns (LockupDynamic.Timestamps memory) { + return LockupDynamic.Timestamps({ start: START_TIME, end: END_TIME }); } - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP - //////////////////////////////////////////////////////////////////////////*/ - - function assets() public view returns (IERC20[] memory assets_) { - assets_ = new IERC20[](1); - assets_[0] = asset; + function lockupLinearStream() public view returns (LockupLinear.StreamLL memory) { + return LockupLinear.StreamLL({ + amounts: lockupAmounts(), + asset: asset, + cliffTime: CLIFF_TIME, + endTime: END_TIME, + isCancelable: true, + isTransferable: true, + isDepleted: false, + isStream: true, + recipient: users.recipient0, + sender: users.sender, + startTime: START_TIME, + wasCanceled: false + }); } - function broker() public view returns (Broker memory) { - return Broker({ account: users.broker, fee: BROKER_FEE }); + function lockupLinearTimestamps() public view returns (LockupLinear.Timestamps memory) { + return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); } - function incrementalStreamIds() public pure returns (uint256[] memory streamIds) { - return ArrayBuilder.fillStreamIds({ firstStreamId: 1, batchSize: BATCH_SIZE }); + function lockupTranchedStream() public view returns (LockupTranched.StreamLT memory) { + return LockupTranched.StreamLT({ + amounts: lockupAmounts(), + asset: asset, + endTime: END_TIME, + isCancelable: true, + isDepleted: false, + isStream: true, + isTransferable: true, + recipient: users.recipient0, + sender: users.sender, + startTime: START_TIME, + tranches: tranches(), + wasCanceled: false + }); } - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-DYNAMIC - //////////////////////////////////////////////////////////////////////////*/ + function lockupTranchedTimestamps() public view returns (LockupTranched.Timestamps memory) { + return LockupTranched.Timestamps({ start: START_TIME, end: END_TIME }); + } - function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { - return createWithDurationsLD(asset, PER_STREAM_AMOUNT, segmentsWithDurations()); + function segments() public view returns (LockupDynamic.Segment[] memory segments_) { + segments_ = new LockupDynamic.Segment[](2); + segments_[0] = ( + LockupDynamic.Segment({ amount: 2500e18, exponent: ud2x18(3.14e18), timestamp: START_TIME + CLIFF_DURATION }) + ); + segments_[1] = ( + LockupDynamic.Segment({ amount: 7500e18, exponent: ud2x18(0.5e18), timestamp: START_TIME + TOTAL_DURATION }) + ); } - function createWithDurationsLD( - IERC20 asset_, - uint128 totalAmount_, - LockupDynamic.SegmentWithDuration[] memory segments_ - ) + function segmentsWithDurations() public view - returns (LockupDynamic.CreateWithDurations memory) + returns (LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations_) { - return LockupDynamic.CreateWithDurations({ - sender: users.alice, - recipient: users.recipient0, - totalAmount: totalAmount_, - asset: asset_, - cancelable: true, - transferable: true, - segments: segments_, - broker: broker() - }); + LockupDynamic.Segment[] memory segments_ = segments(); + segmentsWithDurations_ = new LockupDynamic.SegmentWithDuration[](2); + segmentsWithDurations_[0] = ( + LockupDynamic.SegmentWithDuration({ + amount: segments_[0].amount, + exponent: segments_[0].exponent, + duration: 2500 seconds + }) + ); + segmentsWithDurations_[1] = ( + LockupDynamic.SegmentWithDuration({ + amount: segments_[1].amount, + exponent: segments_[1].exponent, + duration: 7500 seconds + }) + ); } - function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { - return createWithTimestampsLD(asset, PER_STREAM_AMOUNT, segments()); + function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = new LockupTranched.Tranche[](3); + tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: START_TIME + CLIFF_DURATION }); + tranches_[1] = LockupTranched.Tranche({ amount: 100e18, timestamp: WARP_26_PERCENT }); + tranches_[2] = LockupTranched.Tranche({ amount: 7400e18, timestamp: START_TIME + TOTAL_DURATION }); } - function createWithTimestampsLD( - IERC20 asset_, - uint128 totalAmount_, - LockupDynamic.Segment[] memory segments_ - ) + function tranchesWithDurations() public - view - returns (LockupDynamic.CreateWithTimestamps memory) + pure + returns (LockupTranched.TrancheWithDuration[] memory tranchesWithDurations_) { - return LockupDynamic.CreateWithTimestamps({ - sender: users.alice, + tranchesWithDurations_ = new LockupTranched.TrancheWithDuration[](3); + tranchesWithDurations_[0] = LockupTranched.TrancheWithDuration({ amount: 2500e18, duration: 2500 seconds }); + tranchesWithDurations_[1] = LockupTranched.TrancheWithDuration({ amount: 100e18, duration: 100 seconds }); + tranchesWithDurations_[2] = LockupTranched.TrancheWithDuration({ amount: 7400e18, duration: 7400 seconds }); + } + + /*////////////////////////////////////////////////////////////////////////// + CREATE-PARAMS + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { + return LockupDynamic.CreateWithDurations({ + sender: users.sender, recipient: users.recipient0, - totalAmount: totalAmount_, - asset: asset_, + totalAmount: TOTAL_AMOUNT, + asset: asset, cancelable: true, transferable: true, - startTime: START_TIME, - segments: segments_, + segments: segmentsWithDurations(), broker: broker() }); } - /// @dev Returns a batch of {LockupDynamic.Segment} parameters. - function segments() public view returns (LockupDynamic.Segment[] memory segments_) { - segments_ = new LockupDynamic.Segment[](2); - segments_[0] = LockupDynamic.Segment({ - amount: 2500e18, - exponent: ud2x18(3.14e18), - timestamp: START_TIME + CLIFF_DURATION - }); - segments_[1] = LockupDynamic.Segment({ - amount: 7500e18, - exponent: ud2x18(3.14e18), - timestamp: START_TIME + TOTAL_DURATION - }); - } - - /// @dev Returns a batch of {LockupDynamic.SegmentWithDuration} parameters. - function segmentsWithDurations() public pure returns (LockupDynamic.SegmentWithDuration[] memory) { - return segmentsWithDurations({ amount0: 2500e18, amount1: 7500e18 }); + function createWithDurationsBrokerNullLD() public view returns (LockupDynamic.CreateWithDurations memory) { + LockupDynamic.CreateWithDurations memory params = createWithDurationsLD(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } - /// @dev Returns a batch of {LockupDynamic.SegmentWithDuration} parameters. - function segmentsWithDurations( - uint128 amount0, - uint128 amount1 - ) - public - pure - returns (LockupDynamic.SegmentWithDuration[] memory segments_) - { - segments_ = new LockupDynamic.SegmentWithDuration[](2); - segments_[0] = - LockupDynamic.SegmentWithDuration({ amount: amount0, exponent: ud2x18(3.14e18), duration: 2500 seconds }); - segments_[1] = - LockupDynamic.SegmentWithDuration({ amount: amount1, exponent: ud2x18(3.14e18), duration: 7500 seconds }); - } - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-LINEAR - //////////////////////////////////////////////////////////////////////////*/ - function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { - return createWithDurationsLL(asset); - } - - function createWithDurationsLL(IERC20 asset_) public view returns (LockupLinear.CreateWithDurations memory) { return LockupLinear.CreateWithDurations({ - sender: users.alice, + sender: users.sender, recipient: users.recipient0, - totalAmount: PER_STREAM_AMOUNT, - asset: asset_, + totalAmount: TOTAL_AMOUNT, + asset: asset, cancelable: true, transferable: true, durations: durations(), @@ -288,145 +289,116 @@ contract Defaults is Merkle { }); } - function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { - return createWithTimestampsLL(asset); + function createWithDurationsBrokerNullLL() public view returns (LockupLinear.CreateWithDurations memory) { + LockupLinear.CreateWithDurations memory params = createWithDurationsLL(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } - function createWithTimestampsLL(IERC20 asset_) public view returns (LockupLinear.CreateWithTimestamps memory) { - return LockupLinear.CreateWithTimestamps({ - sender: users.alice, + function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { + return LockupTranched.CreateWithDurations({ + sender: users.sender, recipient: users.recipient0, - totalAmount: PER_STREAM_AMOUNT, - asset: asset_, + totalAmount: TOTAL_AMOUNT, + asset: asset, cancelable: true, transferable: true, - timestamps: linearTimestamps(), + tranches: tranchesWithDurations(), broker: broker() }); } - function durations() public pure returns (LockupLinear.Durations memory) { - return LockupLinear.Durations({ cliff: CLIFF_DURATION, total: TOTAL_DURATION }); + function createWithDurationsBrokerNullLT() public view returns (LockupTranched.CreateWithDurations memory) { + LockupTranched.CreateWithDurations memory params = createWithDurationsLT(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } - function linearTimestamps() private view returns (LockupLinear.Timestamps memory) { - return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); + function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { + return LockupDynamic.CreateWithTimestamps({ + sender: users.sender, + recipient: users.recipient0, + totalAmount: TOTAL_AMOUNT, + asset: asset, + cancelable: true, + transferable: true, + startTime: START_TIME, + segments: segments(), + broker: broker() + }); } - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHED - //////////////////////////////////////////////////////////////////////////*/ - - function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { - return createWithDurationsLT(asset, PER_STREAM_AMOUNT, tranchesWithDurations()); + function createWithTimestampsBrokerNullLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { + LockupDynamic.CreateWithTimestamps memory params = createWithTimestampsLD(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } - function createWithDurationsLT( - IERC20 asset_, - uint128 totalAmount_, - LockupTranched.TrancheWithDuration[] memory tranches_ - ) - public - view - returns (LockupTranched.CreateWithDurations memory) - { - return LockupTranched.CreateWithDurations({ - sender: users.alice, + function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { + return LockupLinear.CreateWithTimestamps({ + sender: users.sender, recipient: users.recipient0, - totalAmount: totalAmount_, - asset: asset_, + totalAmount: TOTAL_AMOUNT, + asset: asset, cancelable: true, transferable: true, - tranches: tranches_, + timestamps: lockupLinearTimestamps(), broker: broker() }); } - function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { - return createWithTimestampsLT(asset, PER_STREAM_AMOUNT, tranches()); + function createWithTimestampsBrokerNullLL() public view returns (LockupLinear.CreateWithTimestamps memory) { + LockupLinear.CreateWithTimestamps memory params = createWithTimestampsLL(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } - function createWithTimestampsLT( - IERC20 asset_, - uint128 totalAmount_, - LockupTranched.Tranche[] memory tranches_ - ) - public - view - returns (LockupTranched.CreateWithTimestamps memory) - { + function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { return LockupTranched.CreateWithTimestamps({ - sender: users.alice, + sender: users.sender, recipient: users.recipient0, - totalAmount: totalAmount_, - asset: asset_, + totalAmount: TOTAL_AMOUNT, + asset: asset, cancelable: true, transferable: true, startTime: START_TIME, - tranches: tranches_, + tranches: tranches(), broker: broker() }); } - function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { - tranches_ = new LockupTranched.Tranche[](2); - tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: uint40(block.timestamp) + CLIFF_DURATION }); - tranches_[1] = LockupTranched.Tranche({ amount: 7500e18, timestamp: uint40(block.timestamp) + TOTAL_DURATION }); - } - - /// @dev Mirros the logic from {SablierV2MerkleLT._calculateTranches}. - function tranches(uint128 totalAmount) public view returns (LockupTranched.Tranche[] memory tranches_) { - tranches_ = tranches(); - - uint128 amount0 = ud(totalAmount).mul(tranchesWithPercentages()[0].unlockPercentage.intoUD60x18()).intoUint128(); - uint128 amount1 = ud(totalAmount).mul(tranchesWithPercentages()[1].unlockPercentage.intoUD60x18()).intoUint128(); - - tranches_[0].amount = amount0; - tranches_[1].amount = amount1; - - uint128 amountsSum = amount0 + amount1; - - if (amountsSum != totalAmount) { - tranches_[1].amount += totalAmount - amountsSum; - } - } - - /// @dev Returns a batch of {LockupTranched.TrancheWithDuration} parameters. - function tranchesWithDurations() public pure returns (LockupTranched.TrancheWithDuration[] memory) { - return tranchesWithDurations({ amount0: 2500e18, amount1: 7500e18 }); - } - - /// @dev Returns a batch of {LockupTranched.TrancheWithDuration} parameters. - function tranchesWithDurations( - uint128 amount0, - uint128 amount1 - ) - public - pure - returns (LockupTranched.TrancheWithDuration[] memory segments_) - { - segments_ = new LockupTranched.TrancheWithDuration[](2); - segments_[0] = LockupTranched.TrancheWithDuration({ amount: amount0, duration: 2500 seconds }); - segments_[1] = LockupTranched.TrancheWithDuration({ amount: amount1, duration: 7500 seconds }); + function createWithTimestampsBrokerNullLT() public view returns (LockupTranched.CreateWithTimestamps memory) { + LockupTranched.CreateWithTimestamps memory params = createWithTimestampsLT(); + params.totalAmount = DEPOSIT_AMOUNT; + params.broker = brokerNull(); + return params; } /*////////////////////////////////////////////////////////////////////////// BATCH-LOCKUP //////////////////////////////////////////////////////////////////////////*/ + function incrementalStreamIds() public pure returns (uint256[] memory streamIds) { + return ArrayBuilder.fillStreamIds({ firstStreamId: 1, batchSize: BATCH_SIZE }); + } + /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLD} parameters. function batchCreateWithDurationsLD() public view returns (BatchLockup.CreateWithDurationsLD[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsLD(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLD(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLL} parameters. function batchCreateWithDurationsLL() public view returns (BatchLockup.CreateWithDurationsLL[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsLL(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLL(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLT} parameters. function batchCreateWithDurationsLT() public view returns (BatchLockup.CreateWithDurationsLT[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsLT(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLT(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLD} parameters. @@ -440,7 +412,7 @@ contract Defaults is Merkle { view returns (BatchLockup.CreateWithTimestampsLD[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsLD(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLD(), batchSize); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLL} parameters. @@ -454,7 +426,7 @@ contract Defaults is Merkle { view returns (BatchLockup.CreateWithTimestampsLL[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsLL(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLL(), batchSize); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLT} parameters. @@ -468,6 +440,103 @@ contract Defaults is Merkle { view returns (BatchLockup.CreateWithTimestampsLT[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsLT(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLT(), batchSize); + } + + /*////////////////////////////////////////////////////////////////////////// + MERKLE-LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + function baseParams() public view returns (MerkleLockup.ConstructorParams memory) { + return baseParams(users.admin, asset, EXPIRATION, MERKLE_ROOT); + } + + function baseParams( + address admin, + IERC20 asset_, + uint40 expiration, + bytes32 merkleRoot + ) + public + pure + returns (MerkleLockup.ConstructorParams memory) + { + return MerkleLockup.ConstructorParams({ + asset: asset_, + cancelable: CANCELABLE, + expiration: expiration, + initialAdmin: admin, + ipfsCID: IPFS_CID, + merkleRoot: merkleRoot, + name: NAME, + transferable: TRANSFERABLE + }); + } + + function index1Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX1, users.recipient1, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index2Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX2, users.recipient2, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index3Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX3, users.recipient3, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function index4Proof() public view returns (bytes32[] memory) { + uint256 leaf = MerkleBuilder.computeLeaf(INDEX4, users.recipient4, CLAIM_AMOUNT); + uint256 pos = Arrays.findUpperBound(LEAVES, leaf); + return getProof(LEAVES.toBytes32(), pos); + } + + function getLeaves() public view returns (uint256[] memory) { + return LEAVES; + } + + function tranchesMerkleLockup() public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = new LockupTranched.Tranche[](2); + tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: uint40(block.timestamp) + CLIFF_DURATION }); + tranches_[1] = LockupTranched.Tranche({ amount: 7500e18, timestamp: uint40(block.timestamp) + TOTAL_DURATION }); + } + + /// @dev Mirros the logic from {SablierV2MerkleLT._calculateTranches}. + function tranchesMerkleLockup(uint128 totalAmount) + public + view + returns (LockupTranched.Tranche[] memory tranches_) + { + tranches_ = tranchesMerkleLockup(); + + uint128 amount0 = ud(totalAmount).mul(tranchesWithPercentages()[0].unlockPercentage.intoUD60x18()).intoUint128(); + uint128 amount1 = ud(totalAmount).mul(tranchesWithPercentages()[1].unlockPercentage.intoUD60x18()).intoUint128(); + + tranches_[0].amount = amount0; + tranches_[1].amount = amount1; + + uint128 amountsSum = amount0 + amount1; + + if (amountsSum != totalAmount) { + tranches_[1].amount += totalAmount - amountsSum; + } + } + + function tranchesWithPercentages() + public + pure + returns (MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages_) + { + tranchesWithPercentages_ = new MerkleLT.TrancheWithPercentage[](2); + tranchesWithPercentages_[0] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.25e18), duration: 2500 seconds }); + tranchesWithPercentages_[1] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: ud2x18(0.75e18), duration: 7500 seconds }); } } diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol new file mode 100644 index 000000000..ed3b27415 --- /dev/null +++ b/test/utils/DeployOptimized.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { StdCheats } from "forge-std/src/StdCheats.sol"; + +import { ISablierV2LockupDynamic } from "../../src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierV2BatchLockup } from "../../src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; + +abstract contract DeployOptimized is StdCheats { + /*////////////////////////////////////////////////////////////////////////// + CORE + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Deploys {SablierV2LockupDynamic} from an optimized source compiled with `--via-ir`. + function deployOptimizedLockupDynamic( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor_, + uint256 maxSegmentCount + ) + internal + returns (ISablierV2LockupDynamic) + { + return ISablierV2LockupDynamic( + deployCode( + "out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json", + abi.encode(initialAdmin, address(nftDescriptor_), maxSegmentCount) + ) + ); + } + + /// @dev Deploys {SablierV2LockupLinear} from an optimized source compiled with `--via-ir`. + function deployOptimizedLockupLinear( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor_ + ) + internal + returns (ISablierV2LockupLinear) + { + return ISablierV2LockupLinear( + deployCode( + "out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json", + abi.encode(initialAdmin, address(nftDescriptor_)) + ) + ); + } + + /// @dev Deploys {SablierV2LockupTranched} from an optimized source compiled with `--via-ir`. + function deployOptimizedLockupTranched( + address initialAdmin, + ISablierV2NFTDescriptor nftDescriptor_, + uint256 maxTrancheCount + ) + internal + returns (ISablierV2LockupTranched) + { + return ISablierV2LockupTranched( + deployCode( + "out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json", + abi.encode(initialAdmin, address(nftDescriptor_), maxTrancheCount) + ) + ); + } + + /// @dev Deploys {SablierV2NFTDescriptor} from an optimized source compiled with `--via-ir`. + function deployOptimizedNFTDescriptor() internal returns (ISablierV2NFTDescriptor) { + return + ISablierV2NFTDescriptor(deployCode("out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json")); + } + + /// @notice Deploys all V2 Core contracts from an optimized source compiled with `--via-ir` in the following order: + /// + /// 1. {SablierV2NFTDescriptor} + /// 2. {SablierV2LockupDynamic} + /// 3. {SablierV2LockupLinear} + /// 4. {SablierV2LockupTranched} + function deployOptimizedCore( + address initialAdmin, + uint256 maxSegmentCount, + uint256 maxTrancheCount + ) + internal + returns ( + ISablierV2LockupDynamic lockupDynamic_, + ISablierV2LockupLinear lockupLinear_, + ISablierV2LockupTranched lockupTranched_, + ISablierV2NFTDescriptor nftDescriptor_ + ) + { + nftDescriptor_ = deployOptimizedNFTDescriptor(); + lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxSegmentCount); + lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, nftDescriptor_); + lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxTrancheCount); + } + + /*////////////////////////////////////////////////////////////////////////// + PERIPHERY + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Deploys {SablierV2BatchLockup} from an optimized source compiled with `--via-ir`. + function deployOptimizedBatchLockup() internal returns (ISablierV2BatchLockup) { + return ISablierV2BatchLockup(deployCode("out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json")); + } + + /// @dev Deploys {SablierV2MerkleLockupFactory} from an optimized source compiled with `--via-ir`. + function deployOptimizedMerkleLockupFactory() internal returns (ISablierV2MerkleLockupFactory) { + return ISablierV2MerkleLockupFactory( + deployCode("out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json") + ); + } + + /// @notice Deploys all V2 Periphery contracts from an optimized source in the following order: + /// + /// 1. {SablierV2BatchLockup} + /// 2. {SablierV2MerkleLockupFactory} + function deployOptimizedPeriphery() internal returns (ISablierV2BatchLockup, ISablierV2MerkleLockupFactory) { + return (deployOptimizedBatchLockup(), deployOptimizedMerkleLockupFactory()); + } + + /*////////////////////////////////////////////////////////////////////////// + PROTOCOL + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Deploys all V2 Core and Periphery contracts from an optimized source in the following order: + /// + /// 1. {SablierV2NFTDescriptor} + /// 2. {SablierV2LockupDynamic} + /// 3. {SablierV2LockupLinear} + /// 4. {SablierV2LockupTranched} + /// 5. {SablierV2BatchLockup} + /// 6. {SablierV2MerkleLockupFactory} + function deployOptimizedProtocol( + address initialAdmin, + uint256 maxSegmentCount, + uint256 maxTrancheCount + ) + internal + returns ( + ISablierV2LockupDynamic lockupDynamic_, + ISablierV2LockupLinear lockupLinear_, + ISablierV2LockupTranched lockupTranched_, + ISablierV2NFTDescriptor nftDescriptor_, + ISablierV2BatchLockup batchLockup_, + ISablierV2MerkleLockupFactory merkleLockupFactory_ + ) + { + (lockupDynamic_, lockupLinear_, lockupTranched_, nftDescriptor_) = + deployOptimizedCore(initialAdmin, maxSegmentCount, maxTrancheCount); + (batchLockup_, merkleLockupFactory_) = deployOptimizedPeriphery(); + } +} diff --git a/test/core/utils/Events.sol b/test/utils/Events.sol similarity index 68% rename from test/core/utils/Events.sol rename to test/utils/Events.sol index 925728c25..fc4ff77f7 100644 --- a/test/core/utils/Events.sol +++ b/test/utils/Events.sol @@ -3,8 +3,13 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2NFTDescriptor } from "../../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../../src/core/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLL } from "../../src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "../../src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. abstract contract Events { @@ -29,7 +34,7 @@ abstract contract Events { event TransferAdmin(address indexed oldAdmin, address indexed newAdmin); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP + CORE //////////////////////////////////////////////////////////////////////////*/ event AllowToHook(address indexed admin, address recipient); @@ -42,7 +47,6 @@ abstract contract Events { uint128 senderAmount, uint128 recipientAmount ); - event RenounceLockupStream(uint256 indexed streamId); event SetNFTDescriptor( @@ -51,10 +55,6 @@ abstract contract Events { event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-DYNAMIC - //////////////////////////////////////////////////////////////////////////*/ - event CreateLockupDynamicStream( uint256 streamId, address funder, @@ -69,10 +69,6 @@ abstract contract Events { address broker ); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-LINEAR - //////////////////////////////////////////////////////////////////////////*/ - event CreateLockupLinearStream( uint256 streamId, address funder, @@ -86,10 +82,6 @@ abstract contract Events { address broker ); - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHED - //////////////////////////////////////////////////////////////////////////*/ - event CreateLockupTranchedStream( uint256 streamId, address funder, @@ -103,4 +95,31 @@ abstract contract Events { LockupTranched.Timestamps timestamps, address broker ); + + /*////////////////////////////////////////////////////////////////////////// + PERIPHERY + //////////////////////////////////////////////////////////////////////////*/ + + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); + + event Clawback(address indexed admin, address indexed to, uint128 amount); + + event CreateMerkleLL( + ISablierV2MerkleLL indexed merkleLL, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupLinear lockupLinear, + LockupLinear.Durations streamDurations, + uint256 aggregateAmount, + uint256 recipientCount + ); + + event CreateMerkleLT( + ISablierV2MerkleLT indexed merkleLT, + MerkleLockup.ConstructorParams baseParams, + ISablierV2LockupTranched lockupTranched, + MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, + uint256 totalDuration, + uint256 aggregateAmount, + uint256 recipientCount + ); } diff --git a/test/core/utils/Fuzzers.sol b/test/utils/Fuzzers.sol similarity index 94% rename from test/core/utils/Fuzzers.sol rename to test/utils/Fuzzers.sol index d915e459b..17959ce37 100644 --- a/test/core/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -4,33 +4,36 @@ pragma solidity >=0.8.22; import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/Uint128.sol"; import { UD60x18, ud, uUNIT } from "@prb/math/src/UD60x18.sol"; -import { Lockup, LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupTranched } from "../../src/core/types/DataTypes.sol"; import { Constants } from "./Constants.sol"; -import { Defaults } from "./Defaults.sol"; import { Utils } from "./Utils.sol"; abstract contract Fuzzers is Constants, Utils { using CastingUint128 for uint128; - Defaults private defaults = new Defaults(); - /*////////////////////////////////////////////////////////////////////////// LOCKUP-DYNAMIC //////////////////////////////////////////////////////////////////////////*/ /// @dev Just like {fuzzDynamicStreamAmounts} but with defaults. - function fuzzDynamicStreamAmounts(LockupDynamic.Segment[] memory segments) + function fuzzDynamicStreamAmounts( + LockupDynamic.Segment[] memory segments, + UD60x18 brokerFee + ) internal - view + pure returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { (totalAmount, createAmounts) = - fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: defaults.BROKER_FEE() }); + fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: brokerFee }); } /// @dev Just like {fuzzDynamicStreamAmounts} but with defaults. - function fuzzDynamicStreamAmounts(LockupDynamic.SegmentWithDuration[] memory segments) + function fuzzDynamicStreamAmounts( + LockupDynamic.SegmentWithDuration[] memory segments, + UD60x18 brokerFee + ) internal view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) @@ -39,7 +42,7 @@ abstract contract Fuzzers is Constants, Utils { (totalAmount, createAmounts) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segmentsWithTimestamps, - brokerFee: defaults.BROKER_FEE() + brokerFee: brokerFee }); for (uint256 i = 0; i < segmentsWithTimestamps.length; ++i) { segments[i].amount = segmentsWithTimestamps[i].amount; @@ -199,17 +202,23 @@ abstract contract Fuzzers is Constants, Utils { } /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. - function fuzzTranchedStreamAmounts(LockupTranched.Tranche[] memory tranches) + function fuzzTranchedStreamAmounts( + LockupTranched.Tranche[] memory tranches, + UD60x18 brokerFee + ) internal - view + pure returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) { (totalAmount, createAmounts) = - fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: defaults.BROKER_FEE() }); + fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: brokerFee }); } /// @dev Just like {fuzzTranchedStreamAmounts} but with defaults. - function fuzzTranchedStreamAmounts(LockupTranched.TrancheWithDuration[] memory tranches) + function fuzzTranchedStreamAmounts( + LockupTranched.TrancheWithDuration[] memory tranches, + UD60x18 brokerFee + ) internal view returns (uint128 totalAmount, Lockup.CreateAmounts memory createAmounts) @@ -218,7 +227,7 @@ abstract contract Fuzzers is Constants, Utils { (totalAmount, createAmounts) = fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranchesWithTimestamps, - brokerFee: defaults.BROKER_FEE() + brokerFee: brokerFee }); for (uint256 i = 0; i < tranchesWithTimestamps.length; ++i) { tranches[i].amount = tranchesWithTimestamps[i].amount; diff --git a/test/periphery/utils/MerkleBuilder.sol b/test/utils/MerkleBuilder.sol similarity index 100% rename from test/periphery/utils/MerkleBuilder.sol rename to test/utils/MerkleBuilder.sol diff --git a/test/periphery/utils/MerkleBuilder.t.sol b/test/utils/MerkleBuilder.t.sol similarity index 100% rename from test/periphery/utils/MerkleBuilder.t.sol rename to test/utils/MerkleBuilder.t.sol diff --git a/test/periphery/utils/Murky.sol b/test/utils/Murky.sol similarity index 100% rename from test/periphery/utils/Murky.sol rename to test/utils/Murky.sol diff --git a/test/core/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol similarity index 66% rename from test/core/utils/Precompiles.t.sol rename to test/utils/Precompiles.t.sol index 8d94f8144..65577624e 100644 --- a/test/core/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -4,10 +4,12 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; import { Precompiles } from "precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "core/interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierV2BatchLockup } from "src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLockupFactory } from "src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; import { Base_Test } from "../Base.t.sol"; @@ -22,6 +24,10 @@ contract Precompiles_Test is Base_Test { } } + /*////////////////////////////////////////////////////////////////////////// + CORE + //////////////////////////////////////////////////////////////////////////*/ + function test_DeployLockupDynamic() external onlyTestOptimizedProfile { address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, nftDescriptor)); address expectedLockupDynamic = @@ -87,6 +93,39 @@ contract Precompiles_Test is Base_Test { assertEq(address(actualNFTDescriptor).code, address(expectedNFTDescriptor).code, "bytecodes mismatch"); } + /*////////////////////////////////////////////////////////////////////////// + PERIPHERY + //////////////////////////////////////////////////////////////////////////*/ + + function test_DeployBatchLockup() external onlyTestOptimizedProfile { + address actualBatchLockup = address(precompiles.deployBatchLockup()); + address expectedBatchLockup = address(deployOptimizedBatchLockup()); + assertEq(actualBatchLockup.code, expectedBatchLockup.code, "bytecodes mismatch"); + } + + function test_DeployMerkleLockupFactory() external onlyTestOptimizedProfile { + address actualFactory = address(precompiles.deployMerkleLockupFactory()); + address expectedFactory = address(deployOptimizedMerkleLockupFactory()); + assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); + } + + function test_DeployPeriphery() external onlyTestOptimizedProfile { + (ISablierV2BatchLockup actualBatchLockup, ISablierV2MerkleLockupFactory actualMerkleLockupFactory) = + precompiles.deployPeriphery(); + + (ISablierV2BatchLockup expectedBatchLockup, ISablierV2MerkleLockupFactory expectedMerkleLockupFactory) = + deployOptimizedPeriphery(); + + assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); + assertEq( + address(actualMerkleLockupFactory).code, address(expectedMerkleLockupFactory).code, "bytecodes mismatch" + ); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + /// @dev The expected bytecode has to be adjusted because {SablierV2Lockup} inherits from {NoDelegateCall}, which /// saves the contract's own address in storage. function adjustBytecode( diff --git a/test/core/utils/Types.sol b/test/utils/Types.sol similarity index 62% rename from test/core/utils/Types.sol rename to test/utils/Types.sol index 2ba8fdb1c..173661031 100644 --- a/test/core/utils/Types.sol +++ b/test/utils/Types.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22; struct Users { - // Default admin for all Sablier V2 contracts. + // Default admin for all contracts. address payable admin; // Impartial user. address payable alice; @@ -12,8 +12,12 @@ struct Users { address payable eve; // Default NFT operator. address payable operator; - // Default stream recipient. - address payable recipient; + // Default stream recipients. + address payable recipient0; + address payable recipient1; + address payable recipient2; + address payable recipient3; + address payable recipient4; // Default stream sender. address payable sender; } diff --git a/test/core/utils/Utils.sol b/test/utils/Utils.sol similarity index 97% rename from test/core/utils/Utils.sol rename to test/utils/Utils.sol index bf5099d0e..ae29abb3a 100644 --- a/test/core/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -5,7 +5,7 @@ import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { PRBMathUtils } from "@prb/math/test/utils/Utils.sol"; import { CommonBase } from "forge-std/src/Base.sol"; -import { LockupDynamic, LockupTranched } from "../../../src/core/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../../src/core/types/DataTypes.sol"; abstract contract Utils is CommonBase, PRBMathUtils { /// @dev Bounds a `uint128` number. From baa6b531cd47b8c45e7f26e2d76b45a021ac0370 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 25 Jul 2024 17:08:03 +0300 Subject: [PATCH 06/34] feat: add periphery scripts feat: add core and periphery dirs under script feat: implement DeployDeterministicProtocol script refactor(shell): update CLI run in generate-svg script refactor(script): use count maps in deploy protocol chore: re-order imports Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- script/DeployDeterministicProtocol.s.sol | 43 ++++++++++++++++++ script/DeployProtocol.s.sol | 39 ++++++++++++++++ script/{ => core}/DeployCore.s.sol | 10 ++--- script/{ => core}/DeployCore2.s.sol | 10 ++--- .../{ => core}/DeployDeterministicCore.s.sol | 10 ++--- .../{ => core}/DeployDeterministicCore2.s.sol | 10 ++--- .../DeployDeterministicLockupDynamic.s.sol | 6 +-- .../DeployDeterministicLockupLinear.s.sol | 6 +-- .../DeployDeterministicLockupTranched.s.sol | 6 +-- .../DeployDeterministicNFTDescriptor.s.sol | 4 +- script/{ => core}/DeployLockupDynamic.s.sol | 6 +-- script/{ => core}/DeployLockupLinear.s.sol | 6 +-- script/{ => core}/DeployLockupTranched.s.sol | 6 +-- script/{ => core}/DeployNFTDescriptor.s.sol | 4 +- script/{ => core}/GenerateSVG.s.sol | 8 ++-- script/{ => core}/Init.s.sol | 8 ++-- script/periphery/CreateMerkleLL.s.sol | 43 ++++++++++++++++++ script/periphery/CreateMerkleLT.s.sol | 45 +++++++++++++++++++ script/periphery/DeployBatchLockup.t.sol | 13 ++++++ .../DeployDeterministicBatchLockup.s.sol | 16 +++++++ .../DeployDeterministicPeriphery.s.sol | 27 +++++++++++ .../periphery/DeployMerkleLockupFactory.s.sol | 13 ++++++ script/periphery/DeployPeriphery.s.sol | 24 ++++++++++ shell/generate-svg.sh | 2 +- 24 files changed, 314 insertions(+), 51 deletions(-) create mode 100644 script/DeployDeterministicProtocol.s.sol create mode 100644 script/DeployProtocol.s.sol rename script/{ => core}/DeployCore.s.sol (69%) rename script/{ => core}/DeployCore2.s.sol (66%) rename script/{ => core}/DeployDeterministicCore.s.sol (74%) rename script/{ => core}/DeployDeterministicCore2.s.sol (70%) rename script/{ => core}/DeployDeterministicLockupDynamic.s.sol (75%) rename script/{ => core}/DeployDeterministicLockupLinear.s.sol (74%) rename script/{ => core}/DeployDeterministicLockupTranched.s.sol (75%) rename script/{ => core}/DeployDeterministicNFTDescriptor.s.sol (79%) rename script/{ => core}/DeployLockupDynamic.s.sol (67%) rename script/{ => core}/DeployLockupLinear.s.sol (66%) rename script/{ => core}/DeployLockupTranched.s.sol (67%) rename script/{ => core}/DeployNFTDescriptor.s.sol (68%) rename script/{ => core}/GenerateSVG.s.sol (87%) rename script/{ => core}/Init.s.sol (92%) create mode 100644 script/periphery/CreateMerkleLL.s.sol create mode 100644 script/periphery/CreateMerkleLT.s.sol create mode 100644 script/periphery/DeployBatchLockup.t.sol create mode 100644 script/periphery/DeployDeterministicBatchLockup.s.sol create mode 100644 script/periphery/DeployDeterministicPeriphery.s.sol create mode 100644 script/periphery/DeployMerkleLockupFactory.s.sol create mode 100644 script/periphery/DeployPeriphery.s.sol diff --git a/script/DeployDeterministicProtocol.s.sol b/script/DeployDeterministicProtocol.s.sol new file mode 100644 index 000000000..3f915c8b2 --- /dev/null +++ b/script/DeployDeterministicProtocol.s.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2MerkleLockupFactory } from "../src/periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierV2BatchLockup } from "../src/periphery/SablierV2BatchLockup.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @notice Deploys the Sablier V2 Protocol at deterministic addresses across chains. +contract DeployDeterministicProtocol is BaseScript { + /// @dev Deploy via Forge. + function run(address initialAdmin) + public + virtual + broadcast + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor, + SablierV2BatchLockup batchLockup, + SablierV2MerkleLockupFactory merkleLockupFactory + ) + { + bytes32 salt = constructCreate2Salt(); + + // Deploy V2 Core. + nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); + lockupDynamic = + new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + lockupTranched = + new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + + // Deploy V2 Periphery. + batchLockup = new SablierV2BatchLockup{ salt: salt }(); + merkleLockupFactory = new SablierV2MerkleLockupFactory{ salt: salt }(); + } +} diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol new file mode 100644 index 000000000..6e0d907b8 --- /dev/null +++ b/script/DeployProtocol.s.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2MerkleLockupFactory } from "../src/periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierV2BatchLockup } from "../src/periphery/SablierV2BatchLockup.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @notice Deploys the Sablier V2 Protocol. +contract DeployProtocol is BaseScript { + /// @dev Deploy via Forge. + function run(address initialAdmin) + public + virtual + broadcast + returns ( + SablierV2LockupDynamic lockupDynamic, + SablierV2LockupLinear lockupLinear, + SablierV2LockupTranched lockupTranched, + SablierV2NFTDescriptor nftDescriptor, + SablierV2BatchLockup batchLockup, + SablierV2MerkleLockupFactory merkleLockupFactory + ) + { + // Deploy V2 Core. + nftDescriptor = new SablierV2NFTDescriptor(); + lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + + // Deploy V2 Periphery. + batchLockup = new SablierV2BatchLockup(); + merkleLockupFactory = new SablierV2MerkleLockupFactory(); + } +} diff --git a/script/DeployCore.s.sol b/script/core/DeployCore.s.sol similarity index 69% rename from script/DeployCore.s.sol rename to script/core/DeployCore.s.sol index 317f0746b..8c5e99609 100644 --- a/script/DeployCore.s.sol +++ b/script/core/DeployCore.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all V2 Core contracts. contract DeployCore is BaseScript { diff --git a/script/DeployCore2.s.sol b/script/core/DeployCore2.s.sol similarity index 66% rename from script/DeployCore2.s.sol rename to script/core/DeployCore2.s.sol index eafa8f9a4..8ab6481d4 100644 --- a/script/DeployCore2.s.sol +++ b/script/core/DeployCore2.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; contract DeployCore2 is BaseScript { function run( diff --git a/script/DeployDeterministicCore.s.sol b/script/core/DeployDeterministicCore.s.sol similarity index 74% rename from script/DeployDeterministicCore.s.sol rename to script/core/DeployDeterministicCore.s.sol index 274c5dad7..78dc11f88 100644 --- a/script/DeployDeterministicCore.s.sol +++ b/script/core/DeployDeterministicCore.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all V2 Core contracts at deterministic addresses across chains. /// @dev Reverts if any contract has already been deployed. diff --git a/script/DeployDeterministicCore2.s.sol b/script/core/DeployDeterministicCore2.s.sol similarity index 70% rename from script/DeployDeterministicCore2.s.sol rename to script/core/DeployDeterministicCore2.s.sol index aa995688d..6895dc331 100644 --- a/script/DeployDeterministicCore2.s.sol +++ b/script/core/DeployDeterministicCore2.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore2 is BaseScript { diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/core/DeployDeterministicLockupDynamic.s.sol similarity index 75% rename from script/DeployDeterministicLockupDynamic.s.sol rename to script/core/DeployDeterministicLockupDynamic.s.sol index e27c5012d..2c2c39c7c 100644 --- a/script/DeployDeterministicLockupDynamic.s.sol +++ b/script/core/DeployDeterministicLockupDynamic.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/core/DeployDeterministicLockupLinear.s.sol similarity index 74% rename from script/DeployDeterministicLockupLinear.s.sol rename to script/core/DeployDeterministicLockupLinear.s.sol index dabca6452..abb62d93c 100644 --- a/script/DeployDeterministicLockupLinear.s.sol +++ b/script/core/DeployDeterministicLockupLinear.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. diff --git a/script/DeployDeterministicLockupTranched.s.sol b/script/core/DeployDeterministicLockupTranched.s.sol similarity index 75% rename from script/DeployDeterministicLockupTranched.s.sol rename to script/core/DeployDeterministicLockupTranched.s.sol index c9451f95e..e69c23772 100644 --- a/script/DeployDeterministicLockupTranched.s.sol +++ b/script/core/DeployDeterministicLockupTranched.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. diff --git a/script/DeployDeterministicNFTDescriptor.s.sol b/script/core/DeployDeterministicNFTDescriptor.s.sol similarity index 79% rename from script/DeployDeterministicNFTDescriptor.s.sol rename to script/core/DeployDeterministicNFTDescriptor.s.sol index 9d4a9cf1a..3b28e5f62 100644 --- a/script/DeployDeterministicNFTDescriptor.s.sol +++ b/script/core/DeployDeterministicNFTDescriptor.s.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. diff --git a/script/DeployLockupDynamic.s.sol b/script/core/DeployLockupDynamic.s.sol similarity index 67% rename from script/DeployLockupDynamic.s.sol rename to script/core/DeployLockupDynamic.s.sol index 87ff72b38..28571f9bf 100644 --- a/script/DeployLockupDynamic.s.sol +++ b/script/core/DeployLockupDynamic.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; contract DeployLockupDynamic is BaseScript { function run( diff --git a/script/DeployLockupLinear.s.sol b/script/core/DeployLockupLinear.s.sol similarity index 66% rename from script/DeployLockupLinear.s.sol rename to script/core/DeployLockupLinear.s.sol index 4b2a8fd49..2c49151f6 100644 --- a/script/DeployLockupLinear.s.sol +++ b/script/core/DeployLockupLinear.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; contract DeployLockupLinear is BaseScript { function run( diff --git a/script/DeployLockupTranched.s.sol b/script/core/DeployLockupTranched.s.sol similarity index 67% rename from script/DeployLockupTranched.s.sol rename to script/core/DeployLockupTranched.s.sol index a8d87ce78..75e7e5b15 100644 --- a/script/DeployLockupTranched.s.sol +++ b/script/core/DeployLockupTranched.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; +import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; contract DeployLockupTranched is BaseScript { function run( diff --git a/script/DeployNFTDescriptor.s.sol b/script/core/DeployNFTDescriptor.s.sol similarity index 68% rename from script/DeployNFTDescriptor.s.sol rename to script/core/DeployNFTDescriptor.s.sol index 3bef69c08..a454d49b3 100644 --- a/script/DeployNFTDescriptor.s.sol +++ b/script/core/DeployNFTDescriptor.s.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; contract DeployNFTDescriptor is BaseScript { function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { diff --git a/script/GenerateSVG.s.sol b/script/core/GenerateSVG.s.sol similarity index 87% rename from script/GenerateSVG.s.sol rename to script/core/GenerateSVG.s.sol index f8c2f08ce..9348acf34 100644 --- a/script/GenerateSVG.s.sol +++ b/script/core/GenerateSVG.s.sol @@ -3,11 +3,11 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { NFTSVG } from "../src/core/libraries/NFTSVG.sol"; -import { SVGElements } from "../src/core/libraries/SVGElements.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; +import { NFTSVG } from "../../src/core/libraries/NFTSVG.sol"; +import { SVGElements } from "../../src/core/libraries/SVGElements.sol"; +import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; /// @notice Generates an NFT SVG using the user-provided parameters. contract GenerateSVG is BaseScript, SablierV2NFTDescriptor { diff --git a/script/Init.s.sol b/script/core/Init.s.sol similarity index 92% rename from script/Init.s.sol rename to script/core/Init.s.sol index 1677ea7e9..6a9248317 100644 --- a/script/Init.s.sol +++ b/script/core/Init.s.sol @@ -7,11 +7,11 @@ import { ud60x18 } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2LockupDynamic } from "../src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../src/core/interfaces/ISablierV2LockupLinear.sol"; -import { Broker, LockupDynamic, LockupLinear } from "../src/core/types/DataTypes.sol"; +import { ISablierV2LockupDynamic } from "../../src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { Broker, LockupDynamic, LockupLinear } from "../../src/core/types/DataTypes.sol"; -import { BaseScript } from "./Base.s.sol"; +import { BaseScript } from "../Base.s.sol"; interface IERC20Mint { function mint(address beneficiary, uint256 value) external; diff --git a/script/periphery/CreateMerkleLL.s.sol b/script/periphery/CreateMerkleLL.s.sol new file mode 100644 index 000000000..685fca6f6 --- /dev/null +++ b/script/periphery/CreateMerkleLL.s.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { LockupLinear } from "../../src/core/types/DataTypes.sol"; +import { ISablierV2MerkleLL } from "../../src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { MerkleLockup } from "../../src/periphery/types/DataTypes.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract CreateMerkleLL is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (ISablierV2MerkleLL merkleLL) { + // Prepare the constructor parameters. + ISablierV2MerkleLockupFactory merkleLockupFactory = + ISablierV2MerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); + + MerkleLockup.ConstructorParams memory baseParams; + baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); + baseParams.cancelable = true; + baseParams.expiration = uint40(block.timestamp + 30 days); + baseParams.initialAdmin = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; + baseParams.ipfsCID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; + baseParams.merkleRoot = 0x0000000000000000000000000000000000000000000000000000000000000000; + baseParams.name = "The Boys LL"; + baseParams.transferable = true; + + ISablierV2LockupLinear lockupLinear = ISablierV2LockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); + LockupLinear.Durations memory streamDurations; + streamDurations.cliff = 0; + streamDurations.total = 3600; + uint256 campaignTotalAmount = 10_000e18; + uint256 recipientCount = 100; + + // Deploy MerkleLL contract. + merkleLL = merkleLockupFactory.createMerkleLL( + baseParams, lockupLinear, streamDurations, campaignTotalAmount, recipientCount + ); + } +} diff --git a/script/periphery/CreateMerkleLT.s.sol b/script/periphery/CreateMerkleLT.s.sol new file mode 100644 index 000000000..817723c02 --- /dev/null +++ b/script/periphery/CreateMerkleLT.s.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { UD2x18 } from "@prb/math/src/UD2x18.sol"; + +import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ISablierV2MerkleLT } from "../../src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract CreateMerkleLT is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (ISablierV2MerkleLT merkleLT) { + // Prepare the constructor parameters. + ISablierV2MerkleLockupFactory merkleLockupFactory = + ISablierV2MerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); + + MerkleLockup.ConstructorParams memory baseParams; + baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); + baseParams.cancelable = true; + baseParams.expiration = uint40(block.timestamp + 30 days); + baseParams.initialAdmin = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; + baseParams.ipfsCID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; + baseParams.merkleRoot = 0x0000000000000000000000000000000000000000000000000000000000000000; + baseParams.name = "The Boys LT"; + baseParams.transferable = true; + + ISablierV2LockupTranched lockupTranched = ISablierV2LockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = new MerkleLT.TrancheWithPercentage[](2); + tranchesWithPercentages[0] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: UD2x18.wrap(50), duration: 3600 }); + tranchesWithPercentages[1] = + MerkleLT.TrancheWithPercentage({ unlockPercentage: UD2x18.wrap(50), duration: 7200 }); + uint256 campaignTotalAmount = 10_000e18; + uint256 recipientCount = 100; + + // Deploy MerkleLT contract. + merkleLT = merkleLockupFactory.createMerkleLT( + baseParams, lockupTranched, tranchesWithPercentages, campaignTotalAmount, recipientCount + ); + } +} diff --git a/script/periphery/DeployBatchLockup.t.sol b/script/periphery/DeployBatchLockup.t.sol new file mode 100644 index 000000000..ad6bc831b --- /dev/null +++ b/script/periphery/DeployBatchLockup.t.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract DeployBatchLockup is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (SablierV2BatchLockup batchLockup) { + batchLockup = new SablierV2BatchLockup(); + } +} diff --git a/script/periphery/DeployDeterministicBatchLockup.s.sol b/script/periphery/DeployDeterministicBatchLockup.s.sol new file mode 100644 index 000000000..de3aa68d0 --- /dev/null +++ b/script/periphery/DeployDeterministicBatchLockup.s.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; + +import { BaseScript } from "../Base.s.sol"; + +/// @notice Deploys {SablierV2BatchLockup} at a deterministic address across chains. +/// @dev Reverts if the contract has already been deployed. +contract DeployDeterministicBatchLockup is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (SablierV2BatchLockup batchLockup) { + bytes32 salt = constructCreate2Salt(); + batchLockup = new SablierV2BatchLockup{ salt: salt }(); + } +} diff --git a/script/periphery/DeployDeterministicPeriphery.s.sol b/script/periphery/DeployDeterministicPeriphery.s.sol new file mode 100644 index 000000000..f7db44b84 --- /dev/null +++ b/script/periphery/DeployDeterministicPeriphery.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; +import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; + +import { BaseScript } from "../Base.s.sol"; + +/// @notice Deploys all V2 Periphery contracts at deterministic addresses across chains, in the following order: +/// +/// 1. {SablierV2BatchLockup} +/// 2. {SablierV2MerkleLockupFactory} +/// +/// @dev Reverts if any contract has already been deployed. +contract DeployDeterministicPeriphery is BaseScript { + /// @dev Deploy via Forge. + function run() + public + virtual + broadcast + returns (SablierV2BatchLockup batchLockup, SablierV2MerkleLockupFactory merkleLockupFactory) + { + bytes32 salt = constructCreate2Salt(); + batchLockup = new SablierV2BatchLockup{ salt: salt }(); + merkleLockupFactory = new SablierV2MerkleLockupFactory{ salt: salt }(); + } +} diff --git a/script/periphery/DeployMerkleLockupFactory.s.sol b/script/periphery/DeployMerkleLockupFactory.s.sol new file mode 100644 index 000000000..65b57327a --- /dev/null +++ b/script/periphery/DeployMerkleLockupFactory.s.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract DeployMerkleLockupFactory is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (SablierV2MerkleLockupFactory merkleLockupFactory) { + merkleLockupFactory = new SablierV2MerkleLockupFactory(); + } +} diff --git a/script/periphery/DeployPeriphery.s.sol b/script/periphery/DeployPeriphery.s.sol new file mode 100644 index 000000000..3255b334b --- /dev/null +++ b/script/periphery/DeployPeriphery.s.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; + +import { BaseScript } from "../Base.s.sol"; + +/// @notice Deploys all V2 Periphery contract in the following order: +/// +/// 1. {SablierV2BatchLockup} +/// 2. {SablierV2MerkleLockupFactory} +contract DeployPeriphery is BaseScript { + /// @dev Deploy via Forge. + function run() + public + virtual + broadcast + returns (SablierV2BatchLockup batchLockup, SablierV2MerkleLockupFactory merkleLockupFactory) + { + batchLockup = new SablierV2BatchLockup(); + merkleLockupFactory = new SablierV2MerkleLockupFactory(); + } +} diff --git a/shell/generate-svg.sh b/shell/generate-svg.sh index 7748644d6..56b233038 100755 --- a/shell/generate-svg.sh +++ b/shell/generate-svg.sh @@ -18,7 +18,7 @@ arg_duration=${4:-"91"} # Run the Forge script and extract the SVG from stdout output=$( - forge script script/GenerateSVG.s.sol \ + forge script script/core/GenerateSVG.s.sol \ --sig "run(uint256,string,string,uint256)" \ "$arg_progress" \ "$arg_status" \ From 54614955c0fc4590762076219da141fbc4578fcf Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 25 Jul 2024 18:44:33 +0300 Subject: [PATCH 07/34] ci: include both core and periphery tests in CI ci: use JSON inputs in generate svg workflow ci: lower the fuzz runs to 2000 ci: remove periphery path where not needed chore: fix use of fromJSON Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- .github/workflows/ci-deep.yml | 12 ++++++------ .github/workflows/ci-fork.yml | 2 +- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/generate-svg.yml | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml index cf52cd4a0..daf2e8773 100644 --- a/.github/workflows/ci-deep.yml +++ b/.github/workflows/ci-deep.yml @@ -40,7 +40,7 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: ${{ fromJSON(inputs.unitFuzzRuns) || 50000 }} + foundry-fuzz-runs: ${{ fromJSON(inputs.unitFuzzRuns || '50000') }} foundry-profile: "test-optimized" match-path: "test/unit/**/*.sol" name: "Unit tests" @@ -49,7 +49,7 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: ${{ fromJSON(inputs.integrationFuzzRuns) || 50000 }} + foundry-fuzz-runs: ${{ fromJSON(inputs.integrationFuzzRuns || '50000') }} foundry-profile: "test-optimized" match-path: "test/integration/**/*.sol" name: "Integration tests" @@ -58,8 +58,8 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-invariant-depth: ${{ fromJSON(inputs.invariantDepth) || 100 }} - foundry-invariant-runs: ${{ fromJSON(inputs.invariantRuns) || 100 }} + foundry-invariant-depth: ${{ fromJSON(inputs.invariantDepth || '100') }} + foundry-invariant-runs: ${{ fromJSON(inputs.invariantRuns || '100') }} foundry-profile: "test-optimized" match-path: "test/invariant/**/*.sol" name: "Invariant tests" @@ -70,7 +70,7 @@ jobs: MAINNET_RPC_URL: ${{ secrets.MAINNET_RPC_URL }} uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: ${{ fromJSON(inputs.forkFuzzRuns) || 1000 }} + foundry-fuzz-runs: ${{ fromJSON(inputs.forkFuzzRuns || '1000') }} foundry-profile: "test-optimized" - match-path: "test/fork/**/*.sol" + match-path: "test/{core,periphery}fork/**/*.sol" name: "Fork tests" diff --git a/.github/workflows/ci-fork.yml b/.github/workflows/ci-fork.yml index dbeaf273f..79587228c 100644 --- a/.github/workflows/ci-fork.yml +++ b/.github/workflows/ci-fork.yml @@ -20,7 +20,7 @@ jobs: foundry-fuzz-runs: 100 foundry-profile: "test-optimized" fuzz-seed: true - match-path: "test/fork/**/*.sol" + match-path: "test/{core,periphery}fork/**/*.sol" name: "Fork tests" test-utils: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa6591f02..9e3ffbe11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,18 +24,18 @@ jobs: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: 5000 + foundry-fuzz-runs: 2000 foundry-profile: "test-optimized" - match-path: "test/unit/**/*.sol" + match-path: "test/core/unit/**/*.sol" name: "Unit tests" test-integration: needs: ["lint", "build"] uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: - foundry-fuzz-runs: 5000 + foundry-fuzz-runs: 2000 foundry-profile: "test-optimized" - match-path: "test/integration/**/*.sol" + match-path: "test/{core,periphery}/integration/**/*.sol" name: "Integration tests" test-invariant: @@ -43,7 +43,7 @@ jobs: uses: "sablier-labs/reusable-workflows/.github/workflows/forge-test.yml@main" with: foundry-profile: "test-optimized" - match-path: "test/invariant/**/*.sol" + match-path: "test/core/invariant/**/*.sol" name: "Invariant tests" test-fork: @@ -54,7 +54,7 @@ jobs: with: foundry-fuzz-runs: 20 foundry-profile: "test-optimized" - match-path: "test/fork/**/*.sol" + match-path: "test/{core,periphery}/fork/**/*.sol" name: "Fork tests" coverage: @@ -63,4 +63,4 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} uses: "sablier-labs/reusable-workflows/.github/workflows/forge-coverage.yml@main" with: - match-path: "test/{integration,unit}/**/*.sol" + match-path: "test/{core,periphery}/{integration,unit}/**/*.sol" \ No newline at end of file diff --git a/.github/workflows/generate-svg.yml b/.github/workflows/generate-svg.yml index 6c2f0d0c9..a3d9f4b01 100644 --- a/.github/workflows/generate-svg.yml +++ b/.github/workflows/generate-svg.yml @@ -28,12 +28,12 @@ jobs: - name: "Generate an NFT SVG using the user-provided parameters" run: >- - forge script script/GenerateSVG.s.sol + forge script script/core/GenerateSVG.s.sol --sig "run(uint256,string,string,uint256)" - "${{ inputs.progress }}", - "${{ inputs.status }}" - "${{ inputs.streamed }}" - "${{ inputs.duration }}" + "${{ fromJSON(inputs.progress || true) }}", + "${{ fromJSON(inputs.status || true) }}" + "${{ fromJSON(inputs.streamed || true) }}" + "${{ fromJSON(inputs.duration || true) }}" - name: "Add workflow summary" run: | From 3c6ddaad960605cc58b2960cb6047abae7207334 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Fri, 26 Jul 2024 14:08:26 +0300 Subject: [PATCH 08/34] feat(benchmark): add batch lockup refactor(benchmark): use users.recipient0 refactor(benchmark): dry-fy params return chore(benchmark): run benchmark to update results Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- benchmark/BatchLockup.Gas.t.sol | 259 +++++++++++++++++++ benchmark/Benchmark.t.sol | 18 +- benchmark/LockupDynamic.Gas.t.sol | 41 ++- benchmark/LockupLinear.Gas.t.sol | 4 +- benchmark/LockupTranched.Gas.t.sol | 40 ++- benchmark/results/SablierV2BatchLockup.md | 34 +++ benchmark/results/SablierV2LockupDynamic.md | 32 +-- benchmark/results/SablierV2LockupLinear.md | 14 +- benchmark/results/SablierV2LockupTranched.md | 34 +-- 9 files changed, 375 insertions(+), 101 deletions(-) create mode 100644 benchmark/BatchLockup.Gas.t.sol create mode 100644 benchmark/results/SablierV2BatchLockup.md diff --git a/benchmark/BatchLockup.Gas.t.sol b/benchmark/BatchLockup.Gas.t.sol new file mode 100644 index 000000000..1cf8e5d2e --- /dev/null +++ b/benchmark/BatchLockup.Gas.t.sol @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ud2x18 } from "@prb/math/src/UD2x18.sol"; + +import { LockupDynamic, LockupLinear, LockupTranched } from "../src/core/types/DataTypes.sol"; +import { BatchLockup } from "../src/periphery/types/DataTypes.sol"; +import { BatchLockupBuilder } from "../test/utils/BatchLockupBuilder.sol"; + +import { Benchmark_Test } from "./Benchmark.t.sol"; + +/// @notice Tests used to benchmark {BatchLockup}. +/// @dev This contract creates a Markdown file with the gas usage of each function. +contract BatchLockup_Gas_Test is Benchmark_Test { + /*////////////////////////////////////////////////////////////////////////// + STATE VARIABLES + //////////////////////////////////////////////////////////////////////////*/ + + uint128 internal constant AMOUNT_PER_ITEM = 10e18; + uint8[5] internal batches = [5, 10, 20, 30, 50]; + uint8[5] internal counts = [24, 24, 24, 24, 12]; + + /*////////////////////////////////////////////////////////////////////////// + TEST FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + + function testGas_Implementations() external { + // Set the file path. + benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2BatchLockup.md"); + + // Create the file if it doesn't exist, otherwise overwrite it. + vm.writeFile({ + path: benchmarkResultsFile, + data: string.concat( + "# Benchmarks for BatchLockup\n\n", + "| Function | Lockup Type | Segments/Tranches | Batch Size | Gas Usage |\n", + "| --- | --- | --- | --- | --- |\n" + ) + }); + + for (uint256 i; i < batches.length; ++i) { + // Benchmark the batch create functions for Lockup Linear. + gasCreateWithDurationsLL(batches[i]); + gasCreateWithTimestampsLL(batches[i]); + + // Benchmark the batch create functions for Lockup Dynamic. + gasCreateWithDurationsLD({ batchSize: batches[i], segmentsCount: counts[i] }); + gasCreateWithTimestampsLD({ batchSize: batches[i], segmentsCount: counts[i] }); + + // Benchmark the batch create functions for Lockup Tranched. + gasCreateWithDurationsLT({ batchSize: batches[i], tranchesCount: counts[i] }); + gasCreateWithTimestampsLT({ batchSize: batches[i], tranchesCount: counts[i] }); + } + } + + /*////////////////////////////////////////////////////////////////////////// + GAS BENCHMARKS FOR BATCH FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function gasCreateWithDurationsLD(uint256 batchSize, uint256 segmentsCount) internal { + LockupDynamic.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNullLD(); + createParams.totalAmount = uint128(AMOUNT_PER_ITEM * segmentsCount); + createParams.segments = _generateSegmentsWithDuration(segmentsCount); + BatchLockup.CreateWithDurationsLD[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + + uint256 initialGas = gasleft(); + batchLockup.createWithDurationsLD(lockupDynamic, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurationsLD` | Lockup Dynamic |", + vm.toString(segmentsCount), + " |", + vm.toString(batchSize), + " | ", + gasUsed, + " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithTimestampsLD(uint256 batchSize, uint256 segmentsCount) internal { + LockupDynamic.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNullLD(); + createParams.startTime = getBlockTimestamp(); + createParams.totalAmount = uint128(AMOUNT_PER_ITEM * segmentsCount); + createParams.segments = _generateSegments(segmentsCount); + BatchLockup.CreateWithTimestampsLD[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + + uint256 initialGas = gasleft(); + batchLockup.createWithTimestampsLD(lockupDynamic, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestampsLD` | Lockup Dynamic |", + vm.toString(segmentsCount), + " |", + vm.toString(batchSize), + " | ", + gasUsed, + " |" + ); + + // Append the data to the file + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithDurationsLL(uint256 batchSize) internal { + BatchLockup.CreateWithDurationsLL[] memory params = + BatchLockupBuilder.fillBatch({ params: defaults.createWithDurationsBrokerNullLL(), batchSize: batchSize }); + + uint256 initialGas = gasleft(); + batchLockup.createWithDurationsLL(lockupLinear, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurationsLL` | Lockup Linear | N/A |", vm.toString(batchSize), " | ", gasUsed, " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithTimestampsLL(uint256 batchSize) internal { + BatchLockup.CreateWithTimestampsLL[] memory params = + BatchLockupBuilder.fillBatch({ params: defaults.createWithTimestampsBrokerNullLL(), batchSize: batchSize }); + + uint256 initialGas = gasleft(); + batchLockup.createWithTimestampsLL(lockupLinear, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestampsLL` | Lockup Linear | N/A |", vm.toString(batchSize), " | ", gasUsed, " |" + ); + + // Append the data to the file + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithDurationsLT(uint256 batchSize, uint256 tranchesCount) internal { + LockupTranched.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNullLT(); + createParams.totalAmount = uint128(AMOUNT_PER_ITEM * tranchesCount); + createParams.tranches = _generateTranchesWithDuration(tranchesCount); + BatchLockup.CreateWithDurationsLT[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + + uint256 initialGas = gasleft(); + batchLockup.createWithDurationsLT(lockupTranched, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithDurationsLT` | Lockup Tranched |", + vm.toString(tranchesCount), + " |", + vm.toString(batchSize), + " | ", + gasUsed, + " |" + ); + + // Append the content to the file. + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + function gasCreateWithTimestampsLT(uint256 batchSize, uint256 tranchesCount) internal { + LockupTranched.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNullLT(); + createParams.startTime = getBlockTimestamp(); + createParams.totalAmount = uint128(AMOUNT_PER_ITEM * tranchesCount); + createParams.tranches = _generateTranches(tranchesCount); + BatchLockup.CreateWithTimestampsLT[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + + uint256 initialGas = gasleft(); + batchLockup.createWithTimestampsLT(lockupTranched, dai, params); + string memory gasUsed = vm.toString(initialGas - gasleft()); + + contentToAppend = string.concat( + "| `createWithTimestampsLT` | Lockup Tranched |", + vm.toString(tranchesCount), + " |", + vm.toString(batchSize), + " | ", + gasUsed, + " |" + ); + + // Append the data to the file + _appendToFile(benchmarkResultsFile, contentToAppend); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function _generateSegments(uint256 segmentsCount) private view returns (LockupDynamic.Segment[] memory) { + LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentsCount); + + // Populate segments. + for (uint256 i = 0; i < segmentsCount; ++i) { + segments[i] = LockupDynamic.Segment({ + amount: AMOUNT_PER_ITEM, + exponent: ud2x18(0.5e18), + timestamp: getBlockTimestamp() + uint40(defaults.CLIFF_DURATION() * (1 + i)) + }); + } + + return segments; + } + + function _generateSegmentsWithDuration(uint256 segmentsCount) + private + view + returns (LockupDynamic.SegmentWithDuration[] memory) + { + LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](segmentsCount); + + // Populate segments. + for (uint256 i; i < segmentsCount; ++i) { + segments[i] = LockupDynamic.SegmentWithDuration({ + amount: AMOUNT_PER_ITEM, + exponent: ud2x18(0.5e18), + duration: defaults.CLIFF_DURATION() + }); + } + + return segments; + } + + function _generateTranches(uint256 tranchesCount) private view returns (LockupTranched.Tranche[] memory) { + LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](tranchesCount); + + // Populate tranches. + for (uint256 i = 0; i < tranchesCount; ++i) { + tranches[i] = ( + LockupTranched.Tranche({ + amount: AMOUNT_PER_ITEM, + timestamp: getBlockTimestamp() + uint40(defaults.CLIFF_DURATION() * (1 + i)) + }) + ); + } + + return tranches; + } + + function _generateTranchesWithDuration(uint256 tranchesCount) + private + view + returns (LockupTranched.TrancheWithDuration[] memory) + { + LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](tranchesCount); + + // Populate tranches. + for (uint256 i; i < tranchesCount; ++i) { + tranches[i] = + LockupTranched.TrancheWithDuration({ amount: AMOUNT_PER_ITEM, duration: defaults.CLIFF_DURATION() }); + } + + return tranches; + } +} diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol index 78856032f..b2aaa3afe 100644 --- a/benchmark/Benchmark.t.sol +++ b/benchmark/Benchmark.t.sol @@ -2,8 +2,8 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2Lockup } from "../src/interfaces/ISablierV2Lockup.sol"; +import { ISablierV2Lockup } from "../src/core/interfaces/ISablierV2Lockup.sol"; import { Base_Test } from "../test/Base.t.sol"; /// @notice Benchmark contract with common logic needed by all tests. @@ -32,7 +32,7 @@ abstract contract Benchmark_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public virtual override { - super.setUp(); + Base_Test.setUp(); deal({ token: address(dai), to: users.sender, give: type(uint256).max }); resetPrank({ msgSender: users.sender }); @@ -47,11 +47,11 @@ abstract contract Benchmark_Test is Base_Test { function gasBurn() internal { // Set the caller to the Recipient for `burn` and change timestamp to the end time. - resetPrank({ msgSender: users.recipient }); + resetPrank({ msgSender: users.recipient0 }); vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax(streamIds[0], users.recipient); + lockup.withdrawMax(streamIds[0], users.recipient0); uint256 initialGas = gasleft(); lockup.burn(streamIds[0]); @@ -101,7 +101,7 @@ abstract contract Benchmark_Test is Base_Test { string memory gasUsed = vm.toString(initialGas - gasleft()); // Check if caller is recipient or not. - bool isCallerRecipient = caller == users.recipient; + bool isCallerRecipient = caller == users.recipient0; string memory s = isCallerRecipient ? string.concat("| `withdraw` ", extraInfo, " (by Recipient) | ") @@ -138,13 +138,13 @@ abstract contract Benchmark_Test is Base_Test { } function gasWithdraw_ByAnyone(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { - gasWithdraw_AfterEndTime(streamId1, users.sender, users.recipient, extraInfo); - gasWithdraw_BeforeEndTime(streamId2, users.sender, users.recipient, extraInfo); + gasWithdraw_AfterEndTime(streamId1, users.sender, users.recipient0, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.sender, users.recipient0, extraInfo); } function gasWithdraw_ByRecipient(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { - gasWithdraw_AfterEndTime(streamId1, users.recipient, users.alice, extraInfo); - gasWithdraw_BeforeEndTime(streamId2, users.recipient, users.alice, extraInfo); + gasWithdraw_AfterEndTime(streamId1, users.recipient0, users.alice, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.recipient0, users.alice, extraInfo); } /*////////////////////////////////////////////////////////////////////////// diff --git a/benchmark/LockupDynamic.Gas.t.sol b/benchmark/LockupDynamic.Gas.t.sol index afac9403d..a1945265c 100644 --- a/benchmark/LockupDynamic.Gas.t.sol +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -4,7 +4,8 @@ pragma solidity >=0.8.22; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic } from "../src/types/DataTypes.sol"; +import { Broker, LockupDynamic } from "../src/core/types/DataTypes.sol"; + import { Benchmark_Test } from "./Benchmark.t.sol"; /// @notice Tests used to benchmark LockupDynamic. @@ -21,7 +22,7 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { SET-UP FUNCTION //////////////////////////////////////////////////////////////////////////*/ function setUp() public override { - super.setUp(); + Benchmark_Test.setUp(); lockup = lockupDynamic; } @@ -170,7 +171,7 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { ) private view - returns (LockupDynamic.CreateWithDurations memory) + returns (LockupDynamic.CreateWithDurations memory params) { LockupDynamic.SegmentWithDuration[] memory segments_ = new LockupDynamic.SegmentWithDuration[](totalSegments); @@ -187,16 +188,11 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; - return LockupDynamic.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: _calculateTotalAmount(depositAmount, brokerFee), - asset: dai, - cancelable: true, - transferable: true, - segments: segments_, - broker: Broker({ account: users.broker, fee: brokerFee }) - }); + params = defaults.createWithDurationsLD(); + params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); + params.segments = segments_; + params.broker.fee = brokerFee; + return params; } function _createWithTimestampParams( @@ -205,7 +201,7 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { ) private view - returns (LockupDynamic.CreateWithTimestamps memory) + returns (LockupDynamic.CreateWithTimestamps memory params) { LockupDynamic.Segment[] memory segments_ = new LockupDynamic.Segment[](totalSegments); @@ -222,16 +218,11 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; - return LockupDynamic.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: _calculateTotalAmount(depositAmount, brokerFee), - asset: dai, - cancelable: true, - transferable: true, - startTime: getBlockTimestamp(), - segments: segments_, - broker: Broker({ account: users.broker, fee: brokerFee }) - }); + params = defaults.createWithTimestampsLD(); + params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); + params.segments = segments_; + params.startTime = getBlockTimestamp(); + params.broker.fee = brokerFee; + return params; } } diff --git a/benchmark/LockupLinear.Gas.t.sol b/benchmark/LockupLinear.Gas.t.sol index f4d35e961..617d97f7c 100644 --- a/benchmark/LockupLinear.Gas.t.sol +++ b/benchmark/LockupLinear.Gas.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { ud } from "@prb/math/src/UD60x18.sol"; -import { LockupLinear } from "../src/types/DataTypes.sol"; +import { LockupLinear } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; @@ -15,7 +15,7 @@ contract LockupLinear_Gas_Test is Benchmark_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public override { - super.setUp(); + Benchmark_Test.setUp(); lockup = lockupLinear; } diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol index 591e80c89..bdb6cdd7f 100644 --- a/benchmark/LockupTranched.Gas.t.sol +++ b/benchmark/LockupTranched.Gas.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "../src/types/DataTypes.sol"; +import { Broker, LockupTranched } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; @@ -22,7 +22,7 @@ contract LockupTranched_Gas_Test is Benchmark_Test { //////////////////////////////////////////////////////////////////////////*/ function setUp() public override { - super.setUp(); + Benchmark_Test.setUp(); lockup = lockupTranched; } @@ -167,7 +167,7 @@ contract LockupTranched_Gas_Test is Benchmark_Test { ) private view - returns (LockupTranched.CreateWithDurations memory) + returns (LockupTranched.CreateWithDurations memory params) { LockupTranched.TrancheWithDuration[] memory tranches_ = new LockupTranched.TrancheWithDuration[](totalTranches); @@ -180,16 +180,11 @@ contract LockupTranched_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; - return LockupTranched.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: _calculateTotalAmount(depositAmount, brokerFee), - asset: dai, - cancelable: true, - transferable: true, - tranches: tranches_, - broker: Broker({ account: users.broker, fee: brokerFee }) - }); + params = defaults.createWithDurationsLT(); + params.broker.fee = brokerFee; + params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); + params.tranches = tranches_; + return params; } function _createWithTimestampParams( @@ -198,7 +193,7 @@ contract LockupTranched_Gas_Test is Benchmark_Test { ) private view - returns (LockupTranched.CreateWithTimestamps memory) + returns (LockupTranched.CreateWithTimestamps memory params) { LockupTranched.Tranche[] memory tranches_ = new LockupTranched.Tranche[](totalTranches); @@ -214,16 +209,11 @@ contract LockupTranched_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; - return LockupTranched.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: _calculateTotalAmount(depositAmount, brokerFee), - asset: dai, - cancelable: true, - transferable: true, - startTime: getBlockTimestamp(), - tranches: tranches_, - broker: Broker({ account: users.broker, fee: brokerFee }) - }); + params = defaults.createWithTimestampsLT(); + params.broker.fee = brokerFee; + params.startTime = getBlockTimestamp(); + params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); + params.tranches = tranches_; + return params; } } diff --git a/benchmark/results/SablierV2BatchLockup.md b/benchmark/results/SablierV2BatchLockup.md new file mode 100644 index 000000000..112175f33 --- /dev/null +++ b/benchmark/results/SablierV2BatchLockup.md @@ -0,0 +1,34 @@ +# Benchmarks for BatchLockup + +| Function | Lockup Type | Segments/Tranches | Batch Size | Gas Usage | +| ------------------------ | --------------- | ----------------- | ---------- | --------- | +| `createWithDurationsLL` | Lockup Linear | N/A | 5 | 770796 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 5 | 730532 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 5 | 3935335 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 5 | 3797841 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 5 | 3844973 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 5 | 3726799 | +| `createWithDurationsLL` | Lockup Linear | N/A | 10 | 1413200 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 10 | 1410133 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 10 | 7785667 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 10 | 7547946 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 10 | 7596904 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 10 | 7406060 | +| `createWithDurationsLL` | Lockup Linear | N/A | 20 | 2775981 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 20 | 2771033 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 20 | 15547587 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 20 | 15056228 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 20 | 15143062 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 20 | 14770870 | +| `createWithDurationsLL` | Lockup Linear | N/A | 30 | 4133268 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 30 | 4136198 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 30 | 23351853 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 30 | 22583299 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 30 | 22691758 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 30 | 22152793 | +| `createWithDurationsLL` | Lockup Linear | N/A | 50 | 6854756 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 50 | 6872537 | +| `createWithDurationsLD` | Lockup Dynamic | 12 | 50 | 22883512 | +| `createWithTimestampsLD` | Lockup Dynamic | 12 | 50 | 22241640 | +| `createWithDurationsLT` | Lockup Tranched | 12 | 50 | 22314003 | +| `createWithTimestampsLT` | Lockup Tranched | 12 | 50 | 21891398 | diff --git a/benchmark/results/SablierV2LockupDynamic.md b/benchmark/results/SablierV2LockupDynamic.md index de8e2145b..7ca0a2fcd 100644 --- a/benchmark/results/SablierV2LockupDynamic.md +++ b/benchmark/results/SablierV2LockupDynamic.md @@ -4,27 +4,27 @@ | ---------------------------------------------------------- | --------- | | `burn` | 15716 | | `cancel` | 74341 | -| `renounce` | 39007 | -| `createWithDurations` (2 segments) (Broker fee set) | 200602 | -| `createWithDurations` (2 segments) (Broker fee not set) | 185037 | -| `createWithTimestamps` (2 segments) (Broker fee set) | 184780 | -| `createWithTimestamps` (2 segments) (Broker fee not set) | 180015 | -| `withdraw` (2 segments) (After End Time) (by Recipient) | 19108 | +| `renounce` | 39001 | +| `createWithDurations` (2 segments) (Broker fee set) | 200605 | +| `createWithDurations` (2 segments) (Broker fee not set) | 185039 | +| `createWithTimestamps` (2 segments) (Broker fee set) | 184785 | +| `createWithTimestamps` (2 segments) (Broker fee not set) | 180023 | +| `withdraw` (2 segments) (After End Time) (by Recipient) | 19109 | | `withdraw` (2 segments) (Before End Time) (by Recipient) | 27554 | -| `withdraw` (2 segments) (After End Time) (by Anyone) | 14239 | +| `withdraw` (2 segments) (After End Time) (by Anyone) | 14241 | | `withdraw` (2 segments) (Before End Time) (by Anyone) | 27485 | -| `createWithDurations` (10 segments) (Broker fee set) | 395084 | -| `createWithDurations` (10 segments) (Broker fee not set) | 390326 | -| `createWithTimestamps` (10 segments) (Broker fee set) | 385125 | -| `createWithTimestamps` (10 segments) (Broker fee not set) | 380375 | +| `createWithDurations` (10 segments) (Broker fee set) | 395105 | +| `createWithDurations` (10 segments) (Broker fee not set) | 390350 | +| `createWithTimestamps` (10 segments) (Broker fee set) | 385155 | +| `createWithTimestamps` (10 segments) (Broker fee not set) | 380410 | | `withdraw` (10 segments) (After End Time) (by Recipient) | 14295 | | `withdraw` (10 segments) (Before End Time) (by Recipient) | 32545 | -| `withdraw` (10 segments) (After End Time) (by Anyone) | 14246 | +| `withdraw` (10 segments) (After End Time) (by Anyone) | 14249 | | `withdraw` (10 segments) (Before End Time) (by Anyone) | 32476 | -| `createWithDurations` (100 segments) (Broker fee set) | 2740781 | -| `createWithDurations` (100 segments) (Broker fee not set) | 2736987 | -| `createWithTimestamps` (100 segments) (Broker fee set) | 2642946 | -| `createWithTimestamps` (100 segments) (Broker fee not set) | 2639185 | +| `createWithDurations` (100 segments) (Broker fee set) | 2741072 | +| `createWithDurations` (100 segments) (Broker fee not set) | 2737309 | +| `createWithTimestamps` (100 segments) (Broker fee set) | 2643302 | +| `createWithTimestamps` (100 segments) (Broker fee not set) | 2639574 | | `withdraw` (100 segments) (After End Time) (by Recipient) | 14295 | | `withdraw` (100 segments) (Before End Time) (by Recipient) | 88968 | | `withdraw` (100 segments) (After End Time) (by Anyone) | 14226 | diff --git a/benchmark/results/SablierV2LockupLinear.md b/benchmark/results/SablierV2LockupLinear.md index d53fa08f9..32085722d 100644 --- a/benchmark/results/SablierV2LockupLinear.md +++ b/benchmark/results/SablierV2LockupLinear.md @@ -3,17 +3,17 @@ | Implementation | Gas Usage | | ----------------------------------------------------------- | --------- | | `burn` | 15694 | -| `cancel` | 56829 | -| `renounce` | 19381 | +| `cancel` | 56832 | +| `renounce` | 19378 | | `createWithDurations` (Broker fee set) (cliff not set) | 129276 | | `createWithDurations` (Broker fee not set) (cliff not set) | 113680 | | `createWithDurations` (Broker fee set) (cliff set) | 138071 | -| `createWithDurations` (Broker fee not set) (cliff set) | 133273 | +| `createWithDurations` (Broker fee not set) (cliff set) | 133274 | | `createWithTimestamps` (Broker fee set) (cliff not set) | 115334 | | `createWithTimestamps` (Broker fee not set) (cliff not set) | 110530 | | `createWithTimestamps` (Broker fee set) (cliff set) | 137629 | | `createWithTimestamps` (Broker fee not set) (cliff set) | 132827 | -| `withdraw` (After End Time) (by Recipient) | 29701 | -| `withdraw` (Before End Time) (by Recipient) | 19104 | -| `withdraw` (After End Time) (by Anyone) | 24799 | -| `withdraw` (Before End Time) (by Anyone) | 19002 | +| `withdraw` (After End Time) (by Recipient) | 29704 | +| `withdraw` (Before End Time) (by Recipient) | 19107 | +| `withdraw` (After End Time) (by Anyone) | 24802 | +| `withdraw` (Before End Time) (by Anyone) | 19005 | diff --git a/benchmark/results/SablierV2LockupTranched.md b/benchmark/results/SablierV2LockupTranched.md index ec7ea9494..edb9330a8 100644 --- a/benchmark/results/SablierV2LockupTranched.md +++ b/benchmark/results/SablierV2LockupTranched.md @@ -4,27 +4,27 @@ | ---------------------------------------------------------- | --------- | | `burn` | 15738 | | `cancel` | 63994 | -| `renounce` | 26501 | -| `createWithDurations` (2 tranches) (Broker fee set) | 199536 | -| `createWithDurations` (2 tranches) (Broker fee not set) | 183969 | -| `createWithTimestamps` (2 tranches) (Broker fee set) | 189410 | -| `createWithTimestamps` (2 tranches) (Broker fee not set) | 183945 | -| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20100 | +| `renounce` | 26495 | +| `createWithDurations` (2 tranches) (Broker fee set) | 199538 | +| `createWithDurations` (2 tranches) (Broker fee not set) | 183973 | +| `createWithTimestamps` (2 tranches) (Broker fee set) | 195734 | +| `createWithTimestamps` (2 tranches) (Broker fee not set) | 190260 | +| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20102 | | `withdraw` (2 tranches) (Before End Time) (by Recipient) | 14797 | -| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15199 | +| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15201 | | `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14695 | -| `createWithDurations` (10 tranches) (Broker fee set) | 388757 | -| `createWithDurations` (10 tranches) (Broker fee not set) | 383998 | -| `createWithTimestamps` (10 tranches) (Broker fee set) | 397102 | -| `createWithTimestamps` (10 tranches) (Broker fee not set) | 391750 | -| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17855 | +| `createWithDurations` (10 tranches) (Broker fee set) | 388774 | +| `createWithDurations` (10 tranches) (Broker fee not set) | 384017 | +| `createWithTimestamps` (10 tranches) (Broker fee set) | 403722 | +| `createWithTimestamps` (10 tranches) (Broker fee not set) | 398385 | +| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17857 | | `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19616 | -| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17760 | +| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17763 | | `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19514 | -| `createWithDurations` (100 tranches) (Broker fee set) | 2672918 | -| `createWithDurations` (100 tranches) (Broker fee not set) | 2668643 | -| `createWithTimestamps` (100 tranches) (Broker fee set) | 2738297 | -| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2734635 | +| `createWithDurations` (100 tranches) (Broker fee set) | 2673124 | +| `createWithDurations` (100 tranches) (Broker fee not set) | 2668870 | +| `createWithTimestamps` (100 tranches) (Broker fee set) | 2747871 | +| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2744348 | | `withdraw` (100 tranches) (After End Time) (by Recipient) | 46746 | | `withdraw` (100 tranches) (Before End Time) (by Recipient) | 73989 | | `withdraw` (100 tranches) (After End Time) (by Anyone) | 46644 | From 858912b769cdc8327cd0511e0c9264237d98c30e Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:49:50 +0300 Subject: [PATCH 09/34] build(shell): include periphery in artifacts (#990) build(shell): use deploy protocol deployment script Co-authored-by: PaulRBerg Co-authored-by: smol-ninja --- shell/deploy-multi-chain.sh | 10 ++++- shell/prepare-artifacts.sh | 81 +++++++++++++++++++++++++------------ 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 973844e13..a0414ff07 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -288,7 +288,7 @@ for chain in "${provided_chains[@]}"; do if [[ ${DETERMINISTIC_DEPLOYMENT} == true ]]; then echo -e "${SC}+${NC} Deterministic address" if [[ ${sol_script} == "" ]]; then - deployment_command+=("script" "script/DeployDeterministicCore.s.sol") + deployment_command+=("script" "script/DeployDeterministicProtocol.s.sol") else deployment_command+=("script" "${sol_script}") fi @@ -307,7 +307,7 @@ for chain in "${provided_chains[@]}"; do else # Construct the command if [[ ${sol_script} == "" ]]; then - deployment_command+=("script" "script/DeployCore.s.sol") + deployment_command+=("script" "script/DeployProtocol.s.sol") else deployment_command+=("script" "${sol_script}") fi @@ -356,17 +356,23 @@ for chain in "${provided_chains[@]}"; do touch "${chain_file}" # Extract and save contract addresses + batchLockup_address=$(echo "${output}" | awk '/batchLockup: contract/{print $NF}') lockupDynamic_address=$(echo "${output}" | awk '/lockupDynamic: contract/{print $NF}') lockupLinear_address=$(echo "${output}" | awk '/lockupLinear: contract/{print $NF}') lockupTranched_address=$(echo "${output}" | awk '/lockupTranched: contract/{print $NF}') + merkleLockupFactory_address=$(echo "${output}" | awk '/merkleLockupFactory: contract/{print $NF}') nftDescriptor_address=$(echo "${output}" | awk '/nftDescriptor: contract/{print $NF}') # Save to the chain file { + echo "Core Contracts" echo "SablierV2LockupDynamic = ${lockupDynamic_address}" echo "SablierV2LockupLinear = ${lockupLinear_address}" echo "SablierV2LockupTranched = ${lockupTranched_address}" echo "SablierV2NFTDescriptor = ${nftDescriptor_address}" + echo "Periphery Contracts" + echo "SablierV2BatchLockup = ${batchLockup_address}" + echo "SablierV2MerkleLockupFactory = ${merkleLockupFactory_address}" } >> "$chain_file" echo -e "${SC}${TICK} Deployed on ${chain}. You can find the addresses in ${chain_file}${NC}" diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index 5aa4f6ab5..e696f46db 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -7,43 +7,74 @@ # Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca set -euo pipefail +# Generate the artifacts with Forge +FOUNDRY_PROFILE=optimized forge build + # Delete the current artifacts artifacts=./artifacts rm -rf $artifacts # Create the new artifacts directories mkdir $artifacts \ - "$artifacts/interfaces" \ - "$artifacts/interfaces/erc20" \ - "$artifacts/interfaces/erc721" \ - "$artifacts/libraries" + "$artifacts/core" \ + "$artifacts/core/interfaces" \ + "$artifacts/core/libraries" \ + "$artifacts/erc20" \ + "$artifacts/erc721" \ + "$artifacts/periphery" \ + "$artifacts/periphery/interfaces" \ + "$artifacts/periphery/libraries" -# Generate the artifacts with Forge -FOUNDRY_PROFILE=optimized forge build +################################################ +#### CORE #### +################################################ + +core=./artifacts/core +cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $core +cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $core +cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $core +cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $core + +core_interfaces=./artifacts/core/interfaces +cp out-optimized/ISablierLockupRecipient.sol/ISablierLockupRecipient.json $core_interfaces +cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $core_interfaces +cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $core_interfaces +cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $core_interfaces +cp out-optimized/ISablierV2LockupTranched.sol/ISablierV2LockupTranched.json $core_interfaces +cp out-optimized/ISablierV2NFTDescriptor.sol/ISablierV2NFTDescriptor.json $core_interfaces -# Copy the production artifacts -cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $artifacts -cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $artifacts -cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $artifacts -cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $artifacts - -interfaces=./artifacts/interfaces -cp out-optimized/ISablierLockupRecipient.sol/ISablierLockupRecipient.json $interfaces -cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $interfaces -cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $interfaces -cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $interfaces -cp out-optimized/ISablierV2LockupTranched.sol/ISablierV2LockupTranched.json $interfaces -cp out-optimized/ISablierV2NFTDescriptor.sol/ISablierV2NFTDescriptor.json $interfaces - -erc20=./artifacts/interfaces/erc20 +core_libraries=./artifacts/core/libraries +cp out-optimized/Errors.sol/Errors.json $core_libraries + +################################################ +#### PERIPHERY #### +################################################ + +periphery=./artifacts/periphery +cp out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json $periphery +cp out-optimized/SablierV2MerkleLL.sol/SablierV2MerkleLL.json $periphery +cp out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json $periphery +cp out-optimized/SablierV2MerkleLT.sol/SablierV2MerkleLT.json $periphery + +periphery_interfaces=./artifacts/periphery/interfaces +cp out-optimized/ISablierV2BatchLockup.sol/ISablierV2BatchLockup.json $periphery_interfaces +cp out-optimized/ISablierV2MerkleLL.sol/ISablierV2MerkleLL.json $periphery_interfaces +cp out-optimized/ISablierV2MerkleLockupFactory.sol/ISablierV2MerkleLockupFactory.json $periphery_interfaces +cp out-optimized/ISablierV2MerkleLT.sol/ISablierV2MerkleLT.json $periphery_interfaces + +periphery_libraries=./artifacts/periphery/libraries +cp out-optimized/libraries/Errors.sol/Errors.json $periphery_libraries + +################################################ +#### OTHERS #### +################################################ + +erc20=./artifacts/erc20 cp out-optimized/IERC20.sol/IERC20.json $erc20 -erc721=./artifacts/interfaces/erc721 +erc721=./artifacts/erc721 cp out-optimized/IERC721.sol/IERC721.json $erc721 cp out-optimized/IERC721Metadata.sol/IERC721Metadata.json $erc721 -libraries=./artifacts/libraries -cp out-optimized/Errors.sol/Errors.json $libraries - # Format the artifacts with Prettier bun prettier --write ./artifacts From a97e5ae278e82a91533d42ae4df2cd3f95c14f81 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 29 Jul 2024 22:25:25 +0100 Subject: [PATCH 10/34] test: move generic functions to Base test contract test: rename recipient0 to recipient test: refactor variables in Defaults test(fork): allow leadData to have length 1 Co-authored-by: PaulRBerg Co-authored-by: andreivladbrg --- benchmark/Benchmark.t.sol | 17 ++- codecov.yml | 4 +- foundry.toml | 4 + precompiles/Precompiles.sol | 1 - shell/deploy-multi-chain.sh | 4 +- test/Base.t.sol | 137 ++++++++++++++++- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 4 +- .../withdrawableAmountOf.t.sol | 2 +- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 6 +- .../withdrawableAmountOf.t.sol | 2 +- .../createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 4 +- .../withdrawableAmountOf.t.sol | 2 +- .../concrete/lockup/burn/burn.t.sol | 6 +- .../cancel-multiple/cancelMultiple.t.sol | 14 +- .../concrete/lockup/cancel/cancel.t.sol | 6 +- .../lockup/get-recipient/getRecipient.t.sol | 6 +- .../getRefundedAmount.t.sol | 4 +- .../getWithdrawnAmount.t.sol | 2 +- .../concrete/lockup/is-cold/isCold.t.sol | 2 +- .../lockup/is-depleted/isDepleted.t.sol | 2 +- .../concrete/lockup/is-warm/isWarm.t.sol | 2 +- .../refundableAmountOf.t.sol | 4 +- .../concrete/lockup/renounce/renounce.t.sol | 2 +- .../concrete/lockup/status-of/statusOf.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 4 +- .../lockup/transfer-from/transferFrom.t.sol | 8 +- .../withdrawMaxAndTransfer.t.sol | 16 +- .../lockup/withdraw-max/withdrawMax.t.sol | 14 +- .../withdraw-multiple/withdrawMultiple.t.sol | 22 +-- .../concrete/lockup/withdraw/withdraw.t.sol | 32 ++-- .../withdrawableAmountOf.t.sol | 4 +- .../lockup-dynamic/createWithDurations.t.sol | 6 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 2 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 2 +- .../lockup-linear/createWithDurations.t.sol | 4 +- .../lockup-linear/withdrawableAmountOf.t.sol | 2 +- .../lockup-tranched/createWithDurations.t.sol | 4 +- .../fuzz/lockup-tranched/withdraw.t.sol | 2 +- .../withdrawableAmountOf.t.sol | 2 +- .../fuzz/lockup/cancelMultiple.t.sol | 6 +- .../fuzz/lockup/getWithdrawnAmount.t.sol | 2 +- .../integration/fuzz/lockup/withdraw.t.sol | 10 +- .../integration/fuzz/lockup/withdrawMax.t.sol | 14 +- .../fuzz/lockup/withdrawMaxAndTransfer.t.sol | 6 +- .../fuzz/lockup/withdrawMultiple.t.sol | 12 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 4 +- .../lockup-tranched/LockupTranched.t.sol | 4 +- .../shared/lockup/getWithdrawnAmount.t.sol | 2 +- .../integration/shared/lockup/withdraw.t.sol | 2 +- .../shared/lockup/withdrawMax.t.sol | 2 +- .../lockup/withdrawMaxAndTransfer.t.sol | 2 +- .../shared/lockup/withdrawMultiple.t.sol | 6 +- test/periphery/Periphery.t.sol | 144 +----------------- test/periphery/fork/Fork.t.sol | 2 +- .../fork/merkle-lockup/MerkleLL.t.sol | 2 +- .../fork/merkle-lockup/MerkleLT.t.sol | 2 +- test/utils/Constants.sol | 2 +- test/utils/Defaults.sol | 30 ++-- test/utils/Types.sol | 7 +- 62 files changed, 314 insertions(+), 322 deletions(-) diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol index b2aaa3afe..7e8792532 100644 --- a/benchmark/Benchmark.t.sol +++ b/benchmark/Benchmark.t.sol @@ -14,7 +14,6 @@ abstract contract Benchmark_Test is Base_Test { uint128 internal immutable AMOUNT_PER_SEGMENT = 100e18; uint128 internal immutable AMOUNT_PER_TRANCHE = 100e18; - uint256[7] internal streamIds = [50, 51, 52, 53, 54, 55, 56]; /// @dev The directory where the benchmark files are stored. string internal benchmarkResults = "benchmark/results/"; @@ -27,6 +26,8 @@ abstract contract Benchmark_Test is Base_Test { ISablierV2Lockup internal lockup; + uint256[7] internal streamIds = [50, 51, 52, 53, 54, 55, 56]; + /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION //////////////////////////////////////////////////////////////////////////*/ @@ -47,11 +48,11 @@ abstract contract Benchmark_Test is Base_Test { function gasBurn() internal { // Set the caller to the Recipient for `burn` and change timestamp to the end time. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax(streamIds[0], users.recipient0); + lockup.withdrawMax(streamIds[0], users.recipient); uint256 initialGas = gasleft(); lockup.burn(streamIds[0]); @@ -101,7 +102,7 @@ abstract contract Benchmark_Test is Base_Test { string memory gasUsed = vm.toString(initialGas - gasleft()); // Check if caller is recipient or not. - bool isCallerRecipient = caller == users.recipient0; + bool isCallerRecipient = caller == users.recipient; string memory s = isCallerRecipient ? string.concat("| `withdraw` ", extraInfo, " (by Recipient) | ") @@ -138,13 +139,13 @@ abstract contract Benchmark_Test is Base_Test { } function gasWithdraw_ByAnyone(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { - gasWithdraw_AfterEndTime(streamId1, users.sender, users.recipient0, extraInfo); - gasWithdraw_BeforeEndTime(streamId2, users.sender, users.recipient0, extraInfo); + gasWithdraw_AfterEndTime(streamId1, users.sender, users.recipient, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.sender, users.recipient, extraInfo); } function gasWithdraw_ByRecipient(uint256 streamId1, uint256 streamId2, string memory extraInfo) internal { - gasWithdraw_AfterEndTime(streamId1, users.recipient0, users.alice, extraInfo); - gasWithdraw_BeforeEndTime(streamId2, users.recipient0, users.alice, extraInfo); + gasWithdraw_AfterEndTime(streamId1, users.recipient, users.alice, extraInfo); + gasWithdraw_BeforeEndTime(streamId2, users.recipient, users.alice, extraInfo); } /*////////////////////////////////////////////////////////////////////////// diff --git a/codecov.yml b/codecov.yml index 1ab56482e..c4868077c 100644 --- a/codecov.yml +++ b/codecov.yml @@ -7,6 +7,6 @@ coverage: ignore: - "precompiles" - "script" - - "src/libraries/NFTSVG.sol" - - "src/libraries/SVGElements.sol" + - "src/core/libraries/NFTSVG.sol" + - "src/core/libraries/SVGElements.sol" - "test" diff --git a/foundry.toml b/foundry.toml index 4959d4d8a..373e8e17e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,9 +9,13 @@ ] gas_limit = 9223372036854775807 gas_reports = [ + "SablierV2BatchLockup", "SablierV2LockupDynamic", "SablierV2LockupLinear", "SablierV2LockupTranched", + "SablierV2MerkleLL", + "SablierV2MerkleLockupFactory", + "SablierV2MerkleLT", "SablierV2NFTDescriptor", ] optimizer = true diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 9853f20c3..d432d6d34 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -7,7 +7,6 @@ import { ISablierV2LockupLinear } from "../src/core/interfaces/ISablierV2LockupL import { ISablierV2LockupTranched } from "../src/core/interfaces/ISablierV2LockupTranched.sol"; import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; - import { ISablierV2BatchLockup } from "../src/periphery/interfaces/ISablierV2BatchLockup.sol"; import { ISablierV2MerkleLockupFactory } from "../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index a0414ff07..f67e93a02 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -141,7 +141,7 @@ else echo -e "${WC}Missing '.env.deployment'. Provide details below: ${NC}\n" # initialize chains - initialize_interactive + initialize_interactive fi # Check for arguments passed to the script @@ -201,7 +201,7 @@ for ((i=1; i<=$#; i++)); do # Check if '--script' flag is provided in the arguments if [[ ${arg} == "--script" || ${arg} == "-s" ]]; then - files=(script/*.s.sol) + files=(script/**/*.s.sol) # Present the list of available scripts echo "Please select a script:" diff --git a/test/Base.t.sol b/test/Base.t.sol index 9908c0445..23be527f9 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -11,8 +11,11 @@ import { SablierV2LockupDynamic } from "src/core/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "src/core/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "src/core/SablierV2LockupTranched.sol"; import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierV2MerkleLockupFactory } from "src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; import { ISablierV2BatchLockup } from "src/periphery/interfaces/ISablierV2BatchLockup.sol"; +import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; import { SablierV2BatchLockup } from "src/periphery/SablierV2BatchLockup.sol"; import { SablierV2MerkleLockupFactory } from "src/periphery/SablierV2MerkleLockupFactory.sol"; @@ -48,6 +51,8 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi ISablierV2LockupLinear internal lockupLinear; ISablierV2LockupTranched internal lockupTranched; ISablierV2MerkleLockupFactory internal merkleLockupFactory; + ISablierV2MerkleLL internal merkleLL; + ISablierV2MerkleLT internal merkleLT; ISablierV2NFTDescriptor internal nftDescriptor; Noop internal noop; RecipientGood internal recipientGood; @@ -86,7 +91,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi users.broker = createUser("Broker"); users.eve = createUser("Eve"); users.operator = createUser("Operator"); - users.recipient0 = createUser("Recipient0"); + users.recipient = createUser("Recipient"); users.recipient1 = createUser("Recipient1"); users.recipient2 = createUser("Recipient2"); users.recipient3 = createUser("Recipient3"); @@ -104,6 +109,13 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi HELPERS //////////////////////////////////////////////////////////////////////////*/ + /// @dev Approve `spender` to spend assets from `from`. + function approveContract(IERC20 asset_, address from, address spender) internal { + resetPrank({ msgSender: from }); + (bool success,) = address(asset_).call(abi.encodeCall(IERC20.approve, (spender, MAX_UINT256))); + success; + } + /// @dev Approves all contracts to spend assets from the address passed. function approveProtocol(address from) internal { resetPrank({ msgSender: from }); @@ -156,7 +168,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi } /*////////////////////////////////////////////////////////////////////////// - CALL EXPECTS + CALL EXPECTS - IERC20 //////////////////////////////////////////////////////////////////////////*/ /// @dev Expects a call to {IERC20.transfer}. @@ -178,4 +190,125 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi function expectCallToTransferFrom(IERC20 asset, address from, address to, uint256 value) internal { vm.expectCall({ callee: address(asset), data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) }); } + + /// @dev Expects multiple calls to {IERC20.transfer}. + function expectMultipleCallsToTransfer(uint64 count, address to, uint256 value) internal { + vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, value)) }); + } + + /// @dev Expects multiple calls to {IERC20.transferFrom}. + function expectMultipleCallsToTransferFrom(uint64 count, address from, address to, uint256 value) internal { + expectMultipleCallsToTransferFrom(dai, count, from, to, value); + } + + /// @dev Expects multiple calls to {IERC20.transferFrom}. + function expectMultipleCallsToTransferFrom( + IERC20 asset, + uint64 count, + address from, + address to, + uint256 value + ) + internal + { + vm.expectCall({ + callee: address(asset), + count: count, + data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) + }); + } + + /*////////////////////////////////////////////////////////////////////////// + CALL EXPECTS - LOCKUP + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLD( + uint64 count, + LockupDynamic.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLL( + uint64 count, + LockupLinear.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierV2LockupLinear.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLT( + uint64 count, + LockupTranched.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithDurations, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLD( + uint64 count, + LockupDynamic.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupDynamic), + count: count, + data: abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLL( + uint64 count, + LockupLinear.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupLinear), + count: count, + data: abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, (params)) + }); + } + + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLT( + uint64 count, + LockupTranched.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, (params)) + }); + } } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 5d7baf4c2..79072fc32 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -146,7 +146,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -179,7 +179,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index d076dfada..f5e00fc95 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -353,7 +353,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), segments: defaults.segments(), asset: IERC20(asset), @@ -384,7 +384,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol index 04e1370ed..2362e29d9 100644 --- a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -67,7 +67,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); + lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 039d06d58..623d87884 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -109,7 +109,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -141,7 +141,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index 45435e9be..b809172e7 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -103,7 +103,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } @@ -260,7 +260,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), asset: IERC20(asset), cancelable: true, @@ -290,7 +290,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol index a65fa35c4..c5a6d9d44 100644 --- a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -47,7 +47,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test is } modifier givenPreviousWithdrawals() { - lockupLinear.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); + lockupLinear.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); _; } diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index 08b50dc23..b8e7a2579 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -140,7 +140,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -173,7 +173,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 471125ae8..4d30b16db 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -353,7 +353,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), tranches: defaults.tranches(), asset: IERC20(asset), @@ -384,7 +384,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol index a7ae4d8f6..0f1ea9bd2 100644 --- a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -66,7 +66,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Make the withdrawal. - lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.CLIFF_AMOUNT() }); + lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); diff --git a/test/core/integration/concrete/lockup/burn/burn.t.sol b/test/core/integration/concrete/lockup/burn/burn.t.sol index 437e3f5f8..57a12ba57 100644 --- a/test/core/integration/concrete/lockup/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup/burn/burn.t.sol @@ -18,7 +18,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int notTransferableStreamId = createDefaultStreamNotTransferable(); // Make the Recipient (owner of the NFT) the caller in this test suite. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } function test_RevertWhen_DelegateCalled() external { @@ -87,14 +87,14 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); resetPrank({ msgSender: users.sender }); lockup.cancel(streamId); - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } modifier givenStreamHasBeenDepleted(uint256 streamId_) { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: streamId_, to: users.recipient0 }); + lockup.withdrawMax({ streamId: streamId_, to: users.recipient }); _; } diff --git a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index e5cf0114e..a1fe88a41 100644 --- a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -81,11 +81,11 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient0) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) ); lockup.cancelMultiple(testStreamIds); } @@ -120,11 +120,11 @@ abstract contract CancelMultiple_Integration_Concrete_Test is whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient0) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) ); lockup.cancelMultiple(testStreamIds); } @@ -181,7 +181,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is emit CancelLockupStream({ streamId: testStreamIds[0], sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, asset: dai, senderAmount: senderAmount0, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 @@ -190,7 +190,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is emit CancelLockupStream({ streamId: testStreamIds[1], sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, asset: dai, senderAmount: senderAmount1, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1 @@ -213,7 +213,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is assertEq(lockup.getRefundedAmount(testStreamIds[1]), senderAmount1, "refundedAmount1"); // Assert that the NFTs have not been burned. - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(lockup.getRecipient(testStreamIds[0]), expectedNFTOwner, "NFT owner0"); assertEq(lockup.getRecipient(testStreamIds[1]), expectedNFTOwner, "NFT owner1"); } diff --git a/test/core/integration/concrete/lockup/cancel/cancel.t.sol b/test/core/integration/concrete/lockup/cancel/cancel.t.sol index 0aec17acc..4f6ba46ec 100644 --- a/test/core/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup/cancel/cancel.t.sol @@ -29,7 +29,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenNotNull givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } @@ -72,11 +72,11 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerUnauthorized { // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient0) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) ); lockup.cancel(defaultStreamId); } diff --git a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol index 13b38625c..8bfcd06ae 100644 --- a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol @@ -28,10 +28,10 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Deplete the stream. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Burn the NFT. lockup.burn(defaultStreamId); @@ -47,7 +47,7 @@ abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test, Lo function test_GetRecipient() external view givenNotNull givenNFTNotBurned { address actualRecipient = lockup.getRecipient(defaultStreamId); - address expectedRecipient = users.recipient0; + address expectedRecipient = users.recipient; assertEq(actualRecipient, expectedRecipient, "recipient"); } } diff --git a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index 86b56cde8..bf8632a74 100644 --- a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -45,7 +45,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); @@ -78,7 +78,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes function test_GetRefundedAmount_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); uint128 expectedRefundedAmount = 0; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); diff --git a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index fd6198386..61614c844 100644 --- a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -38,7 +38,7 @@ abstract contract GetWithdrawnAmount_Integration_Concrete_Test is uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol index 657a73e6e..0af6bd4bc 100644 --- a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol @@ -49,7 +49,7 @@ abstract contract IsCold_Integration_Concrete_Test is Integration_Test, Lockup_I function test_IsCold_StatusDepleted() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); bool isCold = lockup.isCold(defaultStreamId); assertTrue(isCold, "isCold"); } diff --git a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 6404a05e8..7ea200621 100644 --- a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -29,7 +29,7 @@ abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test, Lock modifier givenStreamDepleted() { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); _; } diff --git a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol index 06b017503..3ba90957f 100644 --- a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -49,7 +49,7 @@ abstract contract IsWarm_Integration_Concrete_Test is Integration_Test, Lockup_I function test_IsWarm_StatusDepleted() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); bool isWarm = lockup.isWarm(defaultStreamId); assertFalse(isWarm, "isWarm"); } diff --git a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index b6f1a419d..48fbb8057 100644 --- a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -60,7 +60,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedRefundableAmount = 0; @@ -114,7 +114,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualRefundableAmount = lockup.refundableAmountOf(defaultStreamId); uint128 expectedReturnableAmount = 0; assertEq(actualRefundableAmount, expectedReturnableAmount, "refundableAmount"); diff --git a/test/core/integration/concrete/lockup/renounce/renounce.t.sol b/test/core/integration/concrete/lockup/renounce/renounce.t.sol index 66cc4e4e7..ce319d185 100644 --- a/test/core/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup/renounce/renounce.t.sol @@ -40,7 +40,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } diff --git a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol index 4f7d34151..c426e86fa 100644 --- a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol @@ -25,7 +25,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup function test_StatusOf_AssetsFullyWithdrawn() external givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); Lockup.Status expectedStatus = Lockup.Status.DEPLETED; assertEq(actualStatus, expectedStatus); diff --git a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index 3de2649f5..3fc0557ec 100644 --- a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -40,7 +40,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); @@ -63,7 +63,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is function test_StreamedAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); diff --git a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol index a63c105fb..3a48922a6 100644 --- a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -8,7 +8,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lockup_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, Lockup_Integration_Shared_Test) { - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } function test_RevertGiven_StreamNotTransferable() external { @@ -16,7 +16,7 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) ); - lockup.transferFrom({ from: users.recipient0, to: users.alice, tokenId: notTransferableStreamId }); + lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: notTransferableStreamId }); } modifier givenStreamTransferable() { @@ -31,10 +31,10 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: streamId }); vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient0, to: users.alice, tokenId: streamId }); + emit Transfer({ from: users.recipient, to: users.alice, tokenId: streamId }); // Transfer the NFT. - lockup.transferFrom({ from: users.recipient0, to: users.alice, tokenId: streamId }); + lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: streamId }); // Assert that Alice is the new stream recipient (and NFT owner). address actualRecipient = lockup.getRecipient(streamId); diff --git a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 3f2c26638..1430c679b 100644 --- a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -24,7 +24,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient0 }); + lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient }); } function test_RevertWhen_CallerNotCurrentRecipient() external whenNotDelegateCalled givenNotNull { @@ -41,14 +41,14 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is function test_RevertGiven_NFTBurned() external whenNotDelegateCalled givenNotNull whenCallerCurrentRecipient { // Deplete the stream. vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Burn the NFT. lockup.burn({ streamId: defaultStreamId }); // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient0) + abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) ); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -61,7 +61,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is givenNFTNotBurned { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -77,7 +77,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is vm.expectRevert( abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) ); - lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient0 }); + lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient }); } function test_WithdrawMaxAndTransfer() @@ -96,20 +96,20 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient0, value: expectedWithdrawnAmount }); + expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, amount: expectedWithdrawnAmount, asset: dai }); vm.expectEmit({ emitter: address(lockup) }); emit MetadataUpdate({ _tokenId: defaultStreamId }); vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient0, to: users.alice, tokenId: defaultStreamId }); + emit Transfer({ from: users.recipient, to: users.alice, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. uint128 actualWithdrawnAmount = diff --git a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol index 260128e87..1874af85b 100644 --- a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol @@ -16,19 +16,19 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient0, value: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, amount: defaults.DEPOSIT_AMOUNT(), asset: dai }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -46,7 +46,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -58,19 +58,19 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test, Wit uint128 expectedWithdrawnAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient0, value: expectedWithdrawnAmount }); + expectCallToTransfer({ to: users.recipient, value: expectedWithdrawnAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, amount: expectedWithdrawnAmount, asset: dai }); // Make the max withdrawal. - uint128 actualWithdrawnAmount = lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + uint128 actualWithdrawnAmount = lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Assert that the withdrawn amount has been updated. assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); diff --git a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index dc47ab507..f49c86a23 100644 --- a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -97,7 +97,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. - lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient0 }); + lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); // Expect the relevant error to be thrown. vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); @@ -117,7 +117,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. - lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient0 }); + lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); // Expect the relevant error to be thrown. vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); @@ -190,29 +190,29 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is resetPrank({ msgSender: caller }); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient0, value: testAmounts[0] }); - expectCallToTransfer({ to: users.recipient0, value: testAmounts[1] }); - expectCallToTransfer({ to: users.recipient0, value: testAmounts[2] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[0] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[1] }); + expectCallToTransfer({ to: users.recipient, value: testAmounts[2] }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[0], - to: users.recipient0, + to: users.recipient, asset: dai, amount: testAmounts[0] }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[1], - to: users.recipient0, + to: users.recipient, asset: dai, amount: testAmounts[1] }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: testStreamIds[2], - to: users.recipient0, + to: users.recipient, asset: dai, amount: testAmounts[2] }); @@ -231,8 +231,8 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is assertEq(lockup.getWithdrawnAmount(testStreamIds[2]), testAmounts[2], "withdrawnAmount2"); // Assert that the stream NFTs have not been burned. - assertEq(lockup.getRecipient(testStreamIds[0]), users.recipient0, "NFT owner0"); - assertEq(lockup.getRecipient(testStreamIds[1]), users.recipient0, "NFT owner1"); - assertEq(lockup.getRecipient(testStreamIds[2]), users.recipient0, "NFT owner2"); + assertEq(lockup.getRecipient(testStreamIds[0]), users.recipient, "NFT owner0"); + assertEq(lockup.getRecipient(testStreamIds[1]), users.recipient, "NFT owner1"); + assertEq(lockup.getRecipient(testStreamIds[2]), users.recipient, "NFT owner2"); } } diff --git a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol index d14bef221..4d4247b37 100644 --- a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -22,7 +22,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = - abi.encodeCall(ISablierV2Lockup.withdraw, (defaultStreamId, users.recipient0, withdrawAmount)); + abi.encodeCall(ISablierV2Lockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -31,16 +31,16 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint256 nullStreamId = 1729; uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); - lockup.withdraw({ streamId: nullStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: nullStreamId, to: users.recipient, amount: withdrawAmount }); } function test_RevertGiven_StreamDepleted() external whenNotDelegateCalled givenNotNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } function test_RevertWhen_ToZeroAddress() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { @@ -57,7 +57,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenToNonZeroAddress { vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: 0 }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); } function test_RevertWhen_Overdraw() @@ -74,7 +74,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr Errors.SablierV2Lockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: MAX_UINT128 }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); } function test_RevertWhen_CallerUnknown() @@ -139,7 +139,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr whenWithdrawalAddressNotRecipient { // Transfer the stream to Alice. - lockup.transferFrom(users.recipient0, users.alice, defaultStreamId); + lockup.transferFrom(users.recipient, users.alice, defaultStreamId); // Run the test. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -147,11 +147,11 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr abi.encodeWithSelector( Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, - users.recipient0, - users.recipient0 + users.recipient, + users.recipient ) ); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } function test_Withdraw_CallerApprovedOperator() @@ -233,7 +233,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -255,7 +255,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -278,7 +278,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr vm.warp({ newTimestamp: defaults.END_TIME() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.DEPOSIT_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.DEPOSIT_AMOUNT() }); // Assert that the stream's status is "DEPLETED". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -291,7 +291,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -314,7 +314,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); // Assert that the stream's status is "DEPLETED". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -328,7 +328,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index f038c2b3e..bdccef21b 100644 --- a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -40,7 +40,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 10 seconds }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; @@ -63,7 +63,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is function test_WithdrawableAmountOf_StatusDepleted() external givenNotNull givenStreamHasNotBeenCanceled { vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 7d359064c..4dc092c94 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -77,7 +77,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is streamId: streamId, funder: vars.funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: vars.createAmounts, asset: dai, cancelable: true, @@ -108,7 +108,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, users.recipient0, "recipient"); + assertEq(actualStream.recipient, users.recipient, "recipient"); assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); assertEq(actualStream.sender, users.sender, "sender"); assertEq(actualStream.startTime, timestamps.start, "startTime"); @@ -126,7 +126,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is // Assert that the NFT has been minted. vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); - vars.expectedNFTOwner = users.recipient0; + vars.expectedNFTOwner = users.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index 9c5fe5399..b4c241bd3 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -102,7 +102,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is emit MetadataUpdate({ _tokenId: vars.streamId }); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Make the withdrawal. lockupDynamic.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); diff --git a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 1f3b672d3..719b6b619 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -92,7 +92,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); + lockupDynamic.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol index 50613f004..8a0900bb4 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -79,7 +79,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is streamId: streamId, funder: funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: defaults.lockupCreateAmounts(), asset: dai, cancelable: true, @@ -111,7 +111,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Assert that the NFT has been minted. address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index ed871061e..68f2469bf 100644 --- a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -119,7 +119,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupLinear.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); + lockupLinear.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol index eadeff6ab..1c4396ea5 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -77,7 +77,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is streamId: streamId, funder: vars.funder, sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, amounts: vars.createAmounts, asset: dai, cancelable: true, @@ -126,7 +126,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is // Assert that the NFT has been minted. vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); - vars.expectedNFTOwner = users.recipient0; + vars.expectedNFTOwner = users.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 1bc5349e2..153062f3b 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -93,7 +93,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is vars.withdrawAmount = boundUint128(vars.withdrawAmount, 1, vars.withdrawableAmount); // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Expect the assets to be transferred to the fuzzed `to` address. expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); diff --git a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 868e2b014..74cb15aaf 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -94,7 +94,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupTranched.withdraw({ streamId: streamId, to: users.recipient0, amount: withdrawAmount }); + lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); diff --git a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol index 9e0957777..b18b52cd1 100644 --- a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/cancelMultiple.t.sol @@ -47,7 +47,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc emit CancelLockupStream({ streamId: streamIds[0], sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, asset: dai, senderAmount: senderAmount0, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 @@ -56,7 +56,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc emit CancelLockupStream({ streamId: streamIds[1], sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, asset: dai, senderAmount: senderAmount1, recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1 @@ -84,7 +84,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is Integration_Test, Canc assertEq(lockup.getRefundedAmount(streamIds[1]), expectedRefundedAmount1, "refundedAmount1"); // Assert that the NFTs have not been burned. - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(lockup.getRecipient(streamIds[0]), expectedNFTOwner, "NFT owner0"); assertEq(lockup.getRecipient(streamIds[1]), expectedNFTOwner, "NFT owner1"); } diff --git a/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol index 3b8bdfded..71da96105 100644 --- a/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol +++ b/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol @@ -42,7 +42,7 @@ abstract contract GetWithdrawnAmount_Integration_Fuzz_Test is withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: withdrawAmount }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/fuzz/lockup/withdraw.t.sol b/test/core/integration/fuzz/lockup/withdraw.t.sol index 594a1ff4d..14835faff 100644 --- a/test/core/integration/fuzz/lockup/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup/withdraw.t.sol @@ -22,7 +22,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I whenWithdrawAmountNotZero whenNoOverdraw { - vm.assume(caller != users.sender && caller != users.recipient0); + vm.assume(caller != users.sender && caller != users.recipient); // Make the fuzzed address the caller in this test. resetPrank({ msgSender: caller }); @@ -31,7 +31,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient0, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Assert that the stream's status is still "STREAMING". Lockup.Status actualStatus = lockup.statusOf(defaultStreamId); @@ -108,7 +108,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Cancel the stream. resetPrank({ msgSender: users.sender }); lockup.cancel({ streamId: defaultStreamId }); - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); // Bound the withdraw amount. uint128 withdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); @@ -142,7 +142,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -212,7 +212,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup/withdrawMax.t.sol b/test/core/integration/fuzz/lockup/withdrawMax.t.sol index 41760fb22..90ed13ed3 100644 --- a/test/core/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMax.t.sol @@ -18,19 +18,19 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Expect the ERC-20 assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient0, value: defaults.DEPOSIT_AMOUNT() }); + expectCallToTransfer({ to: users.recipient, value: defaults.DEPOSIT_AMOUNT() }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, asset: dai, amount: defaults.DEPOSIT_AMOUNT() }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); @@ -48,7 +48,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra // Assert that the NFT has not been burned. address actualNFTowner = lockup.ownerOf({ tokenId: defaultStreamId }); - address expectedNFTOwner = users.recipient0; + address expectedNFTOwner = users.recipient; assertEq(actualNFTowner, expectedNFTOwner, "NFT owner"); } @@ -62,19 +62,19 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test, Withdra uint128 withdrawAmount = lockup.withdrawableAmountOf(defaultStreamId); // Expect the assets to be transferred to the Recipient. - expectCallToTransfer({ to: users.recipient0, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, asset: dai, amount: withdrawAmount }); // Make the max withdrawal. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient0 }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); // Assert that the withdrawn amount has been updated. uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); diff --git a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol index cd4fb11e2..ecde8780a 100644 --- a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol @@ -38,13 +38,13 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is if (withdrawAmount > 0) { // Expect the assets to be transferred to the fuzzed recipient. - expectCallToTransfer({ to: users.recipient0, value: withdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmount }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: defaultStreamId, - to: users.recipient0, + to: users.recipient, asset: dai, amount: withdrawAmount }); @@ -52,7 +52,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit Transfer({ from: users.recipient0, to: newRecipient, tokenId: defaultStreamId }); + emit Transfer({ from: users.recipient, to: newRecipient, tokenId: defaultStreamId }); // Make the max withdrawal and transfer the NFT. lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: newRecipient }); diff --git a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol index ab72262a4..5ffb0d931 100644 --- a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol @@ -52,21 +52,21 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is ongoingWithdrawAmount = boundUint128(ongoingWithdrawAmount, 1, ongoingWithdrawableAmount); // Expect the withdrawals to be made. - expectCallToTransfer({ to: users.recipient0, value: ongoingWithdrawAmount }); - expectCallToTransfer({ to: users.recipient0, value: settledWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: ongoingWithdrawAmount }); + expectCallToTransfer({ to: users.recipient, value: settledWithdrawAmount }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: ongoingStreamId, - to: users.recipient0, + to: users.recipient, asset: dai, amount: ongoingWithdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); emit WithdrawFromLockupStream({ streamId: settledStreamId, - to: users.recipient0, + to: users.recipient, asset: dai, amount: settledWithdrawAmount }); @@ -85,7 +85,7 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is assertEq(lockup.getWithdrawnAmount(streamIds[1]), amounts[1], "withdrawnAmount1"); // Assert that the stream NFTs have not been burned. - assertEq(lockup.getRecipient(streamIds[0]), users.recipient0, "NFT owner0"); - assertEq(lockup.getRecipient(streamIds[1]), users.recipient0, "NFT owner1"); + assertEq(lockup.getRecipient(streamIds[0]), users.recipient, "NFT owner0"); + assertEq(lockup.getRecipient(streamIds[1]), users.recipient, "NFT owner1"); } } diff --git a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 0bdcfaaa3..a74578e03 100644 --- a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -22,7 +22,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh Lockup_Integration_Shared_Test.setUp(); _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient0; + _params.createWithDurations.recipient = users.recipient; _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithDurations.asset = dai; _params.createWithDurations.cancelable = true; @@ -30,7 +30,7 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh _params.createWithDurations.broker = defaults.broker(); _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient0; + _params.createWithTimestamps.recipient = users.recipient; _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithTimestamps.asset = dai; _params.createWithTimestamps.cancelable = true; diff --git a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol index 90a675ffa..81213515a 100644 --- a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -22,7 +22,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S Lockup_Integration_Shared_Test.setUp(); _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient0; + _params.createWithDurations.recipient = users.recipient; _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithDurations.asset = dai; _params.createWithDurations.cancelable = true; @@ -30,7 +30,7 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S _params.createWithDurations.broker = defaults.broker(); _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient0; + _params.createWithTimestamps.recipient = users.recipient; _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); _params.createWithTimestamps.asset = dai; _params.createWithTimestamps.cancelable = true; diff --git a/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol b/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol index dfce20e73..e7a3985ca 100644 --- a/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol +++ b/test/core/integration/shared/lockup/getWithdrawnAmount.t.sol @@ -7,7 +7,7 @@ abstract contract GetWithdrawnAmount_Integration_Shared_Test is Lockup_Integrati uint256 internal defaultStreamId; function setUp() public virtual override { - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } modifier givenNotNull() { diff --git a/test/core/integration/shared/lockup/withdraw.t.sol b/test/core/integration/shared/lockup/withdraw.t.sol index d5c53369c..75fe7fa5e 100644 --- a/test/core/integration/shared/lockup/withdraw.t.sol +++ b/test/core/integration/shared/lockup/withdraw.t.sol @@ -8,7 +8,7 @@ abstract contract Withdraw_Integration_Shared_Test is Lockup_Integration_Shared_ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } modifier givenEndTimeInTheFuture() { diff --git a/test/core/integration/shared/lockup/withdrawMax.t.sol b/test/core/integration/shared/lockup/withdrawMax.t.sol index 0ce0623a6..f19c3323c 100644 --- a/test/core/integration/shared/lockup/withdrawMax.t.sol +++ b/test/core/integration/shared/lockup/withdrawMax.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMax_Integration_Shared_Test is Lockup_Integration_Shar function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } modifier givenEndTimeInTheFuture() { diff --git a/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol index 03c5bd4b0..222cb78eb 100644 --- a/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/shared/lockup/withdrawMaxAndTransfer.t.sol @@ -8,7 +8,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Shared_Test is Lockup_Integ function setUp() public virtual override { defaultStreamId = createDefaultStream(); - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); } modifier givenNFTNotBurned() { diff --git a/test/core/integration/shared/lockup/withdrawMultiple.t.sol b/test/core/integration/shared/lockup/withdrawMultiple.t.sol index cd5e98baf..ca236ecff 100644 --- a/test/core/integration/shared/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/shared/lockup/withdrawMultiple.t.sol @@ -58,12 +58,12 @@ abstract contract WithdrawMultiple_Integration_Shared_Test is Lockup_Integration caller = users.sender; _; createTestStreams(); - caller = users.recipient0; - resetPrank({ msgSender: users.recipient0 }); + caller = users.recipient; + resetPrank({ msgSender: users.recipient }); _; createTestStreams(); caller = users.operator; - resetPrank({ msgSender: users.recipient0 }); + resetPrank({ msgSender: users.recipient }); lockup.setApprovalForAll({ operator: users.operator, approved: true }); caller = users.operator; resetPrank({ msgSender: users.operator }); diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 87f114cf6..8c6bc43d7 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -3,161 +3,19 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; -import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; import { SablierV2MerkleLL } from "src/periphery/SablierV2MerkleLL.sol"; import { SablierV2MerkleLT } from "src/periphery/SablierV2MerkleLT.sol"; import { Base_Test } from "../Base.t.sol"; contract Periphery_Test is Base_Test { - ISablierV2MerkleLL internal merkleLL; - ISablierV2MerkleLT internal merkleLT; - /*////////////////////////////////////////////////////////////////////////// - SET-UP + SET-UP FUNCTION //////////////////////////////////////////////////////////////////////////*/ - function setUp() public virtual override { Base_Test.setUp(); } - /*////////////////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Approve `spender` to spend assets from `from`. - function approveContract(IERC20 asset_, address from, address spender) internal { - resetPrank({ msgSender: from }); - (bool success,) = address(asset_).call(abi.encodeCall(IERC20.approve, (spender, MAX_UINT256))); - success; - } - - /*////////////////////////////////////////////////////////////////////////// - EXPECT-CALLS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLD( - uint64 count, - LockupDynamic.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupDynamic), - count: count, - data: abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLL( - uint64 count, - LockupLinear.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupLinear), - count: count, - data: abi.encodeCall(ISablierV2LockupLinear.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithDurations}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithDurationsLT( - uint64 count, - LockupTranched.CreateWithDurations memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupTranched), - count: count, - data: abi.encodeCall(ISablierV2LockupTranched.createWithDurations, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLD( - uint64 count, - LockupDynamic.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupDynamic), - count: count, - data: abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLL( - uint64 count, - LockupLinear.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupLinear), - count: count, - data: abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, (params)) - }); - } - - /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithTimestamps}, each with the specified - /// `params`. - function expectMultipleCallsToCreateWithTimestampsLT( - uint64 count, - LockupTranched.CreateWithTimestamps memory params - ) - internal - { - vm.expectCall({ - callee: address(lockupTranched), - count: count, - data: abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, (params)) - }); - } - - /// @dev Expects multiple calls to {IERC20.transfer}. - function expectMultipleCallsToTransfer(uint64 count, address to, uint256 value) internal { - vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, value)) }); - } - - /// @dev Expects multiple calls to {IERC20.transferFrom}. - function expectMultipleCallsToTransferFrom(uint64 count, address from, address to, uint256 value) internal { - expectMultipleCallsToTransferFrom(dai, count, from, to, value); - } - - /// @dev Expects multiple calls to {IERC20.transferFrom}. - function expectMultipleCallsToTransferFrom( - IERC20 asset, - uint64 count, - address from, - address to, - uint256 value - ) - internal - { - vm.expectCall({ - callee: address(asset), - count: count, - data: abi.encodeCall(IERC20.transferFrom, (from, to, value)) - }); - } - /*////////////////////////////////////////////////////////////////////////// MERKLE-LOCKUP //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index 617e254c5..4f97e0ebd 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -34,7 +34,7 @@ abstract contract Fork_Test is Periphery_Test, Merkle { // Fork Ethereum Mainnet at a specific block number. vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); - // Set up the base test contract. + // Set up the parent test contract. Periphery_Test.setUp(); // Load the external dependencies. diff --git a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol index 62ccfec60..6fd0aac55 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol @@ -58,7 +58,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { function testForkFuzz_MerkleLL(Params memory params) external { vm.assume(params.admin != address(0) && params.admin != users.admin); - vm.assume(params.leafData.length > 1); + vm.assume(params.leafData.length > 0); assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); diff --git a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol index e8b50fbcc..027d4f5e5 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol @@ -59,7 +59,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { function testForkFuzz_MerkleLT(Params memory params) external { vm.assume(params.admin != address(0) && params.admin != users.admin); - vm.assume(params.leafData.length > 1); + vm.assume(params.leafData.length > 0); assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); diff --git a/test/utils/Constants.sol b/test/utils/Constants.sol index 592eaacfc..82943e274 100644 --- a/test/utils/Constants.sol +++ b/test/utils/Constants.sol @@ -4,10 +4,10 @@ pragma solidity >=0.8.22; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; abstract contract Constants { + uint40 internal constant JULY_1_2024 = 1_719_792_000; UD60x18 internal constant MAX_BROKER_FEE = UD60x18.wrap(0.1e18); // 10% uint128 internal constant MAX_UINT128 = type(uint128).max; uint256 internal constant MAX_UINT256 = type(uint256).max; uint40 internal constant MAX_UINT40 = type(uint40).max; uint40 internal constant MAX_UNIX_TIMESTAMP = 2_147_483_647; // 2^31 - 1 - uint40 internal constant JULY_1_2024 = 1_719_792_000; } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 8704d6177..c2c03f571 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -36,11 +36,11 @@ contract Defaults is Constants, Merkle { uint40 public immutable MAX_SEGMENT_DURATION; uint256 public constant MAX_TRANCHE_COUNT = 10_000; uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; - uint256 public SEGMENT_COUNT; + uint256 public constant SEGMENT_COUNT = 2; uint40 public immutable START_TIME; uint128 public constant TOTAL_AMOUNT = 10_030.090270812437311935e18; // deposit + broker fee uint40 public constant TOTAL_DURATION = 10_000 seconds; - uint256 public TRANCHE_COUNT; + uint256 public constant TRANCHE_COUNT = 3; uint128 public constant TOTAL_TRANSFER_AMOUNT = DEPOSIT_AMOUNT * uint128(BATCH_SIZE); uint128 public constant WITHDRAW_AMOUNT = 2600e18; uint40 public immutable WARP_26_PERCENT; // 26% of the way through the stream @@ -53,7 +53,7 @@ contract Defaults is Constants, Merkle { bool public constant CANCELABLE = false; uint128 public constant CLAIM_AMOUNT = 10_000e18; uint40 public immutable EXPIRATION; - uint40 public immutable FIRST_CLAIM_TIME; + uint40 public constant FIRST_CLAIM_TIME = JULY_1_2024; uint256 public constant INDEX1 = 1; uint256 public constant INDEX2 = 2; uint256 public constant INDEX3 = 3; @@ -82,13 +82,9 @@ contract Defaults is Constants, Merkle { START_TIME = JULY_1_2024 + 2 days; CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; + EXPIRATION = JULY_1_2024 + 12 weeks; MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); - SEGMENT_COUNT = 2; - TRANCHE_COUNT = 3; WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; - - EXPIRATION = JULY_1_2024 + 12 weeks; - FIRST_CLAIM_TIME = JULY_1_2024; } /*////////////////////////////////////////////////////////////////////////// @@ -147,7 +143,7 @@ contract Defaults is Constants, Merkle { isDepleted: false, isStream: true, isTransferable: true, - recipient: users.recipient0, + recipient: users.recipient, segments: segments(), sender: users.sender, startTime: START_TIME, @@ -169,7 +165,7 @@ contract Defaults is Constants, Merkle { isTransferable: true, isDepleted: false, isStream: true, - recipient: users.recipient0, + recipient: users.recipient, sender: users.sender, startTime: START_TIME, wasCanceled: false @@ -189,7 +185,7 @@ contract Defaults is Constants, Merkle { isDepleted: false, isStream: true, isTransferable: true, - recipient: users.recipient0, + recipient: users.recipient, sender: users.sender, startTime: START_TIME, tranches: tranches(), @@ -259,7 +255,7 @@ contract Defaults is Constants, Merkle { function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { return LockupDynamic.CreateWithDurations({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, @@ -279,7 +275,7 @@ contract Defaults is Constants, Merkle { function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { return LockupLinear.CreateWithDurations({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, @@ -299,7 +295,7 @@ contract Defaults is Constants, Merkle { function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { return LockupTranched.CreateWithDurations({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, @@ -319,7 +315,7 @@ contract Defaults is Constants, Merkle { function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { return LockupDynamic.CreateWithTimestamps({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, @@ -340,7 +336,7 @@ contract Defaults is Constants, Merkle { function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { return LockupLinear.CreateWithTimestamps({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, @@ -360,7 +356,7 @@ contract Defaults is Constants, Merkle { function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { return LockupTranched.CreateWithTimestamps({ sender: users.sender, - recipient: users.recipient0, + recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, diff --git a/test/utils/Types.sol b/test/utils/Types.sol index 173661031..ed5aa2454 100644 --- a/test/utils/Types.sol +++ b/test/utils/Types.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22; struct Users { - // Default admin for all contracts. + // Default admin. address payable admin; // Impartial user. address payable alice; @@ -12,8 +12,9 @@ struct Users { address payable eve; // Default NFT operator. address payable operator; - // Default stream recipients. - address payable recipient0; + // Default stream recipient. + address payable recipient; + // Other recipients. address payable recipient1; address payable recipient2; address payable recipient3; From d7162c4e5ac4fe546668974ec553247479b72263 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Thu, 1 Aug 2024 23:58:00 +0100 Subject: [PATCH 11/34] refactor: remove V2 and obsolete references (#994) Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> * refactor: remove V2 from codebase refactor: refer to Lockup contracts * fix: make NFTDescriptor compatible with previous versions * fix: use sablier as variabel name in tokenURI * chore: update precompiles * refactor: prefix Sablier in NFT mapsymbol * refactor(periphery): order alphabetically functions in batch interfaces style: center headers style: improve the asci art style: remove empty spaces chore: add todos * test: computing merkle proof for 1 leaf * refactor: use lockup as variable in NFT Descriptor * refactor: replace v2-core with lockup in urls * test: add v1.2.0 to NFTDescriptor_Fork_Test refactor: use package versions in NFTDescriptor_Fork_Test * refactor: rename SablierNFTDescriptor to LockupNFTDescriptor * docs(README): remove periphery reference * test: add TODO over loadDependencies function --------- Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Co-authored-by: andreivladbrg --- CHANGELOG.md | 84 ++++----- CONTRIBUTING.md | 8 +- LICENSE.md | 2 +- README.md | 45 +++-- SECURITY.md | 16 +- benchmark/BatchLockup.Gas.t.sol | 2 +- benchmark/Benchmark.t.sol | 4 +- benchmark/LockupDynamic.Gas.t.sol | 2 +- benchmark/LockupLinear.Gas.t.sol | 2 +- benchmark/LockupTranched.Gas.t.sol | 2 +- ...V2BatchLockup.md => SablierBatchLockup.md} | 0 ...ckupDynamic.md => SablierLockupDynamic.md} | 0 ...LockupLinear.md => SablierLockupLinear.md} | 0 ...upTranched.md => SablierLockupTranched.md} | 0 foundry.toml | 26 +-- package.json | 12 +- precompiles/Precompiles.sol | 171 +++++++++--------- script/DeployDeterministicProtocol.s.sol | 42 ++--- script/DeployProtocol.s.sol | 42 ++--- script/core/DeployCore.s.sol | 26 +-- script/core/DeployCore2.s.sol | 22 +-- script/core/DeployDeterministicCore.s.sol | 26 +-- script/core/DeployDeterministicCore2.s.sol | 22 +-- .../DeployDeterministicLockupDynamic.s.sol | 12 +- .../DeployDeterministicLockupLinear.s.sol | 12 +- .../DeployDeterministicLockupTranched.s.sol | 15 +- .../DeployDeterministicNFTDescriptor.s.sol | 8 +- script/core/DeployLockupDynamic.s.sol | 10 +- script/core/DeployLockupLinear.s.sol | 10 +- script/core/DeployLockupTranched.s.sol | 10 +- script/core/DeployNFTDescriptor.s.sol | 6 +- script/core/GenerateSVG.s.sol | 10 +- script/core/Init.s.sol | 10 +- script/periphery/CreateMerkleLL.s.sol | 15 +- script/periphery/CreateMerkleLT.s.sol | 15 +- script/periphery/DeployBatchLockup.t.sol | 6 +- .../DeployDeterministicBatchLockup.s.sol | 8 +- .../DeployDeterministicPeriphery.s.sol | 16 +- .../periphery/DeployMerkleLockupFactory.s.sol | 6 +- script/periphery/DeployPeriphery.s.sol | 16 +- shell/deploy-multi-chain.sh | 12 +- shell/prepare-artifacts.sh | 34 ++-- shell/update-precompiles.sh | 12 +- ...Descriptor.sol => LockupNFTDescriptor.sol} | 110 +++++------ ...upDynamic.sol => SablierLockupDynamic.sol} | 64 +++---- ...ckupLinear.sol => SablierLockupLinear.sol} | 64 +++---- ...Tranched.sol => SablierLockupTranched.sol} | 64 +++---- ...{SablierV2Lockup.sol => SablierLockup.sol} | 148 +++++++-------- ...escriptor.sol => ILockupNFTDescriptor.sol} | 6 +- ...SablierV2Lockup.sol => ISablierLockup.sol} | 14 +- ...pDynamic.sol => ISablierLockupDynamic.sol} | 6 +- ...kupLinear.sol => ISablierLockupLinear.sol} | 6 +- ...ranched.sol => ISablierLockupTranched.sol} | 6 +- src/core/libraries/Errors.sol | 90 +++++---- src/core/libraries/Helpers.sol | 58 +++--- src/core/libraries/NFTSVG.sol | 14 +- src/core/types/DataTypes.sol | 28 +-- ...BatchLockup.sol => SablierBatchLockup.sol} | 86 ++++----- ...lierV2MerkleLL.sol => SablierMerkleLL.sol} | 34 ++-- ...lierV2MerkleLT.sol => SablierMerkleLT.sol} | 38 ++-- ...ory.sol => SablierMerkleLockupFactory.sol} | 38 ++-- ...rkleLockup.sol => SablierMerkleLockup.sol} | 45 +++-- ...atchLockup.sol => ISablierBatchLockup.sol} | 90 ++++----- ...ierV2MerkleLL.sol => ISablierMerkleLL.sol} | 12 +- ...ierV2MerkleLT.sol => ISablierMerkleLT.sol} | 12 +- ...kleLockup.sol => ISablierMerkleLockup.sol} | 6 +- ...ry.sol => ISablierMerkleLockupFactory.sol} | 40 ++-- src/periphery/libraries/Errors.sol | 20 +- src/periphery/types/DataTypes.sol | 12 +- test/Base.t.sol | 82 ++++----- test/core/fork/Fork.t.sol | 6 +- test/core/fork/LockupDynamic.t.sol | 2 +- test/core/fork/LockupLinear.t.sol | 2 +- test/core/fork/LockupTranched.t.sol | 2 +- test/core/fork/NFTDescriptor.t.sol | 139 +++++++++++--- .../lockup-dynamic/LockupDynamic.t.sol | 8 +- .../concrete/lockup-dynamic/constructor.t.sol | 12 +- .../createWithDurations.t.sol | 14 +- .../createWithTimestamps.t.sol | 28 ++- .../get-segments/getSegments.t.sol | 2 +- .../lockup-dynamic/get-stream/getStream.t.sol | 2 +- .../get-timestamps/getTimestamps.t.sol | 2 +- .../lockup-dynamic/token-uri/tokenURI.t.sol | 2 +- .../concrete/lockup-linear/LockupLinear.t.sol | 8 +- .../concrete/lockup-linear/constructor.t.sol | 12 +- .../createWithDurations.t.sol | 12 +- .../createWithTimestamps.t.sol | 24 +-- .../get-cliff-time/getCliffTime.t.sol | 2 +- .../lockup-linear/get-stream/getStream.t.sol | 2 +- .../get-timestamps/getTimestamps.t.sol | 2 +- .../lockup-linear/token-uri/tokenURI.t.sol | 2 +- .../lockup-tranched/LockupTranched.t.sol | 8 +- .../lockup-tranched/constructor.t.sol | 12 +- .../createWithDurations.t.sol | 14 +- .../createWithTimestamps.t.sol | 28 ++- .../get-stream/getStream.t.sol | 2 +- .../get-timestamps/getTimestamps.t.sol | 2 +- .../get-tranches/getTranches.t.sol | 2 +- .../lockup-tranched/token-uri/tokenURI.t.sol | 2 +- .../lockup/allow-to-hook/allowToHook.t.sol | 4 +- .../concrete/lockup/burn/burn.t.sol | 16 +- .../cancel-multiple/cancelMultiple.t.sol | 28 ++- .../concrete/lockup/cancel/cancel.t.sol | 26 ++- .../concrete/lockup/get-asset/getAsset.t.sol | 2 +- .../getDepositedAmount.t.sol | 2 +- .../lockup/get-end-time/getEndTime.t.sol | 2 +- .../getRefundedAmount.t.sol | 2 +- .../lockup/get-sender/getSender.t.sol | 2 +- .../lockup/get-start-time/getStartTime.t.sol | 2 +- .../getWithdrawnAmount.t.sol | 2 +- .../lockup/is-cancelable/isCancelable.t.sol | 2 +- .../concrete/lockup/is-cold/isCold.t.sol | 2 +- .../lockup/is-depleted/isDepleted.t.sol | 2 +- .../is-transferable/isTransferable.t.sol | 2 +- .../concrete/lockup/is-warm/isWarm.t.sol | 2 +- .../refundableAmountOf.t.sol | 2 +- .../concrete/lockup/renounce/renounce.t.sol | 18 +- .../set-nft-descriptor/setNFTDescriptor.t.sol | 12 +- .../concrete/lockup/status-of/statusOf.t.sol | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 2 +- .../lockup/transfer-from/transferFrom.t.sol | 4 +- .../lockup/was-canceled/wasCanceled.t.sol | 2 +- .../withdrawMaxAndTransfer.t.sol | 16 +- .../withdraw-multiple/withdrawMultiple.t.sol | 18 +- .../concrete/lockup/withdraw/withdraw.t.sol | 27 ++- .../withdrawableAmountOf.t.sol | 2 +- .../nft-descriptor/generateAccentColor.t.sol | 2 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 20 +- .../fuzz/lockup-dynamic/LockupDynamic.t.sol | 8 +- .../lockup-dynamic/createWithDurations.t.sol | 2 +- .../lockup-dynamic/createWithTimestamps.t.sol | 14 +- .../fuzz/lockup-linear/LockupLinear.t.sol | 8 +- .../lockup-linear/createWithDurations.t.sol | 6 +- .../lockup-linear/createWithTimestamps.t.sol | 12 +- .../fuzz/lockup-tranched/LockupTranched.t.sol | 8 +- .../lockup-tranched/createWithDurations.t.sol | 2 +- .../createWithTimestamps.t.sol | 14 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 2 +- .../shared/lockup-linear/LockupLinear.t.sol | 2 +- .../lockup-tranched/LockupTranched.t.sol | 2 +- .../integration/shared/lockup/Lockup.t.sol | 10 +- test/core/invariant/Lockup.t.sol | 6 +- test/core/invariant/LockupDynamic.t.sol | 4 +- test/core/invariant/LockupLinear.t.sol | 6 +- test/core/invariant/LockupTranched.t.sol | 4 +- .../handlers/LockupDynamicCreateHandler.sol | 15 +- .../handlers/LockupDynamicHandler.sol | 6 +- .../core/invariant/handlers/LockupHandler.sol | 8 +- .../handlers/LockupLinearCreateHandler.sol | 15 +- .../handlers/LockupLinearHandler.sol | 6 +- .../handlers/LockupTranchedCreateHandler.sol | 21 +-- .../handlers/LockupTranchedHandler.sol | 6 +- .../nft-descriptor/NFTDescriptor.t.sol | 4 +- .../nft-descriptor/generateDescription.t.sol | 6 +- .../nft-descriptor/generateName.t.sol | 14 +- .../concrete/nft-descriptor/generateSVG.t.sol | 18 +- test/mocks/Hooks.sol | 6 +- test/mocks/NFTDescriptorMock.sol | 14 +- test/periphery/Periphery.t.sol | 14 +- test/periphery/fork/Fork.t.sol | 13 +- .../fork/merkle-lockup/MerkleLL.t.sol | 27 ++- .../fork/merkle-lockup/MerkleLT.t.sol | 27 ++- .../createWithDurationsLD.t.sol | 6 +- .../createWithDurationsLL.t.sol | 6 +- .../createWithDurationsLT.t.sol | 6 +- .../createWithTimestampsLD.t.sol | 6 +- .../createWithTimestamps.t.sol | 6 +- .../createWithTimestampsLT.t.sol | 6 +- .../merkle-lockup/MerkleLockup.t.sol | 20 +- .../create-merkle-ll/createMerkleLL.t.sol | 6 +- .../create-merkle-lt/createMerkleLT.t.sol | 6 +- .../merkle-lockup/ll/claim/claim.t.sol | 12 +- .../merkle-lockup/ll/clawback/clawback.t.sol | 6 +- .../ll/constructor/constructor.t.sol | 5 +- .../ll/has-expired/hasExpired.t.sol | 4 +- .../merkle-lockup/lt/claim/claim.t.sol | 20 +- .../merkle-lockup/lt/clawback/clawback.t.sol | 6 +- .../lt/constructor/constructor.t.sol | 6 +- .../lt/has-expired/hasExpired.t.sol | 4 +- test/utils/Calculations.sol | 8 +- test/utils/Defaults.sol | 2 +- test/utils/DeployOptimized.sol | 117 ++++++------ test/utils/Events.sol | 20 +- test/utils/Precompiles.t.sol | 34 ++-- 184 files changed, 1638 insertions(+), 1576 deletions(-) rename benchmark/results/{SablierV2BatchLockup.md => SablierBatchLockup.md} (100%) rename benchmark/results/{SablierV2LockupDynamic.md => SablierLockupDynamic.md} (100%) rename benchmark/results/{SablierV2LockupLinear.md => SablierLockupLinear.md} (100%) rename benchmark/results/{SablierV2LockupTranched.md => SablierLockupTranched.md} (100%) rename src/core/{SablierV2NFTDescriptor.sol => LockupNFTDescriptor.sol} (78%) rename src/core/{SablierV2LockupDynamic.sol => SablierLockupDynamic.sol} (84%) rename src/core/{SablierV2LockupLinear.sol => SablierLockupLinear.sol} (79%) rename src/core/{SablierV2LockupTranched.sol => SablierLockupTranched.sol} (76%) rename src/core/abstracts/{SablierV2Lockup.sol => SablierLockup.sol} (84%) rename src/core/interfaces/{ISablierV2NFTDescriptor.sol => ILockupNFTDescriptor.sol} (89%) rename src/core/interfaces/{ISablierV2Lockup.sol => ISablierLockup.sol} (97%) rename src/core/interfaces/{ISablierV2LockupDynamic.sol => ISablierLockupDynamic.sol} (97%) rename src/core/interfaces/{ISablierV2LockupLinear.sol => ISablierLockupLinear.sol} (97%) rename src/core/interfaces/{ISablierV2LockupTranched.sol => ISablierLockupTranched.sol} (97%) rename src/periphery/{SablierV2BatchLockup.sol => SablierBatchLockup.sol} (79%) rename src/periphery/{SablierV2MerkleLL.sol => SablierMerkleLL.sol} (74%) rename src/periphery/{SablierV2MerkleLT.sol => SablierMerkleLT.sol} (85%) rename src/periphery/{SablierV2MerkleLockupFactory.sol => SablierMerkleLockupFactory.sol} (75%) rename src/periphery/abstracts/{SablierV2MerkleLockup.sol => SablierMerkleLockup.sol} (81%) rename src/periphery/interfaces/{ISablierV2BatchLockup.sol => ISablierBatchLockup.sol} (66%) rename src/periphery/interfaces/{ISablierV2MerkleLL.sol => ISablierMerkleLL.sol} (80%) rename src/periphery/interfaces/{ISablierV2MerkleLT.sol => ISablierMerkleLT.sol} (82%) rename src/periphery/interfaces/{ISablierV2MerkleLockup.sol => ISablierMerkleLockup.sol} (94%) rename src/periphery/interfaces/{ISablierV2MerkleLockupFactory.sol => ISablierMerkleLockupFactory.sol} (72%) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb01c70e6..92e8d49a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,101 +4,101 @@ All notable changes to this project will be documented in this file. The format is based on [Common Changelog](https://common-changelog.org/). -[1.2.0]: https://github.com/sablier-labs/v2-core/compare/v1.1.2...v1.2.0 -[1.1.2]: https://github.com/sablier-labs/v2-core/compare/v1.1.1...v1.1.2 -[1.1.1]: https://github.com/sablier-labs/v2-core/compare/v1.1.0...v1.1.1 -[1.1.0]: https://github.com/sablier-labs/v2-core/compare/v1.0.2...v1.1.0 -[1.0.2]: https://github.com/sablier-labs/v2-core/compare/v1.0.1...v1.0.2 -[1.0.1]: https://github.com/sablier-labs/v2-core/compare/v1.0.0...v1.0.1 -[1.0.0]: https://github.com/sablier-labs/v2-core/releases/tag/v1.0.0 +[1.2.0]: https://github.com/sablier-labs/lockup/compare/v1.1.2...v1.2.0 +[1.1.2]: https://github.com/sablier-labs/lockup/compare/v1.1.1...v1.1.2 +[1.1.1]: https://github.com/sablier-labs/lockup/compare/v1.1.0...v1.1.1 +[1.1.0]: https://github.com/sablier-labs/lockup/compare/v1.0.2...v1.1.0 +[1.0.2]: https://github.com/sablier-labs/lockup/compare/v1.0.1...v1.0.2 +[1.0.1]: https://github.com/sablier-labs/lockup/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/sablier-labs/lockup/releases/tag/v1.0.0 ## [1.2.0] - 2024-07-04 ### Changed -- **Breaking:** move common logic into `Lockup` contract ([#784](https://github.com/sablier-labs/v2-core/pull/784), - [#813](https://github.com/sablier-labs/v2-core/pull/813), [#850](https://github.com/sablier-labs/v2-core/pull/850), - [#941](https://github.com/sablier-labs/v2-core/pull/941)) -- **Breaking:** use a new hook system ([#951](https://github.com/sablier-labs/v2-core/pull/951)) +- **Breaking:** move common logic into `Lockup` contract ([#784](https://github.com/sablier-labs/lockup/pull/784), + [#813](https://github.com/sablier-labs/lockup/pull/813), [#850](https://github.com/sablier-labs/lockup/pull/850), + [#941](https://github.com/sablier-labs/lockup/pull/941)) +- **Breaking:** use a new hook system ([#951](https://github.com/sablier-labs/lockup/pull/951)) - Replace `ISablierV2Recipient` with `ISablierLockupRecipient` hook interface - Remove `try..catch` block from hook calls - Allow only supported characters in NFT Descriptor asset symbols - ([#945](https://github.com/sablier-labs/v2-core/pull/945), [#960](https://github.com/sablier-labs/v2-core/pull/960), - [#949](https://github.com/sablier-labs/v2-core/pull/949)) -- Bump build dependencies ([#806](https://github.com/sablier-labs/v2-core/pull/806), - [#942](https://github.com/sablier-labs/v2-core/pull/942), [#944](https://github.com/sablier-labs/v2-core/pull/944)) -- Change permissions of `withdraw` function to public ([#785](https://github.com/sablier-labs/v2-core/pull/785)) -- Disallow zero `startTime` ([#813](https://github.com/sablier-labs/v2-core/pull/813), - [#852](https://github.com/sablier-labs/v2-core/pull/852)) + ([#945](https://github.com/sablier-labs/lockup/pull/945), [#960](https://github.com/sablier-labs/lockup/pull/960), + [#949](https://github.com/sablier-labs/lockup/pull/949)) +- Bump build dependencies ([#806](https://github.com/sablier-labs/lockup/pull/806), + [#942](https://github.com/sablier-labs/lockup/pull/942), [#944](https://github.com/sablier-labs/lockup/pull/944)) +- Change permissions of `withdraw` function to public ([#785](https://github.com/sablier-labs/lockup/pull/785)) +- Disallow zero `startTime` ([#813](https://github.com/sablier-labs/lockup/pull/813), + [#852](https://github.com/sablier-labs/lockup/pull/852)) - Rename create functions `createWithTimestamps` and `createWithDurations` across all lockup contracts - ([#798](https://github.com/sablier-labs/v2-core/pull/798)) -- Switch to Bun ([#775](https://github.com/sablier-labs/v2-core/pull/775)) -- Use Solidity v0.8.26 ([#944](https://github.com/sablier-labs/v2-core/pull/944)) + ([#798](https://github.com/sablier-labs/lockup/pull/798)) +- Switch to Bun ([#775](https://github.com/sablier-labs/lockup/pull/775)) +- Use Solidity v0.8.26 ([#944](https://github.com/sablier-labs/lockup/pull/944)) ### Added -- Add Lockup Tranched contract ([#817](https://github.com/sablier-labs/v2-core/pull/817)) -- Add `precompiles` in the NPM release ([#841](https://github.com/sablier-labs/v2-core/pull/841)) +- Add Lockup Tranched contract ([#817](https://github.com/sablier-labs/lockup/pull/817)) +- Add `precompiles` in the NPM release ([#841](https://github.com/sablier-labs/lockup/pull/841)) - Add return value in `withdrawMax` and `withdrawMaxAndTransfer` - ([#961](https://github.com/sablier-labs/v2-core/pull/961)) + ([#961](https://github.com/sablier-labs/lockup/pull/961)) ### Removed -- **Breaking:** remove protocol fee ([#839](https://github.com/sablier-labs/v2-core/pull/839)) -- Remove flash loan abstract contract ([#779](https://github.com/sablier-labs/v2-core/pull/779)) -- Remove `to` from `withdrawMultiple` function ([#785](https://github.com/sablier-labs/v2-core/pull/785)) +- **Breaking:** remove protocol fee ([#839](https://github.com/sablier-labs/lockup/pull/839)) +- Remove flash loan abstract contract ([#779](https://github.com/sablier-labs/lockup/pull/779)) +- Remove `to` from `withdrawMultiple` function ([#785](https://github.com/sablier-labs/lockup/pull/785)) ## [1.1.2] - 2023-12-19 ### Changed -- Use Solidity v0.8.23 ([#758](https://github.com/sablier-labs/v2-core/pull/758)) +- Use Solidity v0.8.23 ([#758](https://github.com/sablier-labs/lockup/pull/758)) ## [1.1.1] - 2023-12-16 ### Changed - Bump package version for NPM release - ([88db61](https://github.com/sablier-labs/v2-core/tree/88db61bcf193ef9494b31c883ed2c9ad997a1271)) + ([88db61](https://github.com/sablier-labs/lockup/tree/88db61bcf193ef9494b31c883ed2c9ad997a1271)) ## [1.1.0] - 2023-12-15 ### Changed -- **Breaking**: Remove ability to cancel for recipients ([#710](https://github.com/sablier-labs/v2-core/pull/710)) -- Move `isWarm` and `isCold` to `SablierV2Lockup` ([#664](https://github.com/sablier-labs/v2-core/pull/664)) +- **Breaking**: Remove ability to cancel for recipients ([#710](https://github.com/sablier-labs/lockup/pull/710)) +- Move `isWarm` and `isCold` to `SablierV2Lockup` ([#664](https://github.com/sablier-labs/lockup/pull/664)) - Replace the streamed amount with the deposit amount in the NFT descriptor - ([#692](https://github.com/sablier-labs/v2-core/pull/692)) -- Simplify `renounce` and `withdraw` implementations ([#683](https://github.com/sablier-labs/v2-core/pull/683), - [#705](https://github.com/sablier-labs/v2-core/pull/705)) -- Update import paths to use Node.js dependencies ([#734](https://github.com/sablier-labs/v2-core/pull/734)) -- Use Solidity v0.8.21 ([#688](https://github.com/sablier-labs/v2-core/pull/688)) + ([#692](https://github.com/sablier-labs/lockup/pull/692)) +- Simplify `renounce` and `withdraw` implementations ([#683](https://github.com/sablier-labs/lockup/pull/683), + [#705](https://github.com/sablier-labs/lockup/pull/705)) +- Update import paths to use Node.js dependencies ([#734](https://github.com/sablier-labs/lockup/pull/734)) +- Use Solidity v0.8.21 ([#688](https://github.com/sablier-labs/lockup/pull/688)) ### Added -- Add `ERC-4906` metadata update in `transferFrom` ([#686](https://github.com/sablier-labs/v2-core/pull/686)) -- Add `transferable` boolean flag ([#668](https://github.com/sablier-labs/v2-core/pull/668)) +- Add `ERC-4906` metadata update in `transferFrom` ([#686](https://github.com/sablier-labs/lockup/pull/686)) +- Add `transferable` boolean flag ([#668](https://github.com/sablier-labs/lockup/pull/668)) ### Removed - Remove `@openzeppelin/contracts` from Node.js peer dependencies - ([#694](https://github.com/sablier-labs/v2-core/pull/694)) + ([#694](https://github.com/sablier-labs/lockup/pull/694)) ## [1.0.2] - 2023-08-14 ### Changed -- Update `@prb/math` import paths to contain `src/` ([#648](https://github.com/sablier-labs/v2-core/pull/648)) +- Update `@prb/math` import paths to contain `src/` ([#648](https://github.com/sablier-labs/lockup/pull/648)) ## [1.0.1] - 2023-07-13 ### Changed -- Optimize use of variables in `tokenURI` ([#617](https://github.com/sablier-labs/v2-core/pull/617)) +- Optimize use of variables in `tokenURI` ([#617](https://github.com/sablier-labs/lockup/pull/617)) ### Fixed -- Fix data URI scheme in `tokenURI` ([#617](https://github.com/sablier-labs/v2-core/pull/617)) +- Fix data URI scheme in `tokenURI` ([#617](https://github.com/sablier-labs/lockup/pull/617)) ## [1.0.0] - 2023-07-07 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cac15041c..797db37c1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,10 @@ # Contributing -Feel free to dive in! [Open](https://github.com/sablier-labs/v2-core/issues/new) an issue, -[start](https://github.com/sablier-labs/v2-core/discussions/new) a discussion or submit a PR. For any informal concerns +Feel free to dive in! [Open](https://github.com/sablier-labs/lockup/issues/new) an issue, +[start](https://github.com/sablier-labs/lockup/discussions/new) a discussion or submit a PR. For any informal concerns or feedback, please join our [Discord server](https://discord.gg/bSwRCwWRsT). -Contributions to Sablier V2 Core are welcome by anyone interested in writing more tests, improving readability, +Contributions to Sablier Lockup are welcome by anyone interested in writing more tests, improving readability, optimizing for gas efficiency, or extending the protocol via new features. ## Pre Requisites @@ -23,7 +23,7 @@ In addition, familiarity with [Solidity](https://soliditylang.org/) is requisite Clone this repository including submodules: ```shell -$ git clone --recurse-submodules -j8 git@github.com:sablier-labs/v2-core.git +$ git clone --recurse-submodules -j8 git@github.com:sablier-labs/lockup.git ``` Then, inside the project's directory, run this to install the Node.js dependencies and build the contracts: diff --git a/LICENSE.md b/LICENSE.md index f89bb709d..b6fdb6d23 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -9,7 +9,7 @@ Parameters Licensor: Sablier Labs Ltd -Licensed Work: Sablier V2 Core The Licensed Work is (C) 2024 Sablier Labs Ltd +Licensed Work: Sablier Lockup The Licensed Work is (C) 2024 Sablier Labs Ltd Additional Use Grant: Any uses listed and defined at v2-core-license-grants.sablier.eth diff --git a/README.md b/README.md index 781609aca..836d8aad1 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,20 @@ -# Sablier V2 Core [![Github Actions][gha-badge]][gha] [![Coverage][codecov-badge]][codecov] [![Foundry][foundry-badge]][foundry] [![Discord][discord-badge]][discord] +# Sablier Lockup [![Github Actions][gha-badge]][gha] [![Coverage][codecov-badge]][codecov] [![Foundry][foundry-badge]][foundry] [![Discord][discord-badge]][discord] -[gha]: https://github.com/sablier-labs/v2-core/actions -[gha-badge]: https://github.com/sablier-labs/v2-core/actions/workflows/ci.yml/badge.svg -[codecov]: https://codecov.io/gh/sablier-labs/v2-core -[codecov-badge]: https://codecov.io/gh/sablier-labs/v2-core/branch/main/graph/badge.svg +[gha]: https://github.com/sablier-labs/lockup/actions +[gha-badge]: https://github.com/sablier-labs/lockup/actions/workflows/ci.yml/badge.svg +[codecov]: https://codecov.io/gh/sablier-labs/lockup +[codecov-badge]: https://codecov.io/gh/sablier-labs/lockup/branch/main/graph/badge.svg [discord]: https://discord.gg/bSwRCwWRsT [discord-badge]: https://dcbadge.vercel.app/api/server/bSwRCwWRsT?style=flat [foundry]: https://getfoundry.sh [foundry-badge]: https://img.shields.io/badge/Built%20with-Foundry-FFDB1C.svg -This repository contains the core smart contracts of the Sablier V2 Protocol. For higher-level logic, see the -[sablier-labs/v2-periphery](https://github.com/sablier-labs/v2-periphery) repository. - In-depth documentation is available at [docs.sablier.com](https://docs.sablier.com). ## Background -Sablier V2 is a token distribution protocol used by DAOs and businesses for vesting, payroll, airdrops, and more. Our -flagship model is the linear stream, which distributes assets on a continuous, by-the-second basis. +Sablier Lockup Protocol is a token distribution protocol used by DAOs and businesses for vesting, payroll, airdrops, and +more. Our flagship model is the linear stream, which distributes assets on a continuous, by-the-second basis. The way it works is that the sender of a payment stream first deposits a specific amount of ERC-20 tokens in a contract. Then, the contract progressively allocates the funds to the recipient, who can access them as they become available over @@ -30,16 +27,16 @@ of tokens deposited. This is the recommended approach. -Install Sablier V2 Core using your favorite package manager, e.g., with Bun: +Install Lockup using your favorite package manager, e.g., with Bun: ```shell -bun add @sablier/v2-core +bun add @sablier/lockup ``` Then, if you are using Foundry, you need to add these to your `remappings.txt` file: ```text -@sablier/v2-core/=node_modules/@sablier/v2-core/ +@sablier/lockup/=node_modules/@sablier/lockup/ @openzeppelin/contracts/=node_modules/@openzeppelin/contracts/ @prb/math/=node_modules/@prb/math/ ``` @@ -51,7 +48,7 @@ This installation method is not recommended, but it is available for those who p First, install the submodule using Forge: ```shell -forge install --no-commit sablier-labs/v2-core +forge install --no-commit sablier-labs/lockup ``` Second, install the project's dependencies: @@ -63,21 +60,21 @@ forge install --no-commit OpenZeppelin/openzeppelin-contracts@v5.0.2 PaulRBerg/p Finally, add these to your `remappings.txt` file: ```text -@sablier/v2-core/=lib/v2-core/ +@sablier/lockup/=lib/lockup/ @openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ @prb/math/=lib/prb-math/ ``` ## Usage -This is just a glimpse of Sablier V2 Core. For more guides and examples, see the +This is just a glimpse of Sablier Lockup. For more guides and examples, see the [documentation](https://docs.sablier.com). ```solidity -import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "@sablier/lockup/src/interfaces/ISablierLockupLinear.sol"; contract MyContract { - ISablierV2LockupLinear sablier; + ISablierLockupLinear lockup; function buildSomethingWithSablier() external { // ... @@ -87,7 +84,7 @@ contract MyContract { ## Architecture -V2 Core uses a singleton-style architecture, where all streams are managed in the `LockupLinear`, `LockupDynamic` and +Lockup uses a singleton-style architecture, where all streams are managed in the `LockupLinear`, `LockupDynamic` and `LockupTranched` contracts. That is, Sablier does not deploy a new contract for each stream. It bundles all streams into a single contract, which is more gas-efficient and easier to maintain. @@ -97,12 +94,12 @@ docs, as well as these [diagrams](https://docs.sablier.com/contracts/v2/referenc ### Branching Tree Technique You may notice that some test files are accompanied by `.tree` files. This is called the Branching Tree Technique, and -it is explained in depth [here](https://github.com/sablier-labs/v2-core/wiki/Tests#branching-tree-technique). +it is explained in depth [here](https://github.com/sablier-labs/lockup/wiki/Tests#branching-tree-technique). ## Deployments The list of all deployment addresses can be found [here](https://docs.sablier.com). For guidance on the deploy scripts, -see the [Deployments wiki](https://github.com/sablier-labs/v2-core/wiki/Deployments). +see the [Deployments wiki](https://github.com/sablier-labs/lockup/wiki/Deployments). ## Security @@ -114,15 +111,15 @@ bug bounty program per the terms outlined in the aforementioned policy. ## Contributing -Feel free to dive in! [Open](https://github.com/sablier-labs/v2-core/issues/new) an issue, -[start](https://github.com/sablier-labs/v2-core/discussions/new) a discussion or submit a PR. For any informal concerns +Feel free to dive in! [Open](https://github.com/sablier-labs/lockup/issues/new) an issue, +[start](https://github.com/sablier-labs/lockup/discussions/new) a discussion or submit a PR. For any informal concerns or feedback, please join our [Discord server](https://discord.gg/bSwRCwWRsT). For guidance on how to create PRs, see the [CONTRIBUTING](./CONTRIBUTING.md) guide. ## License -The primary license for Sablier V2 Core is the Business Source License 1.1 (`BUSL-1.1`), see +The primary license for Sablier Lockup is the Business Source License 1.1 (`BUSL-1.1`), see [`LICENSE.md`](./LICENSE.md). However, there are exceptions: - All files in `src/interfaces/` and `src/types` are licensed under `GPL-3.0-or-later`, see diff --git a/SECURITY.md b/SECURITY.md index dbf5eb603..5ed9da5d5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -9,8 +9,8 @@ report it to us. ### Overview -Starting on July 1, 2023, the [sablier-labs/v2-core](https://github.com/sablier-labs/v2-core) repository is subject to -the Sablier V2 Bug Bounty (the "Program") to incentivize responsible bug disclosure. +Starting on July 1, 2023, the [sablier-labs/lockup](https://github.com/sablier-labs/lockup) repository is subject to the +Sablier Bug Bounty (the "Program") to incentivize responsible bug disclosure. We are limiting the scope of the Program to critical and high severity bugs, and are offering a reward of up to $100,000. Happy hunting! @@ -25,8 +25,8 @@ The Program does NOT cover the following: - External code in `node_modules`, except for code that is explicitly used by a deployed contract located in the [src](./src) directory. - Contract deployments on test networks, such as Sepolia. -- Bugs in third-party contracts or platforms interacting with Sablier V2 Core. -- Previously reported or discovered vulnerabilities in contracts built by third parties on Sablier V2 Core. +- Bugs in third-party contracts or platforms interacting with Sablier Lockup. +- Previously reported or discovered vulnerabilities in contracts built by third parties on Sablier Lockup. - Bugs that have already been reported. Vulnerabilities contingent upon the occurrence of any of the following also are outside the scope of this Program: @@ -42,7 +42,7 @@ Vulnerabilities contingent upon the occurrence of any of the following also are ### Assumptions -Sablier V2 Core has been developed with a number of technical assumptions in mind. For a disclosure to qualify as a +Sablier Lockup has been developed with a number of technical assumptions in mind. For a disclosure to qualify as a vulnerability, it must adhere to these assumptions as well: - The immutable variables `MAX_SEGMENT_COUNT` and `MAX_TRANCHE_COUNT` have values that cannot lead to an overflow of the @@ -89,8 +89,8 @@ publicly for their contribution if they so choose. To qualify for a reward under this Program, you must adhere to the following criteria: - Identify a previously unreported, non-public vulnerability that could result in the loss or freeze of any ERC-20 asset - in Sablier V2 (but not on any third-party platform interacting with Sablier V2) and that is within the scope of this - Program. + in Sablier Lockup (but not on any third-party platform interacting with Sablier Lockup) and that is within the scope + of this Program. - The vulnerability must be distinct from the issues covered in the [Audits](https://github.com/sablier-labs/audits). - Be the first to report the unique vulnerability to [security@sablier.com](mailto:security@sablier.com) in accordance with the disclosure requirements specified above. If multiple similar vulnerabilities are reported within a 24-hour @@ -101,7 +101,7 @@ To qualify for a reward under this Program, you must adhere to the following cri - Avoid exploiting the vulnerability in any manner, such as making it public or profiting from it (aside from the reward offered under this Program). - Make a genuine effort to prevent privacy violations, data destruction, and any interruption or degradation of Sablier - V2. + Lockup. - Submit only one vulnerability per submission, unless chaining vulnerabilities is necessary to demonstrate the impact of any of them. - Do not submit a vulnerability that stems from an underlying issue for which a reward has already been paid under this diff --git a/benchmark/BatchLockup.Gas.t.sol b/benchmark/BatchLockup.Gas.t.sol index 1cf8e5d2e..aafd0da24 100644 --- a/benchmark/BatchLockup.Gas.t.sol +++ b/benchmark/BatchLockup.Gas.t.sol @@ -26,7 +26,7 @@ contract BatchLockup_Gas_Test is Benchmark_Test { function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2BatchLockup.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierBatchLockup.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol index 7e8792532..4e249e816 100644 --- a/benchmark/Benchmark.t.sol +++ b/benchmark/Benchmark.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2Lockup } from "../src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "../src/core/interfaces/ISablierLockup.sol"; import { Base_Test } from "../test/Base.t.sol"; /// @notice Benchmark contract with common logic needed by all tests. @@ -24,7 +24,7 @@ abstract contract Benchmark_Test is Base_Test { /// @dev A variable used to store the content to append to the results file. string internal contentToAppend; - ISablierV2Lockup internal lockup; + ISablierLockup internal lockup; uint256[7] internal streamIds = [50, 51, 52, 53, 54, 55, 56]; diff --git a/benchmark/LockupDynamic.Gas.t.sol b/benchmark/LockupDynamic.Gas.t.sol index a1945265c..315dd7786 100644 --- a/benchmark/LockupDynamic.Gas.t.sol +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -33,7 +33,7 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupDynamic.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupDynamic.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ diff --git a/benchmark/LockupLinear.Gas.t.sol b/benchmark/LockupLinear.Gas.t.sol index 617d97f7c..457821882 100644 --- a/benchmark/LockupLinear.Gas.t.sol +++ b/benchmark/LockupLinear.Gas.t.sol @@ -26,7 +26,7 @@ contract LockupLinear_Gas_Test is Benchmark_Test { function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupLinear.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupLinear.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol index bdb6cdd7f..e802d3516 100644 --- a/benchmark/LockupTranched.Gas.t.sol +++ b/benchmark/LockupTranched.Gas.t.sol @@ -33,7 +33,7 @@ contract LockupTranched_Gas_Test is Benchmark_Test { function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierV2LockupTranched.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupTranched.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ diff --git a/benchmark/results/SablierV2BatchLockup.md b/benchmark/results/SablierBatchLockup.md similarity index 100% rename from benchmark/results/SablierV2BatchLockup.md rename to benchmark/results/SablierBatchLockup.md diff --git a/benchmark/results/SablierV2LockupDynamic.md b/benchmark/results/SablierLockupDynamic.md similarity index 100% rename from benchmark/results/SablierV2LockupDynamic.md rename to benchmark/results/SablierLockupDynamic.md diff --git a/benchmark/results/SablierV2LockupLinear.md b/benchmark/results/SablierLockupLinear.md similarity index 100% rename from benchmark/results/SablierV2LockupLinear.md rename to benchmark/results/SablierLockupLinear.md diff --git a/benchmark/results/SablierV2LockupTranched.md b/benchmark/results/SablierLockupTranched.md similarity index 100% rename from benchmark/results/SablierV2LockupTranched.md rename to benchmark/results/SablierLockupTranched.md diff --git a/foundry.toml b/foundry.toml index 373e8e17e..7b82c742a 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,14 +9,14 @@ ] gas_limit = 9223372036854775807 gas_reports = [ - "SablierV2BatchLockup", - "SablierV2LockupDynamic", - "SablierV2LockupLinear", - "SablierV2LockupTranched", - "SablierV2MerkleLL", - "SablierV2MerkleLockupFactory", - "SablierV2MerkleLT", - "SablierV2NFTDescriptor", + "LockupNFTDescriptor", + "SablierBatchLockup", + "SablierLockupDynamic", + "SablierLockupLinear", + "SablierLockupTranched", + "SablierMerkleLL", + "SablierMerkleLockupFactory", + "SablierMerkleLT", ] optimizer = true optimizer_runs = 1000 @@ -78,10 +78,10 @@ ] [profile.smt.model_checker.contracts] - "src/SablierV2LockupDynamic.sol" = ["SablierV2LockupDynamic"] - "src/SablierV2LockupLinear.sol" = ["SablierV2LockupLinear"] - "src/SablierV2LockupTranched.sol" = ["SablierV2LockupTranched"] - "src/SablierV2NFTDescriptor.sol" = ["SablierV2NFTDescriptor"] + "src/LockupNFTDescriptor.sol" = ["LockupNFTDescriptor"] + "src/SablierLockupDynamic.sol" = ["SablierLockupDynamic"] + "src/SablierLockupLinear.sol" = ["SablierLockupLinear"] + "src/SablierLockupTranched.sol" = ["SablierLockupTranched"] # Test the optimized contracts without re-compiling them [profile.test-optimized] @@ -90,7 +90,7 @@ [doc] ignore = ["**/*.t.sol"] out = "docs" - repository = "https://github.com/sablier-labs/v2-core" + repository = "https://github.com/sablier-labs/lockup" [fmt] bracket_spacing = true diff --git a/package.json b/package.json index c8138bf07..c0f23ed57 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@sablier/v2-core", - "description": "Core smart contracts of the Sablier V2 token distribution protocol", + "name": "@sablier/lockup", + "description": "Core smart contracts of the Lockup token distribution protocol", "license": "BUSL-1.1", "version": "1.2.0", "author": { @@ -8,7 +8,7 @@ "url": "https://sablier.com" }, "bugs": { - "url": "https://github.com/sablier-labs/v2-core/issues" + "url": "https://github.com/sablier-labs/lockup/issues" }, "dependencies": { "@openzeppelin/contracts": "5.0.2", @@ -29,7 +29,7 @@ "CHANGELOG.md", "LICENSE-GPL.md" ], - "homepage": "https://github.com/sablier-labs/v2-core#readme", + "homepage": "https://github.com/sablier-labs/lockup#readme", "keywords": [ "asset-distribution", "asset-streaming", @@ -38,10 +38,12 @@ "cryptoassets", "ethereum", "foundry", + "lockup", "money-streaming", "real-time-finance", "sablier", "sablier-v2", + "sablier-lockup", "smart-contracts", "solidity", "token-distribution", @@ -56,7 +58,7 @@ "publishConfig": { "access": "public" }, - "repository": "github.com/sablier-labs/v2-core", + "repository": "github.com/sablier-labs/lockup", "scripts": { "benchmark": "bun run build:optimized && FOUNDRY_PROFILE=benchmark forge test --mt testGas && bun run prettier:write", "build": "forge build", diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index d432d6d34..0dcf85b33 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -2,13 +2,13 @@ // solhint-disable max-line-length,no-inline-assembly,reason-string pragma solidity >=0.8.22; -import { ISablierV2LockupDynamic } from "../src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; -import { ISablierV2BatchLockup } from "../src/periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLockupFactory } from "../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ILockupNFTDescriptor } from "../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; +import { ISablierLockupDynamic } from "../src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "../src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierBatchLockup } from "../src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleLockupFactory } from "../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; /// @notice This is useful for external integrations seeking to test against the exact deployed bytecode, as recompiling /// with via IR enabled would be time-consuming. @@ -21,17 +21,17 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_BATCH_LOCKUP = - hex"60808060405234601557611e0a908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd3146111a357806349a32c4014610e3e578063606ef87514610b025780639e743f29146107a6578063a514f83e1461040c5763f7ca34eb1461005b575f80fd5b3461033c5761006936611512565b91909282156103e4575f905f5b8481106103b057506001600160a01b036100939116918383611a7a565b61009c83611758565b926001600160a01b035f9316925b8181106100c357604051806100bf8782611587565b0390f35b6100ce818388611a17565b6100d7906117a7565b90826100e482828a611a17565b6020016100f0906117a7565b6100fb83838b611a17565b60400161010790611643565b9389610114858583611a17565b606001610120906117bb565b61012b868684611a17565b608001610137906117bb565b610142878785611a17565b60a00161014e90611a57565b918761015b818987611a17565b60c0810161016891611926565b98610174929196611a17565b60e0019360405195610185876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101ec9261197a565b9360e08601948552366101fe916118c8565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610353575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610312575b6001925061030b8288611901565b52016100aa565b506020823d8211610340575b8161032b602093836116ff565b8101031261033c57600191516102fd565b5f80fd5b3d915061031e565b6040513d5f823e3d90fd5b919493509160206060826103a1600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102be565b916001906fffffffffffffffffffffffffffffffff6103db60406103d5878a8c611a17565b01611643565b16019201610076565b7ff8bf106c000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c576104436115c0565b61044b6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610140870201011161033c5783156103e45790915f9190825b85811061077457506001600160a01b036104be9116928484611a7a565b6104c784611758565b926001600160a01b03165f5b8581106104e857604051806100bf8782611587565b6104fb6104f6828886611a69565b6117a7565b90610512602061050c838a88611a69565b016117a7565b878561052460406103d5868585611a69565b61053a6060610534878686611a69565b016117bb565b906101006105648761055d8188610557608061053484848d611a69565b98611a69565b968c611a69565b01906001600160a01b036040519861057b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c57604051956105fa876116e3565b61060660a08201611839565b875261061460c08201611839565b602088015260e00161062590611839565b604087015260c089019586523661063b916118c8565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff1661010484015251610124830161071291602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610348575f90610742575b6001925061073b8288611901565b52016104d3565b506020823d821161076c575b8161075b602093836116ff565b8101031261033c576001915161072d565b3d915061074e565b93926001906fffffffffffffffffffffffffffffffff61079a60406103d5898b89611a69565b160194019392936104a1565b3461033c576107b436611512565b91909282156103e4575f905f5b848110610ad457506001600160a01b036107de9116918383611a7a565b6107e783611758565b926001600160a01b035f9316925b81811061080a57604051806100bf8782611587565b610815818388611a17565b61081e906117a7565b908261082b82828a611a17565b602001610837906117a7565b61084283838b611a17565b60400161084e90611643565b938961085b858583611a17565b606001610867906117bb565b610872868684611a17565b60800161087e906117bb565b610889878785611a17565b60a00161089590611a57565b91876108a2818987611a17565b60c081016108af916117c8565b986108bb929196611a17565b60e00193604051956108cc876116c6565b6001600160a01b0316865260208601966001600160a01b0316875260408601996fffffffffffffffffffffffffffffffff168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906109339261184b565b9360e0860194855236610945916118c8565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516fffffffffffffffffffffffffffffffff166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610a8b575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610348575f90610a59575b60019250610a528288611901565b52016107f5565b506020823d8211610a83575b81610a72602093836116ff565b8101031261033c5760019151610a44565b3d9150610a65565b91949350916020604082610ac5600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291610a05565b916001906fffffffffffffffffffffffffffffffff610af960406103d5878a8c611a17565b160192016107c1565b3461033c57610b1036611512565b91909282156103e4575f905f5b848110610e1057506001600160a01b03610b3a9116918383611a7a565b610b4383611758565b926001600160a01b035f9316925b818110610b6657604051806100bf8782611587565b610b718183886115d6565b610b7a906117a7565b9082610b8782828a6115d6565b602001610b93906117a7565b610b9e83838b6115d6565b604001610baa90611643565b9389610bb78585836115d6565b606001610bc3906117bb565b610bce8686846115d6565b608001610bda906117bb565b9086610be78188866115d6565b60a08101610bf491611926565b97610c009291956115d6565b60c0019260405194610c1186611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a0860193151584523690610c6a9261197a565b9260c0850193845236610c7c916118c8565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610db3575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90610d81575b60019250610d7a8288611901565b5201610b51565b506020823d8211610dab575b81610d9a602093836116ff565b8101031261033c5760019151610d6c565b3d9150610d8d565b91949350916020606082610e01600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610d2d565b916001906fffffffffffffffffffffffffffffffff610e3560406103d5878a8c6115d6565b16019201610b1d565b3461033c5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033c57610e756115c0565b610e7d6114cb565b906044359167ffffffffffffffff831161033c573660238401121561033c5782600401359267ffffffffffffffff841161033c57602481019060243691610120870201011161033c5783156103e45790915f9190825b85811061117157506001600160a01b03610ef09116928484611a7a565b610ef984611758565b926001600160a01b03165f5b858110610f1a57604051806100bf8782611587565b610f286104f6828886611915565b90610f39602061050c838a88611915565b8785610f4b60406103d5868585611915565b610f5b6060610534878686611915565b9060e0610f8487610f7d8188610f77608061053484848d611915565b98611915565b968c611915565b01906001600160a01b0360405198610f9b8a611660565b1688526001600160a01b0360208901961686526fffffffffffffffffffffffffffffffff6040890191168152606088019189835260808901931515845260a08901941515855260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60873603011261033c576040519561101a876116aa565b61102660a08201611839565b875260c00161103490611839565b602087015260c089019586523661104a916118c8565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516fffffffffffffffffffffffffffffffff166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e484015251610104830161110f91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610348575f9061113f575b600192506111388288611901565b5201610f05565b506020823d8211611169575b81611158602093836116ff565b8101031261033c576001915161112a565b3d915061114b565b93926001906fffffffffffffffffffffffffffffffff61119760406103d5898b89611915565b16019401939293610ed3565b3461033c576111b136611512565b91909282156103e4575f905f5b84811061149d57506001600160a01b036111db9116918383611a7a565b6111e483611758565b926001600160a01b035f9316925b81811061120757604051806100bf8782611587565b6112128183886115d6565b61121b906117a7565b908261122882828a6115d6565b602001611234906117a7565b61123f83838b6115d6565b60400161124b90611643565b93896112588585836115d6565b606001611264906117bb565b61126f8686846115d6565b60800161127b906117bb565b90866112888188866115d6565b60a08101611295916117c8565b976112a19291956115d6565b60c00192604051946112b286611660565b6001600160a01b0316855260208501956001600160a01b0316865260408501986fffffffffffffffffffffffffffffffff16895260608501968c885260808601921515835260a086019315158452369061130b9261184b565b9260c085019384523661131d916118c8565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516fffffffffffffffffffffffffffffffff166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611454575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610348575f90611422575b6001925061141b8288611901565b52016111f2565b506020823d821161144c575b8161143b602093836116ff565b8101031261033c576001915161140d565b3d915061142e565b9194935091602060408261148e600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b019501920186939492916113ce565b916001906fffffffffffffffffffffffffffffffff6114c260406103d5878a8c6115d6565b160192016111be565b602435906001600160a01b038216820361033c57565b9181601f8401121561033c5782359167ffffffffffffffff831161033c576020808501948460051b01011161033c57565b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc82011261033c576004356001600160a01b038116810361033c57916024356001600160a01b038116810361033c57916044359067ffffffffffffffff821161033c57611583916004016114e1565b9091565b60206040818301928281528451809452019201905f5b8181106115aa5750505090565b825184526020938401939092019160010161159d565b600435906001600160a01b038216820361033c57565b91908110156116165760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff018136030182121561033c570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b356fffffffffffffffffffffffffffffffff8116810361033c5790565b610100810190811067ffffffffffffffff82111761167d57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761167d57604052565b610120810190811067ffffffffffffffff82111761167d57604052565b6060810190811067ffffffffffffffff82111761167d57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761167d57604052565b67ffffffffffffffff811161167d5760051b60200190565b9061176282611740565b61176f60405191826116ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061179d8294611740565b0190602036910137565b356001600160a01b038116810361033c5790565b35801515810361033c5790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c57602001918160061b3603831361033c57565b35906fffffffffffffffffffffffffffffffff8216820361033c57565b359064ffffffffff8216820361033c57565b92919261185782611740565b9361186560405195866116ff565b602085848152019260061b82019181831161033c57925b8284106118895750505050565b60408483031261033c57602060409182516118a3816116aa565b6118ac8761181c565b81526118b9838801611839565b8382015281520193019261187c565b919082604091031261033c576040516118e0816116aa565b809280356001600160a01b038116810361033c578252602090810135910152565b80518210156116165760209160051b010190565b919081101561161657610120020190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561033c570180359067ffffffffffffffff821161033c5760200191606082023603831361033c57565b92919261198682611740565b9361199460405195866116ff565b606060208685815201930282019181831161033c57925b8284106119b85750505050565b60608483031261033c57604051906119cf826116e3565b6119d88561181c565b825260208501359067ffffffffffffffff8216820361033c5782602092836060950152611a0760408801611839565b60408201528152019301926119ab565b91908110156116165760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee18136030182121561033c570190565b3564ffffffffff8116810361033c5790565b919081101561161657610140020190565b9190611acf6040517f23b872dd00000000000000000000000000000000000000000000000000000000602082015233602482015230604482015283606482015260648152611ac96084826116ff565b82611c8f565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103485784915f91611c42575b5010611b3b575b50505050565b5f806040519460208601907f095ea7b3000000000000000000000000000000000000000000000000000000008252876024880152604487015260448652611b836064876116ff565b85519082855af190611b93611d14565b82611c10575b5081611c05575b5015611bad575b80611b35565b611bf8611bfd93604051907f095ea7b300000000000000000000000000000000000000000000000000000000602083015260248201525f604482015260448152611ac96064826116ff565b611c8f565b5f8080611ba7565b90503b15155f611ba0565b80519192508115918215611c28575b5050905f611b99565b611c3b9250602080918301019101611c77565b5f80611c1f565b9150506020813d602011611c6f575b81611c5e602093836116ff565b8101031261033c578390515f611b2e565b3d9150611c51565b9081602091031261033c5751801515810361033c5790565b5f806001600160a01b03611cb893169360208151910182865af1611cb1611d14565b9083611d71565b8051908115159182611cf9575b5050611cce5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611d0c9250602080918301019101611c77565b155f80611cc5565b3d15611d6c573d9067ffffffffffffffff821161167d5760405191611d6160207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846116ff565b82523d5f602084013e565b606090565b90611dae5750805115611d8657805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611df4575b611dbf575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611db756fea164736f6c634300081a000a"; + hex"60808060405234601557611b67908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd31461108957806349a32c4014610d7b578063606ef87514610a635780639e743f291461072b578063a514f83e146103e85763f7ca34eb1461005b575f80fd5b3461032a57610069366113d4565b91909282156103c0575f905f5b84811061039557506001600160a01b036100939116918383611827565b61009c83611584565b926001600160a01b035f9316925b8181106100c357604051806100bf878261142b565b0390f35b6100ce8183886117e1565b6100d7906115b6565b90826100e482828a6117e1565b6020016100f0906115b6565b6100fb83838b6117e1565b604001610107906114b0565b93896101148585836117e1565b606001610120906115ca565b61012b8686846117e1565b608001610137906115ca565b6101428787856117e1565b60a00161014e90611804565b918761015b8189876117e1565b60c081016101689161170e565b986101749291966117e1565b60e001936040519561018587611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906101e392611744565b9360e08601948552366101f5916116b0565b966101008601978852604051998a977f31df3d480000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b808210610341575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f90610300575b600192506102f982886116e9565b52016100aa565b506020823d821161032e575b816103196020938361154a565b8101031261032a57600191516102eb565b5f80fd5b3d915061030c565b6040513d5f823e3d90fd5b91949350916020606082610386600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102ac565b916001906001600160801b036103b760406103b1878a8c6117e1565b016114b0565b16019201610076565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461032a57606036600319011261032a57610401611464565b61040961138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610140870201011161032a5783156103c05790915f9190825b85811061070257506001600160a01b0361047c9116928484611827565b61048584611584565b926001600160a01b03165f5b8581106104a657604051806100bf878261142b565b6104b96104b4828886611816565b6115b6565b906104d060206104ca838a88611816565b016115b6565b87856104e260406103b1868585611816565b6104f860606104f2878686611816565b016115ca565b906101006105228761051b818861051560806104f284848d611816565b98611816565b968c611816565b01906001600160a01b03604051986105398a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526060609f19873603011261032a57604051956105918761152e565b61059d60a08201611621565b87526105ab60c08201611621565b602088015260e0016105bc90611621565b604087015260c08901958652366105d2916116b0565b9560e08901968752604051987f53b15727000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c4850152602081015164ffffffffff1660e48501526040015164ffffffffff166101048401525161012483016106a091602080916001600160a01b0381511684520151910152565b8180865a925f61016492602095f18015610336575f906106d0575b600192506106c982886116e9565b5201610491565b506020823d82116106fa575b816106e96020938361154a565b8101031261032a57600191516106bb565b3d91506106dc565b93926001906001600160801b0361071f60406103b1898b89611816565b1601940193929361045f565b3461032a57610739366113d4565b91909282156103c0575f905f5b848110610a3e57506001600160a01b036107639116918383611827565b61076c83611584565b926001600160a01b035f9316925b81811061078f57604051806100bf878261142b565b61079a8183886117e1565b6107a3906115b6565b90826107b082828a6117e1565b6020016107bc906115b6565b6107c783838b6117e1565b6040016107d3906114b0565b93896107e08585836117e1565b6060016107ec906115ca565b6107f78686846117e1565b608001610803906115ca565b61080e8787856117e1565b60a00161081a90611804565b91876108278189876117e1565b60c08101610834916115d7565b986108409291966117e1565b60e001936040519561085187611511565b6001600160a01b0316865260208601966001600160a01b0316875260408601996001600160801b03168a5260608601978d895260808701921515835260a08701931515845260c087019464ffffffffff16855236906108af92611633565b9360e08601948552366108c1916116b0565b966101008601978852604051998a977f32fbe22b0000000000000000000000000000000000000000000000000000000089526004890160209052610164890197516001600160a01b031660248a0152516001600160a01b03166044890152516001600160801b03166064880152516001600160a01b0316608487015251151560a486015251151560c48501525164ffffffffff1660e48401525190610104830161014090528151809152610184830191602001905f905b8082106109fe575050925180516001600160a01b03166101248401526020908101516101448401529250819003815f885af18015610336575f906109cc575b600192506109c582886116e9565b520161077a565b506020823d82116109f6575b816109e56020938361154a565b8101031261032a57600191516109b7565b3d91506109d8565b91949350916020604082610a2f600194895164ffffffffff602080926001600160801b038151168552015116910152565b01950192018693949291610978565b916001906001600160801b03610a5a60406103b1878a8c6117e1565b16019201610746565b3461032a57610a71366113d4565b91909282156103c0575f905f5b848110610d5657506001600160a01b03610a9b9116918383611827565b610aa483611584565b926001600160a01b035f9316925b818110610ac757604051806100bf878261142b565b610ad281838861147a565b610adb906115b6565b9082610ae882828a61147a565b602001610af4906115b6565b610aff83838b61147a565b604001610b0b906114b0565b9389610b1885858361147a565b606001610b24906115ca565b610b2f86868461147a565b608001610b3b906115ca565b9086610b4881888661147a565b60a08101610b559161170e565b97610b6192919561147a565b60c0019260405194610b72866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a0860193151584523690610bc292611744565b9260c0850193845236610bd4916116b0565b9560e085019687526040519889967f54c022920000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210610d02575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f90610cd0575b60019250610cc982886116e9565b5201610ab2565b506020823d8211610cfa575b81610ce96020938361154a565b8101031261032a5760019151610cbb565b3d9150610cdc565b91949350916020606082610d47600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610c7c565b916001906001600160801b03610d7260406103b1878a8c61147a565b16019201610a7e565b3461032a57606036600319011261032a57610d94611464565b610d9c61138d565b906044359167ffffffffffffffff831161032a573660238401121561032a5782600401359267ffffffffffffffff841161032a57602481019060243691610120870201011161032a5783156103c05790915f9190825b85811061106057506001600160a01b03610e0f9116928484611827565b610e1884611584565b926001600160a01b03165f5b858110610e3957604051806100bf878261142b565b610e476104b48288866116fd565b90610e5860206104ca838a886116fd565b8785610e6a60406103b18685856116fd565b610e7a60606104f28786866116fd565b9060e0610ea387610e9c8188610e9660806104f284848d6116fd565b986116fd565b968c6116fd565b01906001600160a01b0360405198610eba8a6114c4565b1688526001600160a01b0360208901961686526001600160801b036040890191168152606088019189835260808901931515845260a0890194151585526040609f19873603011261032a5760405195610f12876114f5565b610f1e60a08201611621565b875260c001610f2c90611621565b602087015260c0890195865236610f42916116b0565b9560e08901968752604051987fab167ccc000000000000000000000000000000000000000000000000000000008a52516001600160a01b031660048a0152516001600160a01b03166024890152516001600160801b03166044880152516001600160a01b03166064870152511515608486015251151560a485015251805164ffffffffff1660c48501526020015164ffffffffff1660e4840152516101048301610ffe91602080916001600160a01b0381511684520151910152565b8180865a925f61014492602095f18015610336575f9061102e575b6001925061102782886116e9565b5201610e24565b506020823d8211611058575b816110476020938361154a565b8101031261032a5760019151611019565b3d915061103a565b93926001906001600160801b0361107d60406103b1898b896116fd565b16019401939293610df2565b3461032a57611097366113d4565b91909282156103c0575f905f5b84811061136857506001600160a01b036110c19116918383611827565b6110ca83611584565b926001600160a01b035f9316925b8181106110ed57604051806100bf878261142b565b6110f881838861147a565b611101906115b6565b908261110e82828a61147a565b60200161111a906115b6565b61112583838b61147a565b604001611131906114b0565b938961113e85858361147a565b60600161114a906115ca565b61115586868461147a565b608001611161906115ca565b908661116e81888661147a565b60a0810161117b916115d7565b9761118792919561147a565b60c0019260405194611198866114c4565b6001600160a01b0316855260208501956001600160a01b0316865260408501986001600160801b0316895260608501968c885260808601921515835260a08601931515845236906111e892611633565b9260c08501938452366111fa916116b0565b9560e085019687526040519889967f897f362b0000000000000000000000000000000000000000000000000000000088526004880160209052610144880196516001600160a01b03166024890152516001600160a01b03166044880152516001600160801b03166064870152516001600160a01b0316608486015251151560a485015251151560c4840152519060e4830161012090528151809152610164830191602001905f905b808210611328575050925180516001600160a01b03166101048401526020908101516101248401529250819003815f885af18015610336575f906112f6575b600192506112ef82886116e9565b52016110d8565b506020823d8211611320575b8161130f6020938361154a565b8101031261032a57600191516112e1565b3d9150611302565b91949350916020604082611359600194895164ffffffffff602080926001600160801b038151168552015116910152565b019501920186939492916112a2565b916001906001600160801b0361138460406103b1878a8c61147a565b160192016110a4565b602435906001600160a01b038216820361032a57565b9181601f8401121561032a5782359167ffffffffffffffff831161032a576020808501948460051b01011161032a57565b606060031982011261032a576004356001600160a01b038116810361032a57916024356001600160a01b038116810361032a57916044359067ffffffffffffffff821161032a57611427916004016113a3565b9091565b60206040818301928281528451809452019201905f5b81811061144e5750505090565b8251845260209384019390920191600101611441565b600435906001600160a01b038216820361032a57565b919081101561149c5760051b8101359060fe198136030182121561032a570190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b038116810361032a5790565b610100810190811067ffffffffffffffff8211176114e157604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff8211176114e157604052565b610120810190811067ffffffffffffffff8211176114e157604052565b6060810190811067ffffffffffffffff8211176114e157604052565b90601f8019910116810190811067ffffffffffffffff8211176114e157604052565b67ffffffffffffffff81116114e15760051b60200190565b9061158e8261156c565b61159b604051918261154a565b82815280926115ac601f199161156c565b0190602036910137565b356001600160a01b038116810361032a5790565b35801515810361032a5790565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a57602001918160061b3603831361032a57565b35906001600160801b038216820361032a57565b359064ffffffffff8216820361032a57565b92919261163f8261156c565b9361164d604051958661154a565b602085848152019260061b82019181831161032a57925b8284106116715750505050565b60408483031261032a576020604091825161168b816114f5565b6116948761160d565b81526116a1838801611621565b83820152815201930192611664565b919082604091031261032a576040516116c8816114f5565b809280356001600160a01b038116810361032a578252602090810135910152565b805182101561149c5760209160051b010190565b919081101561149c57610120020190565b903590601e198136030182121561032a570180359067ffffffffffffffff821161032a5760200191606082023603831361032a57565b9291926117508261156c565b9361175e604051958661154a565b606060208685815201930282019181831161032a57925b8284106117825750505050565b60608483031261032a57604051906117998261152e565b6117a28561160d565b825260208501359067ffffffffffffffff8216820361032a57826020928360609501526117d160408801611621565b6040820152815201930192611775565b919081101561149c5760051b8101359061011e198136030182121561032a570190565b3564ffffffffff8116810361032a5790565b919081101561149c57610140020190565b919061187c6040517f23b872dd0000000000000000000000000000000000000000000000000000000060208201523360248201523060448201528360648201526064815261187660848261154a565b82611a0a565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156103365784915f916119bd575b50106118e8575b50505050565b5f8060405194602086019063095ea7b360e01b825287602488015260448701526044865261191760648761154a565b85519082855af190611927611a8f565b8261198b575b5081611980575b5015611941575b806118e2565b611973611978936040519063095ea7b360e01b602083015260248201525f60448201526044815261187660648261154a565b611a0a565b5f808061193b565b90503b15155f611934565b805191925081159182156119a3575b5050905f61192d565b6119b692506020809183010191016119f2565b5f8061199a565b9150506020813d6020116119ea575b816119d96020938361154a565b8101031261032a578390515f6118db565b3d91506119cc565b9081602091031261032a5751801515810361032a5790565b5f806001600160a01b03611a3393169360208151910182865af1611a2c611a8f565b9083611ace565b8051908115159182611a74575b5050611a495750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b611a8792506020809183010191016119f2565b155f80611a40565b3d15611ac9573d9067ffffffffffffffff82116114e15760405191611abe601f8201601f19166020018461154a565b82523d5f602084013e565b606090565b90611b0b5750805115611ae357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611b51575b611b1c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15611b1456fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_DYNAMIC = - hex"60c0604052346103e457615a506060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601d84527f5361626c696572205632204c6f636b75702044796e616d6963204e4654000000602085015261009860406103e8565b601181527029a0a116ab1916a627a1a5aaa816a22ca760791b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615642908161040e823960805181613935015260a051818181610bca01526139ff0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c657508063027b6744146127a457806306fdde03146126e9578063081812fc146126cb578063095ea7b3146125c65780631400ecec146125155780631c1cdd4c146124b15780631e99d5691461249457806323b872dd1461247d578063303acc851461244057806331df3d481461232d578063406887cb146121be57806340e58ee514611ea5578063425d30dd14611e5557806342842e0e14611e2c57806342966c6814611c685780634426757014611c425780634857501f14611bd15780634869e12d14611b975780634cc55e1114611a9f57806354c02292146117ee57806357404b12146117605780636352211e146117315780636d0cee751461173157806370a08231146116c757806375829def146116595780637cad6cd1146115685780637de6b1db146113e95780638659c27014610feb578063894e9a0d14610cbc5780638f69b99314610c3c5780639067b67714610bed5780639188ec8414610bb357806395d89b4114610aab578063a22cb465146109f7578063a80fc071146109a6578063ad35efd414610947578063b2564569146108f7578063b637b8651461089e578063b88d4fde14610816578063b8a3be66146107e1578063b971302a14610793578063bc2be1be14610744578063c156a11d1461060e578063c87b56dd146104f8578063d4dbd20b146104a7578063d511609f1461045c578063d975dfed14610422578063e985e9c5146103c9578063ea5ead1914610385578063eac8f5b814610334578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f3565b6044356001600160801b03811681036102b0576102ae916102a661392b565b6004356133df565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b86103a66128f3565b916103b081614206565b928391613082565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e26128dd565b6001600160a01b036103f26128f3565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614206565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610515816136ad565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610603575f90610586575b610582906040519182916020835260208301906128b8565b0390f35b503d805f833e6105968183612a76565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105ce83612a98565b916105dc6040519384612a76565b838352602084830101116102b057610582926105fe9160208085019101612897565b61056a565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062a6128f3565b61063261392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f5260036020526001600160a01b0360405f205416908133036107125761067483614206565b6001600160801b0381169182610702575b6001600160a01b038116156106ef576106a6856001600160a01b03926137f1565b1692836106c05784637e27328960e01b5f5260045260245ffd5b80859185036106d457602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070d828587613082565b610685565b8263216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b05761082f6128dd565b6108376128f3565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086483612a98565b926108726040519485612a76565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105826108e360405f20612f0b565b604051918291602083526020830190612988565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761097f9061375d565b6040516005821015610992576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a106128dd565b602435908115158092036102b0576001600160a01b0316908115610a7f57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610ba9575b602083108114610b9557828552908115610b715750600114610b13575b61058283610aff81850382612a76565b6040519182916020835260208301906128b8565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5757509091508101602001610aff610aef565b919260018160209254838588010152019101909291610b3f565b60ff191660208086019190915291151560051b84019091019150610aff9050610aef565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad2565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c749061375d565b6005811015806109925760028214908115610cb0575b8115610c9e575b6020826040519015158152f35b90506109925760046020911482610c91565b5050600381145f610c8a565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd757606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d37612ebb565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7281612a59565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e11600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612ed9565b61012083019081526002610e248c61375d565b610e2d816129fa565b14610fcf575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea46101808d612a76565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610ef890612f0b565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e0820161058291612988565b5f8752610e33565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101c903690600401612957565b9061102561392b565b5f915b80831061103157005b61103c838284612e4a565b359261104661392b565b835f52600a60205260ff600160405f20015460a81c16156113d657835f52600a60205260ff600160405f20015460a01c165f146110905783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c4576110c5815f52600a6020526001600160a01b0360405f205416331490565b156113ae576110d3816136ce565b90805f52600a6020526110eb600260405f2001612ed9565b916001600160801b038351166001600160801b038216101561139a57815f52600a60205260ff60405f205460f01c161561138657806001600160801b0360208161113f948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611361575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125a6001600160a01b03600160405f2001541694611232888588614660565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a4866001600160a01b03165f52600960205260405f2090565b54166112ba575b50505050506001019190611028565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91611333575b50160361131757808080806112ab565b632187e5e760e21b5f526001600160a01b03602491166004525ffd5b611354915060203d811161135a575b61134c8183612a76565b81019061368d565b87611307565b503d611342565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611189565b506339c6dc7360e21b5f526024906004525ffd5b506322cad1af60e11b5f526024906004525ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140561392b565b805f52600a60205260ff600160405f20015460a81c1615610323576114298161375d565b611432816129fa565b6004810361144d5750634a5541ef60e01b5f5260045260245ffd5b611456816129fa565b60038103611471575063fe19f19f60e01b5f5260045260245ffd5b60029061147d816129fa565b14611556576114a0815f52600a6020526001600160a01b0360405f205416331490565b1561153757805f52600a60205260ff60405f205460f01c1615611525576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b63216caf0d60e01b5f526004526001600160a01b03331660245260445ffd5b6322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611643575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161162f5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116726128dd565b5f546001600160a01b03811633810361164357506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116e86128dd565b168015611705575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b057602061174f6004356136ad565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177c612ea3565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c683612a3d565b825260208201526117ec8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182961392b565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186b913691612d66565b9081519161187883612d4e565b926118866040519485612a76565b808452601f1961189582612d4e565b015f5b818110611a8857505064ffffffffff4216916001600160801b036118bb82613985565b51511667ffffffffffffffff60206118d284613985565b5101511664ffffffffff8060406118e886613985565b5101511686011690604051926118fd84612a21565b83526020830152604082015261191286613985565b5261191c85613985565b5060015b8281106119f45750505061193682600401612e82565b9261194360248401612e82565b9261195060448201612e6e565b916064820135936001600160a01b0385168095036102b0576020966119ec966119ac966001600160801b036119e1976001600160a01b0361199360848a01612e96565b94816119a160a48c01612e96565b976040519d8e612a04565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e03565b6101008201526139a6565b604051908152f35b806001600160801b03611a0960019385613992565b51511667ffffffffffffffff6020611a218487613992565b5101511664ffffffffff806040611a3b5f1987018d613992565b51015116816040611a4c878a613992565b5101511601169060405192611a6084612a21565b835260208301526040820152611a768289613992565b52611a818188613992565b5001611920565b602090611a93612ebb565b82828901015201611898565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad0903690600401612957565b9060243567ffffffffffffffff81116102b057611af1903690600401612957565b9091611afb61392b565b818403611b67575f5b848110611b0d57005b80611b61611b1e6001938886612e4a565b35611b2a838987612e4a565b355f5260036020526001600160a01b0360405f205416611b53611b4e85898b612e4a565b612e6e565b91611b5c61392b565b6133df565b01611b04565b50827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b8602091614156565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0a8261375d565b600581101561099257600203611c28575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1b565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8461392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0157611cc3816140e4565b156113ae57805f5260036020526001600160a01b0360405f205416151580611dfa575b80611ddd575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d94575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8257005b637e27328960e01b5f5260045260245ffd5b611db3835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3a565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cec565b505f611ce6565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e3d3661291d565b9060405192611e4d602085612a76565b5f8452612f92565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec161392b565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0a57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c457611f3c815f52600a6020526001600160a01b0360405f205416331490565b1561153757611f4a816136ce565b90805f52600a602052611f62600260405f2001612ed9565b916001600160801b038351166001600160801b03821610156121ab57815f52600a60205260ff60405f205460f01c161561219857806001600160801b03602081611fb6948188511603169501511690612aea565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612173575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120a96001600160a01b03600160405f2001541694611232888588614660565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ec57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060357630d4af11f60e31b916001600160e01b0319915f91612154575b50160361214257005b632187e5e760e21b5f5260045260245ffd5b61216d915060203d60201161135a5761134c8183612a76565b84612139565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612000565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b346102b05760203660031901126102b0576121d76128dd565b6001600160a01b035f54169033820361231657806001600160a01b03913b156122ea57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610603575f916122bb575b501561229057805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122dd915060203d6020116122e3575b6122d58183612a76565b810190612e32565b82612245565b503d6122cb565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236761392b565b6040519061237482612a04565b61238081600401612909565b825261238e60248201612909565b602083015261239f60448201612ab4565b604083015260648101356001600160a01b03811681036102b05760608301526123ca608482016129ed565b60808301526123db60a482016129ed565b60a08301526123ec60c48201612d3c565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e16119ec926124306020953690602460048201359101612d66565b60e0840152610104369101612e03565b346102b05760203660031901126102b0576001600160a01b036124616128dd565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61248e3661291d565b91612b0a565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124e99061375d565b600581101561099257806020911590811561250a575b506040519015158152f35b6001915014826124ff565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125aa575b612578575b506001600160801b0360405191168152f35b6125a49150805f52600a835261259e6001600160801b03600260405f20015416916136ce565b90612aea565b82612566565b50805f52600a835260ff600160405f20015460a01c1615612561565b346102b05760403660031901126102b0576125df6128dd565b6024356125eb816136ad565b331515806126b8575b80612685575b6126595781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fa565b50336001600160a01b03821614156125f4565b346102b05760203660031901126102b057602061174f600435612ac8565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279a575b602083108114610b9557828552908115610b71575060011461273c5761058283610aff81850382612a76565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278057509091508101602001610aff610aef565b919260018160209254838588010152019101909291612768565b91607f1691612710565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612822575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561286d575b811561285c575b508361281b565b6301ffc9a760e01b91501483612855565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061284e565b5f5b8381106128a85750505f910152565b8181015183820152602001612899565b906020916128d181518092818552858086019101612897565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a55750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff86820151168685015201511660408201520194019101919091612998565b359081151582036102b057565b6005111561099257565b610120810190811067ffffffffffffffff821117610fd757604052565b6060810190811067ffffffffffffffff821117610fd757604052565b6040810190811067ffffffffffffffff821117610fd757604052565b610140810190811067ffffffffffffffff821117610fd757604052565b90601f8019910116810190811067ffffffffffffffff821117610fd757604052565b67ffffffffffffffff8111610fd757601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad1816136ad565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161162f57565b91906001600160a01b031680156106ef57815f5260036020526001600160a01b0360405f205416151580612d34575b80612d17575b612d04577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c4f575b6001600160a01b03935085612c18575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0057505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c37825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612b9f565b9192905080612cad575b15612c6657828291612b8f565b8284612c7e57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cdb575b80612c595750825f526005602052336001600160a01b0360405f20541614612c59565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cb8565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b3f565b506001612b39565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd75760051b60200190565b929192612d7282612d4e565b93612d806040519586612a76565b60606020868581520193028201918183116102b057925b828410612da45750505050565b6060848303126102b05760405190612dbb82612a21565b612dc485612ab4565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df360408801612d3c565b6040820152815201930192612d97565b91908260409103126102b057604051612e1b81612a3d565b6020808294612e2981612909565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb082612a3d565b5f6020838281520152565b60405190612ec882612a21565b5f6040838281528260208201520152565b90604051612ee681612a21565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1781612d4e565b92612f256040519485612a76565b81845260208401905f5260205f205f915b838310612f435750505050565b600160208192604051612f5581612a21565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f36565b90612f9e838284612b0a565b803b612fab575b50505050565b602091612ff16001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128b8565b03815f865af15f9181613061575b5061302d575061300d6141d7565b805190816130285782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361304f57505f808080612fa5565b633250574960e11b5f5260045260245ffd5b61307b91925060203d60201161135a5761134c8183612a76565b905f612fff565b9061308b61392b565b815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f205416948583141580613364575b613330576001600160801b0361311786614206565b168085116132fd575061313c90855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561317f90612ed9565b6001600160801b036131a38160208401511692826040818351169201511690612aea565b1611156132cb575b835f52600a6020526131cf836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b5575b6132395750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613296575b50160361214257808080612fa5565b6132af915060203d60201161135a5761134c8183612a76565b5f613287565b50835f52600960205260ff60405f20541661322f565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ab565b84867fa1fb2bbc000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857fb34359d3000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b5061336e856140e4565b15613102565b837fd2aabcd9000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f7fbf7168000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073257815f52600a60205260ff600160405f20015460a01c166133cc576001600160a01b03811680156133a0576001600160801b03841691821561337457835f5260036020526001600160a01b0360405f20541694858314158061367d575b613330576001600160801b0361346c86614206565b168085116132fd575061349190855f52600a602052600260405f20015460801c61422c565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d490612ed9565b6001600160801b036134f88160208401511692826040818351169201511690612aea565b16111561364b575b835f52600a602052613524836001600160a01b03600160405f200154169283614660565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613626575b61358e5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610603576392b9102b60e01b916001600160e01b0319915f91613607575b5016036135eb57808080612fa5565b6001600160a01b0390632187e5e760e21b5f521660045260245ffd5b613620915060203d60201161135a5761134c8183612a76565b5f6135dc565b5060ff613644856001600160a01b03165f52600960205260405f2090565b5416613584565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613500565b50613687856140e4565b15613457565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d82575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375757815f52600a60205264ffffffffff60405f205460c81c16111561373c57805f52600b602052600160405f2054115f14613733576137309061430c565b90565b6137309061424c565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f1461377f5750600490565b805f52600a60205260405f205460f81c6137eb57805f52600a60205264ffffffffff60405f205460a01c1642106137e6576137b9816136ce565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e157600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613919575b806138fc575b611dcb577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c5575b16806138ad575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613869565b6138e4835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613862565b50805f52600a60205260ff600160405f20015460b01c1615613816565b506001600160a01b0382161515613810565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361395d57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5a5760200190565b8051821015612e5a5760209160051b010190565b906139c86001600160801b036040840151166020610100850151015190614522565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bc578015614094578151801561406c577f00000000000000000000000000000000000000000000000000000000000000008111614041575064ffffffffff6040613a3684613985565b51015116811015613ffd57505f905f905f81515f905b808210613f75575050505064ffffffffff80421691169081811015613f475750506001600160801b031690818103613f1957505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c218751975f19890190613992565b51015160c81b169360a01b169116171785555f5b818110613e0b575050600187016007556001600160a01b0360208301511680156106ef57613c6b886001600160a01b03926137f1565b16613ddf578682613cb96001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b0385511690309033906145ff565b6001600160801b0360208401511680613daf575b506001600160a01b0381511694613da4613d866001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2b8b612a3d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c0870152610140860190612988565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613dd9906001600160a01b036060840151166001600160a01b0361010085015151169033906145ff565b5f613ccd565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e268160e0870151613992565b51825468010000000000000000811015610fd75760018101808555811015612e5a576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c35565b7fd90b7e39000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f99906001600160801b03613f908588613992565b5151169061422c565b9364ffffffffff806040613fad8685613992565b51015116941680851115613fc957506001849301909291613a4c565b8490847f9588ac09000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061400e84613985565b51015116907ff539a17c000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4757689b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f3952c64e000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412a575b508115614111575090565b90506001600160a01b036141253392612ac8565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614106565b805f52600a60205261416d600260405f2001612ed9565b90805f52600a60205260ff600160405f20015460a01c165f1461419b5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141ba5750613730906136ce565b61373091506001600160801b036040818351169201511690612aea565b3d15614201573d906141e882612a98565b916141f66040519384612a76565b82523d5f602084013e565b606090565b6137309061421381614156565b905f52600a602052600260405f20015460801c90612aea565b906001600160801b03809116911601906001600160801b03821161162f57565b5f818152600a60205260409020546142839064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b0565b90805f52600b60205260405f20805415612e5a575f526142d867ffffffffffffffff60205f205460801c1692825f52600a6020526142d36001600160801b03600260405f20015416948592614790565b614803565b9182136142f557506142f16001600160801b03916148de565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433082612a59565b6101206143c360028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612ed9565b92019182525f52600b6020526143db60405f20612f0b565b915f9264ffffffffff60406143ef83613985565b510151168664ffffffffff5f925b16106144e3578161447464ffffffffff9697988784816001600160801b0361442c6142d3986144799b9a613992565b5151169a8b9867ffffffffffffffff6020614447868b613992565b51015116978260406144598784613992565b5101511694806144c6575050511680925b03169203166146b0565b614790565b91821361449a5750906001600160801b0361449481936148de565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c1575090565b905090565b60409250906144d8915f190190613992565b51015116809261446a565b936001600160801b03600191816144fa8886613992565b51511601169401958064ffffffffff8060406145168b87613992565b510151169892986143fd565b91909160405161453181612a3d565b5f81525f6020820152926001600160801b0382169081156145e25767016345785d8a000081116145ab5761456d6001600160801b0391836154fb565b1660208501918183521115614597576001600160801b03918261459292511690612aea565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f381612a3d565b5f81525f602082015290565b9091926001600160a01b0361465e9481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614659608483612a76565b614913565b565b61465e926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614659606483612a76565b600160ff1b81148015614783575b61475b575f811215614752576146e2815f035b5f84121561474b57835f0390614998565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471c575f19911813156147175790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b8390614998565b6146e2816146d1565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146be565b806147aa57506147a657670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f557806147cd575050670de0b6b3a764000090565b670de0b6b3a764000081146147f1576147ec906142d361373093614a9e565b614bf5565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d1575b6148a9575f8112156148a057614835815f035b5f84121561489957835f03906154fb565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486a575f19911813156147175790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fb565b61483581614824565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614811565b5f81126148e85790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493c93169360208151910182865af16149356141d7565b90836155a9565b805190811515918261497d575b50506149525750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149909250602080918301019101612e32565b155f80614949565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a635781841015614a2957670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a70570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a70576ec097ce7bc90715b34b9f10000000000590565b805f811315614bca57670de0b6b3a76400008112614baa57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9757506706f05b59d3b20000905b5f8213614b615750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b89575b60011d90614b54565b809192019160011d90614b80565b9050670de0b6b3a7640000929150020290565b5f1991508015614a70576ec097ce7bc90715b34b9f100000000005614abb565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c225768033dd1780914b971141981126137e657614c19905f03614bf5565b61373090614a84565b680a688906bd8affffff81136154d057670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539b575b670de0b6b3a76400009066ff000000000000831661528b575b65ff00000000008316615183575b64ff000000008316615083575b63ff0000008316614f8b575b62ff00008316614e9b575b61ff008316614db3575b60ff8316614cd3575b029060401c60bf031c90565b60808316614da0575b60408316614d8d575b60208316614d7a575b60108316614d67575b60088316614d54575b60048316614d41575b60028316614d2e575b6001831615614cc757680100000000000000010260401c614cc7565b680100000000000000010260401c614d12565b680100000000000000030260401c614d09565b680100000000000000060260401c614d00565b6801000000000000000b0260401c614cf7565b680100000000000000160260401c614cee565b6801000000000000002c0260401c614ce5565b680100000000000000590260401c614cdc565b6180008316614e88575b6140008316614e75575b6120008316614e62575b6110008316614e4f575b6108008316614e3c575b6104008316614e29575b6102008316614e16575b610100831615614cbe57680100000000000000b10260401c614cbe565b680100000000000001630260401c614df9565b680100000000000002c60260401c614def565b6801000000000000058c0260401c614de5565b68010000000000000b170260401c614ddb565b6801000000000000162e0260401c614dd1565b68010000000000002c5d0260401c614dc7565b680100000000000058b90260401c614dbd565b628000008316614f78575b624000008316614f65575b622000008316614f52575b621000008316614f3f575b620800008316614f2c575b620400008316614f19575b620200008316614f06575b62010000831615614cb4576801000000000000b1720260401c614cb4565b680100000000000162e40260401c614ee8565b6801000000000002c5c80260401c614edd565b68010000000000058b910260401c614ed2565b680100000000000b17210260401c614ec7565b68010000000000162e430260401c614ebc565b680100000000002c5c860260401c614eb1565b6801000000000058b90c0260401c614ea6565b63800000008316615070575b6340000000831661505d575b6320000000831661504a575b63100000008316615037575b63080000008316615024575b63040000008316615011575b63020000008316614ffe575b6301000000831615614ca95768010000000000b172180260401c614ca9565b6801000000000162e4300260401c614fdf565b68010000000002c5c8600260401c614fd3565b680100000000058b90c00260401c614fc7565b6801000000000b17217f0260401c614fbb565b680100000000162e42ff0260401c614faf565b6801000000002c5c85fe0260401c614fa3565b68010000000058b90bfc0260401c614f97565b6480000000008316615170575b644000000000831661515d575b642000000000831661514a575b6410000000008316615137575b6408000000008316615124575b6404000000008316615111575b64020000000083166150fe575b640100000000831615614c9d57680100000000b17217f80260401c614c9d565b68010000000162e42ff10260401c6150de565b680100000002c5c85fe30260401c6150d1565b6801000000058b90bfce0260401c6150c4565b68010000000b17217fbb0260401c6150b7565b6801000000162e42fff00260401c6150aa565b68010000002c5c8601cc0260401c61509d565b680100000058b90c0b490260401c615090565b658000000000008316615278575b654000000000008316615265575b652000000000008316615252575b65100000000000831661523f575b65080000000000831661522c575b650400000000008316615219575b650200000000008316615206575b65010000000000831615614c90576801000000b1721835510260401c614c90565b680100000162e430e5a20260401c6151e5565b6801000002c5c863b73f0260401c6151d7565b68010000058b90cf1e6e0260401c6151c9565b680100000b1721bcfc9a0260401c6151bb565b68010000162e43f4f8310260401c6151ad565b680100002c5c89d5ec6d0260401c61519f565b6801000058b91b5bc9ae0260401c615191565b66800000000000008316615388575b66400000000000008316615375575b66200000000000008316615362575b6610000000000000831661534f575b6608000000000000831661533c575b66040000000000008316615329575b66020000000000008316615316575b6601000000000000831615614c825768010000b17255775c040260401c614c82565b6801000162e525ee05470260401c6152f4565b68010002c5cc37da94920260401c6152e5565b680100058ba01fb9f96d0260401c6152d6565b6801000b175effdc76ba0260401c6152c7565b680100162f3904051fa10260401c6152b8565b6801002c605e2e8cec500260401c6152a9565b68010058c86da1c09ea20260401c61529a565b67800000000000000082166154b1575b670de0b6b3a764000090674000000000000000831661549e575b672000000000000000831661548b575b6710000000000000008316615478575b6708000000000000008316615465575b6704000000000000008316615452575b670200000000000000831661543f575b670100000000000000831661542c575b9050614c69565b680100b1afa5abcbed610260401c615425565b68010163da9fb33356d80260401c615415565b680102c9a3e778060ee70260401c615405565b6801059b0d31585743ae0260401c6153f5565b68010b5586cf9890f62a0260401c6153e5565b6801172b83c7d517adce0260401c6153d5565b6801306fe0a31b7152df0260401c6153c5565b5077b504f333f9de6484800000000000000000000000000000006153ab565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559857670de0b6b3a7640000821015615568577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e657508051156155be57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562c575b6155f7575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155ef56fea164736f6c634300081a000a"; + hex"60c0604052346103e157615a506060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615645908161040b823960805181613938015260a051818181610bcc0152613a020152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a661392e565b6004356133e2565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b181614209565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614209565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b0565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b61063361392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f205416908133036107135761067583614209565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f4565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613760565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613760565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613760565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b9061102761392e565b5f915b80831061103357005b61103e838284612e4d565b359261104861392e565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d1565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614663565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613690565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140861392e565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613760565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b0565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c61392e565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be82613988565b51511667ffffffffffffffff60206118d584613988565b5101511664ffffffffff8060406118eb86613988565b51015116860116906040519261190084612a24565b83526020830152604082015261191586613988565b5261191f85613988565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139a9565b604051908152f35b806001600160801b03611a0c60019385613995565b51511667ffffffffffffffff6020611a248487613995565b5101511664ffffffffff806040611a3e5f1987018d613995565b51015116816040611a4f878a613995565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613995565b52611a848188613995565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe61392e565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f61392e565b6133e2565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614159565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613760565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8761392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140e7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec461392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d1565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614663565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a61392e565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613760565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d1565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b0565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b0565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141da565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b9061308e61392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613367575b613333576001600160801b0361311a86614209565b16808511613300575061313f90855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318290612edc565b6001600160801b036131a68160208401511692826040818351169201511690612aed565b1611156132ce575b835f52600a6020526131d2836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b8575b61323c5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f91613299575b50160361214557808080612fa8565b6132b2915060203d60201161135c5761134e8183612a79565b5f61328a565b50835f52600960205260ff60405f205416613232565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ae565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b50613371856140e7565b15613105565b837fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613680575b613333576001600160801b0361346f86614209565b16808511613300575061349490855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d790612edc565b6001600160801b036134fb8160208401511692826040818351169201511690612aed565b16111561364e575b835f52600a602052613527836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613629575b6135915750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360a575b5016036135ee57808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613623915060203d60201161135c5761134e8183612a79565b5f6135df565b5060ff613647856001600160a01b03165f52600960205260405f2090565b5416613587565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613503565b5061368a856140e7565b1561345a565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375a57815f52600a60205264ffffffffff60405f205460c81c16111561373f57805f52600b602052600160405f2054115f14613736576137339061430f565b90565b6137339061424f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137825750600490565b805f52600a60205260405f205460f81c6137ee57805f52600a60205264ffffffffff60405f205460a01c1642106137e9576137bc816136d1565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391c575b806138ff575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c8575b16806138b0575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386c565b6138e7835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613865565b50805f52600a60205260ff600160405f20015460b01c1615613819565b506001600160a01b0382161515613813565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cb6001600160801b036040840151166020610100850151015190614525565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bf578015614097578151801561406f577f00000000000000000000000000000000000000000000000000000000000000008111614044575064ffffffffff6040613a3984613988565b5101511681101561400057505f905f905f81515f905b808210613f78575050505064ffffffffff80421691169081811015613f4a5750506001600160801b031690818103613f1c57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c248751975f19890190613995565b51015160c81b169360a01b169116171785555f5b818110613e0e575050600187016007556001600160a01b0360208301511680156106f057613c6e886001600160a01b03926137f4565b16613de2578682613cbc6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b038551169030903390614602565b6001600160801b0360208401511680613db2575b506001600160a01b0381511694613da7613d896001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2e8b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613ddc906001600160a01b036060840151166001600160a01b036101008501515116903390614602565b5f613cd0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e298160e0870151613995565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c38565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f9c906001600160801b03613f938588613995565b5151169061422f565b9364ffffffffff806040613fb08685613995565b51015116941680851115613fcc57506001849301909291613a4f565b8490847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061401184613988565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412d575b508115614114575090565b90506001600160a01b036141283392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614109565b805f52600a602052614170600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461419e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141bd5750613733906136d1565b61373391506001600160801b036040818351169201511690612aed565b3d15614204573d906141eb82612a9b565b916141f96040519384612a79565b82523d5f602084013e565b606090565b6137339061421681614159565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142869064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b3565b90805f52600b60205260405f20805415612e5d575f526142db67ffffffffffffffff60205f205460801c1692825f52600a6020526142d66001600160801b03600260405f20015416948592614793565b614806565b9182136142f857506142f46001600160801b03916148e1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433382612a5c565b6101206143c660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143de60405f20612f0e565b915f9264ffffffffff60406143f283613988565b510151168664ffffffffff5f925b16106144e6578161447764ffffffffff9697988784816001600160801b0361442f6142d69861447c9b9a613995565b5151169a8b9867ffffffffffffffff602061444a868b613995565b510151169782604061445c8784613995565b5101511694806144c9575050511680925b03169203166146b3565b614793565b91821361449d5750906001600160801b0361449781936148e1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c4575090565b905090565b60409250906144db915f190190613995565b51015116809261446d565b936001600160801b03600191816144fd8886613995565b51511601169401958064ffffffffff8060406145198b87613995565b51015116989298614400565b91909160405161453481612a40565b5f81525f6020820152926001600160801b0382169081156145e55767016345785d8a000081116145ae576145706001600160801b0391836154fe565b166020850191818352111561459a576001600160801b03918261459592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f681612a40565b5f81525f602082015290565b9091926001600160a01b036146619481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261465c608483612a79565b614916565b565b614661926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261465c606483612a79565b600160ff1b81148015614786575b61475e575f811215614755576146e5815f035b5f84121561474e57835f039061499b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f575f199118131561471a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061499b565b6146e5816146d4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b806147ad57506147a957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f857806147d0575050670de0b6b3a764000090565b670de0b6b3a764000081146147f4576147ef906142d661373393614aa1565b614bf8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d4575b6148ac575f8112156148a357614838815f035b5f84121561489c57835f03906154fe565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486d575f199118131561471a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fe565b61483881614827565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614814565b5f81126148eb5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493f93169360208151910182865af16149386141da565b90836155ac565b8051908115159182614980575b50506149555750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149939250602080918301019101612e35565b155f8061494c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a665781841015614a2c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a73570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a73576ec097ce7bc90715b34b9f10000000000590565b805f811315614bcd57670de0b6b3a76400008112614bad57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9a57506706f05b59d3b20000905b5f8213614b645750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b8c575b60011d90614b57565b809192019160011d90614b83565b9050670de0b6b3a7640000929150020290565b5f1991508015614a73576ec097ce7bc90715b34b9f100000000005614abe565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c255768033dd1780914b971141981126137e957614c1c905f03614bf8565b61373390614a87565b680a688906bd8affffff81136154d357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539e575b670de0b6b3a76400009066ff000000000000831661528e575b65ff00000000008316615186575b64ff000000008316615086575b63ff0000008316614f8e575b62ff00008316614e9e575b61ff008316614db6575b60ff8316614cd6575b029060401c60bf031c90565b60808316614da3575b60408316614d90575b60208316614d7d575b60108316614d6a575b60088316614d57575b60048316614d44575b60028316614d31575b6001831615614cca57680100000000000000010260401c614cca565b680100000000000000010260401c614d15565b680100000000000000030260401c614d0c565b680100000000000000060260401c614d03565b6801000000000000000b0260401c614cfa565b680100000000000000160260401c614cf1565b6801000000000000002c0260401c614ce8565b680100000000000000590260401c614cdf565b6180008316614e8b575b6140008316614e78575b6120008316614e65575b6110008316614e52575b6108008316614e3f575b6104008316614e2c575b6102008316614e19575b610100831615614cc157680100000000000000b10260401c614cc1565b680100000000000001630260401c614dfc565b680100000000000002c60260401c614df2565b6801000000000000058c0260401c614de8565b68010000000000000b170260401c614dde565b6801000000000000162e0260401c614dd4565b68010000000000002c5d0260401c614dca565b680100000000000058b90260401c614dc0565b628000008316614f7b575b624000008316614f68575b622000008316614f55575b621000008316614f42575b620800008316614f2f575b620400008316614f1c575b620200008316614f09575b62010000831615614cb7576801000000000000b1720260401c614cb7565b680100000000000162e40260401c614eeb565b6801000000000002c5c80260401c614ee0565b68010000000000058b910260401c614ed5565b680100000000000b17210260401c614eca565b68010000000000162e430260401c614ebf565b680100000000002c5c860260401c614eb4565b6801000000000058b90c0260401c614ea9565b63800000008316615073575b63400000008316615060575b6320000000831661504d575b6310000000831661503a575b63080000008316615027575b63040000008316615014575b63020000008316615001575b6301000000831615614cac5768010000000000b172180260401c614cac565b6801000000000162e4300260401c614fe2565b68010000000002c5c8600260401c614fd6565b680100000000058b90c00260401c614fca565b6801000000000b17217f0260401c614fbe565b680100000000162e42ff0260401c614fb2565b6801000000002c5c85fe0260401c614fa6565b68010000000058b90bfc0260401c614f9a565b6480000000008316615173575b6440000000008316615160575b642000000000831661514d575b641000000000831661513a575b6408000000008316615127575b6404000000008316615114575b6402000000008316615101575b640100000000831615614ca057680100000000b17217f80260401c614ca0565b68010000000162e42ff10260401c6150e1565b680100000002c5c85fe30260401c6150d4565b6801000000058b90bfce0260401c6150c7565b68010000000b17217fbb0260401c6150ba565b6801000000162e42fff00260401c6150ad565b68010000002c5c8601cc0260401c6150a0565b680100000058b90c0b490260401c615093565b65800000000000831661527b575b654000000000008316615268575b652000000000008316615255575b651000000000008316615242575b65080000000000831661522f575b65040000000000831661521c575b650200000000008316615209575b65010000000000831615614c93576801000000b1721835510260401c614c93565b680100000162e430e5a20260401c6151e8565b6801000002c5c863b73f0260401c6151da565b68010000058b90cf1e6e0260401c6151cc565b680100000b1721bcfc9a0260401c6151be565b68010000162e43f4f8310260401c6151b0565b680100002c5c89d5ec6d0260401c6151a2565b6801000058b91b5bc9ae0260401c615194565b6680000000000000831661538b575b66400000000000008316615378575b66200000000000008316615365575b66100000000000008316615352575b6608000000000000831661533f575b6604000000000000831661532c575b66020000000000008316615319575b6601000000000000831615614c855768010000b17255775c040260401c614c85565b6801000162e525ee05470260401c6152f7565b68010002c5cc37da94920260401c6152e8565b680100058ba01fb9f96d0260401c6152d9565b6801000b175effdc76ba0260401c6152ca565b680100162f3904051fa10260401c6152bb565b6801002c605e2e8cec500260401c6152ac565b68010058c86da1c09ea20260401c61529d565b67800000000000000082166154b4575b670de0b6b3a76400009067400000000000000083166154a1575b672000000000000000831661548e575b671000000000000000831661547b575b6708000000000000008316615468575b6704000000000000008316615455575b6702000000000000008316615442575b670100000000000000831661542f575b9050614c6c565b680100b1afa5abcbed610260401c615428565b68010163da9fb33356d80260401c615418565b680102c9a3e778060ee70260401c615408565b6801059b0d31585743ae0260401c6153f8565b68010b5586cf9890f62a0260401c6153e8565b6801172b83c7d517adce0260401c6153d8565b6801306fe0a31b7152df0260401c6153c8565b5077b504f333f9de6484800000000000000000000000000000006153ae565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559b57670de0b6b3a764000082101561556b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e957508051156155c157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562f575b6155fa575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155f256fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_LINEAR = - hex"60a0604052346103bf57614b706040813803918261001c816103c3565b9384928339810103126103bf5780516001600160a01b03811691908290036103bf57602001516001600160a01b038116908190036103bf5761005e60406103c3565b91601c83527f5361626c696572205632204c6f636b7570204c696e656172204e465400000000602084015261009360406103c3565b601181527029a0a116ab1916a627a1a5aaa816a624a760791b60208201523060805283519092906001600160401b0381116102d057600154600181811c911680156103b5575b60208210146102b257601f8111610352575b50602094601f82116001146102ef579481929394955f926102e4575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102d057600254600181811c911680156102c6575b60208210146102b257601f811161024f575b506020601f82116001146101ec57819293945f926101e1575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478790816103e9823960805181613adb0152f35b015190505f80610168565b601f1982169060025f52805f20915f5b8181106102375750958360019596971061021f575b505050811b0160025561017d565b01515f1960f88460031b161c191690555f8080610211565b9192602060018192868b0151815501940192016101fc565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a8575b601f0160051c01905b81811061029d575061014f565b5f8155600101610290565b9091508190610287565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013d565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610107565b601f1982169560015f52805f20915f5b88811061033a57508360019596979810610322575b505050811b0160015561011c565b01515f1960f88460031b161c191690555f8080610314565b919260206001819286850151815501940192016102ff565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ab575b601f0160051c01905b8181106103a057506100eb565b5f8155600101610393565b909150819061038a565b90607f16906100d9565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102d05760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313757508063027b67441461311557806306fdde031461305a578063081812fc1461303c578063095ea7b314612f375780631400ecec14612e865780631c1cdd4c14612e225780631e99d56914612e0557806323b872dd14612dee578063303acc8514612db1578063406887cb14612c4257806340e58ee51461296b578063425d30dd1461291b57806342842e0e146128f257806342966c681461272e57806344267570146127085780634857501f146126975780634869e12d1461265d5780634cc55e11146122b657806353b157271461218b57806357404b12146120c55780636352211e146120965780636d0cee751461209657806370a082311461202c57806375829def14611fbe578063780a82c814611f725780637cad6cd114611e955780637de6b1db14611d485780638659c27014611991578063894e9a0d146116a95780638f69b993146116295780639067b677146115da57806395d89b41146114d2578063a22cb4651461141e578063a80fc071146113cd578063ab167ccc1461125c578063ad35efd4146111fd578063b2564569146111ad578063b88d4fde14611123578063b8a3be66146110ee578063b971302a146110a0578063bc2be1be14611051578063c156a11d14610c3c578063c87b56dd14610b31578063d4dbd20b14610ae0578063d511609f14610a95578063d975dfed14610a4a578063e985e9c5146109f1578063ea5ead19146106ac578063eac8f5b81461065b578063f590c17614610600578063f851a440146105db5763fdd46d6014610263575f80fd5b346105d75760603660031901126105d75760043561027f613264565b906102886133c6565b610290613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431b565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136aa565b6001600160801b036103b681602084015116928260408183511692015116906133fe565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b632187e5e760e21b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb8183613388565b8101906137e0565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b5061058684613b2b565b15610307565b8263d2aabcd960e01b5f5260045260245ffd5b82630ff7ee2d60e31b5f5260045260245ffd5b50634a5541ef60e01b5f5260045260245ffd5b5062b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105d7575f3660031901126105d75760206001600160a01b035f5416604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d75760403660031901126105d7576004356106c8613264565b906106d28161431b565b906106db613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c166109df576001600160a01b0383169182156109cc576001600160801b03169182156109b957815f5260036020526001600160a01b0360405f2054169384821415806109a9575b61098e576001600160801b036107678461431b565b168085116109745750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107dd600260405f20016136aa565b6001600160801b0361080181602084015116928260408183511692015116906133fe565b161115610942575b825f52600a60205261082d846001600160a01b03600160405f200154169283614341565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092c575b61089d575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090d575b5016036108fa578180610892565b50632187e5e760e21b5f5260045260245ffd5b610926915060203d6020116104d9576104cb8183613388565b856108ec565b50835f52600960205260ff60405f20541661088d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610809565b848463287ecaef60e21b5f5260045260245260445260645ffd5b509063b34359d360e01b5f526004523360245260445260645ffd5b506109b383613b2b565b15610752565b5063d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105d75760403660031901126105d757610a0a61324e565b6001600160a01b03610a1a613264565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a8460209161431b565b6001600160801b0360405191168152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a6020526020600260405f20015460801c604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d75760203660031901126105d757600435610b4e81613800565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bbf575b610bbb90604051918291602083526020830190613229565b0390f35b503d805f833e610bcf8183613388565b8101906020818303126105d75780519067ffffffffffffffff82116105d757019080601f830112156105d757815191610c07836133aa565b91610c156040519384613388565b838352602084830101116105d757610bbb92610c379160208085019101613208565b610ba3565b346105d75760403660031901126105d757600435610c58613264565b610c60613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103a576001600160801b03610caa8461431b565b169081158015610d33575b506001600160a01b03811615610d2057610cd7846001600160a01b0392613997565b169182610cf15783637e27328960e01b5f5260045260245ffd5b8084918403610d0557602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3b613ad1565b845f52600a60205260ff600160405f20015460a81c161561102857845f52600a60205260ff600160405f20015460a01c1661101557831561100257610fef57835f5260036020526001600160a01b0360405f2054168084141580610fdf575b610fc4576001600160801b03610daf8661431b565b16808411610faa5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e0e90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e25600260405f20016136aa565b6001600160801b03610e4981602084015116928260408183511692015116906133fe565b161115610f78575b845f52600a6020526001600160a01b03600160405f20015416610e75848683614341565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f62575b15610cb5576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f43575b501614610cb557632187e5e760e21b5f5260045260245ffd5b610f5c915060203d6020116104d9576104cb8183613388565b88610f2a565b50805f52600960205260ff60405f205416610ed5565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e51565b838663287ecaef60e21b5f5260045260245260445260645ffd5b838563b34359d360e01b5f526004523360245260445260645ffd5b50610fe985613b2b565b15610d9a565b8363d2aabcd960e01b5f5260045260245ffd5b84630ff7ee2d60e31b5f5260045260245ffd5b84634a5541ef60e01b5f5260045260245ffd5b8462b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d75760203660031901126105d7576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d75760803660031901126105d75761113c61324e565b611144613264565b6064359167ffffffffffffffff83116105d757366023840112156105d757826004013591611171836133aa565b9261117f6040519485613388565b80845236602482870101116105d7576020815f9260246111ab98018388013785010152604435916136f0565b005b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761123590613903565b6040516005821015611248576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d7576101403660031901126105d757611276613ad1565b61127e61368c565b64ffffffffff421680825264ffffffffff6112976136dc565b166113b2575b60e43564ffffffffff811681036105d75764ffffffffff9101166040820152600435906001600160a01b038216918281036105d757506024356001600160a01b038116908181036105d757506044356001600160801b038116908181036105d757506064356001600160a01b0381168091036105d75760843591821515928381036105d7575060a43593841515948581036105d7575060405196611340886132e5565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d7576040519061137a8261336c565b61010435906001600160a01b03821682036105d757826113aa9260209452610124358482015260e0820152613c21565b604051908152f35b64ffffffffff6113c06136dc565b820116602083015261129d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d75760403660031901126105d75761143761324e565b602435908115158092036105d7576001600160a01b03169081156114a657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7575f3660031901126105d7576040515f6002548060011c906001811680156115d0575b6020831081146115bc57828552908115611598575060011461153a575b610bbb8361152681850382613388565b604051918291602083526020830190613229565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061157e57509091508101602001611526611516565b919260018160209254838588010152019101909291611566565b60ff191660208086019190915291151560051b840190910191506115269050611516565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114f9565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a5761166190613903565b600581101580611248576002821490811561169d575b811561168b575b6020826040519015158152f35b9050611248576004602091148261167e565b5050600381145f611677565b346105d75760203660031901126105d7576004355f6101606040516116cd81613332565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e0820152826101008201528261012082015261171061368c565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260405f2060405161174b8161334f565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ea600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136aa565b61012083019081526117fb87613903565b600581101561124857600214611989575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188181613332565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180c565b346105d75760203660031901126105d75760043567ffffffffffffffff81116105d7576119c29036906004016132b4565b906119cb613ad1565b5f915b8083106119d757005b6119e2838284613668565b35926119ec613ad1565b835f52600a60205260ff600160405f20015460a81c1615611d3657835f52600a60205260ff600160405f20015460a01c165f14611a365783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2457611a6b815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57611a7981613821565b90805f52600a602052611a91600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081611ae59481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc3575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bf76001600160a01b03600160405f2001541694611bcf888588614341565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c48575b505050505060010191906119ce565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca5575b50160361049f5780808080611c39565b611cbd915060203d81116104d9576104cb8183613388565b87611c95565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b2f565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105d75760203660031901126105d757600435611d64613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57611d8881613903565b60058110156112485760048103611dac5750634a5541ef60e01b5f5260045260245ffd5b60038103611dc7575063fe19f19f60e01b5f5260045260245ffd5b600214611e8357611dec815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57805f52600a60205260ff60405f205460f01c1615611e71576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105d75760203660031901126105d7576004356001600160a01b0381168091036105d7576001600160a01b035f5416338103611f5c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d75760203660031901126105d757611fd761324e565b5f546001600160a01b038116338103611f5c57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d75760203660031901126105d7576001600160a01b0361204d61324e565b16801561206a575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d75760203660031901126105d75760206120b4600435613800565b6001600160a01b0360405191168152f35b346105d75760203660031901126105d7576004356120e161368c565b50805f52600a60205260ff600160405f20015460a81c161561064a57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261215184613316565b835260208301526040820152612189604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d7576101603660031901126105d7576121a5613ad1565b6040516121b1816132e5565b6121b961324e565b81526121c3613264565b60208201526121d06133c6565b60408201526064356001600160a01b03811681036105d757606082015260843580151581036105d757608082015260a43580151581036105d75760a082015260603660c31901126105d75760405161222781613316565b60c43564ffffffffff811681036105d757815260e43564ffffffffff811681036105d75760208201526101043564ffffffffff811681036105d757604082015260c08201526040610123193601126105d757604051906122868261336c565b61012435906001600160a01b03821682036105d757826113aa9260209452610144358482015260e0820152613c21565b346105d75760403660031901126105d75760043567ffffffffffffffff81116105d7576122e79036906004016132b4565b60243567ffffffffffffffff81116105d7576123079036906004016132b4565b612312939193613ad1565b80830361262e575f5b83811061232457005b61232f818585613668565b3561233b828686613668565b355f5260036020526001600160a01b0360405f2054169061235d838589613668565b356001600160801b038116908181036105d75750612379613ad1565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109cc5780156109b957815f5260036020526001600160a01b0360405f20541692838114158061261e575b612604576001600160801b036123f08461431b565b168083116125ea5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761244f90845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052612466600260405f20016136aa565b6001600160801b0361248a81602084015116928260408183511692015116906133fe565b1611156125b8575b825f52600a6020526001600160a01b03600160405f200154166124b6838383614341565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a2575b612527575b5050505060010161231b565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612584575b50160361049f5780808061251b565b61259c915060203d81116104d9576104cb8183613388565b89612575565b50835f52600960205260ff60405f205416612516565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612492565b828463287ecaef60e21b5f5260045260245260445260645ffd5b8263b34359d360e01b5f526004523360245260445260645ffd5b5061262883613b2b565b156123db565b827faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57610a84602091613b9d565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f6126d082613903565b6005811015611248576002036126ee575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e1565b346105d7575f3660031901126105d75760206001600160a01b0360085416604051908152f35b346105d75760203660031901126105d75760043561274a613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c16156128c75761278981613b2b565b15611d0e57805f5260036020526001600160a01b0360405f2054161515806128c0575b806128a3575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285a575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284857005b637e27328960e01b5f5260045260245ffd5b612879835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612800565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b2565b505f6127ac565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d7576111ab6129033661327a565b9060405192612913602085613388565b5f84526136f0565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d75760203660031901126105d757600435612987613ad1565b805f52600a60205260ff600160405f20015460a81c161561064a57805f52600a60205260ff600160405f20015460a01c165f146129d057634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2457612a02815f52600a6020526001600160a01b0360405f205416331490565b15611d0e57612a1081613821565b90805f52600a602052612a28600260405f20016136aa565b916001600160801b038351166001600160801b0382161015611cfb57815f52600a60205260ff60405f205460f01c1615611ce857806001600160801b03602081612a7c9481885116031695015116906133fe565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c1d575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b666001600160a01b03600160405f2001541694611bcf888588614341565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612ba957005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612bfe5750160361049f57005b612c17915060203d6020116104d9576104cb8183613388565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612ac6565b346105d75760203660031901126105d757612c5b61324e565b6001600160a01b035f541690338203612d9a57806001600160a01b03913b15612d6e57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d3f575b5015612d1457805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d61915060203d602011612d67575b612d598183613388565b810190613650565b82612cc9565b503d612d4f565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d75760203660031901126105d7576001600160a01b03612dd261324e565b165f526009602052602060ff60405f2054166040519015158152f35b346105d7576111ab612dff3661327a565b9161341e565b346105d7575f3660031901126105d7576020600754604051908152f35b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a57612e5a90613903565b6005811015611248578060209115908115612e7b575b506040519015158152f35b600191501482612e70565b346105d75760203660031901126105d757600435805f52600a60205260ff600160405f20015460a81c161561064a576020905f90805f52600a835260ff60405f205460f01c1680612f1b575b612ee9575b506001600160801b0360405191168152f35b612f159150805f52600a8352612f0f6001600160801b03600260405f2001541691613821565b906133fe565b82612ed7565b50805f52600a835260ff600160405f20015460a01c1615612ed2565b346105d75760403660031901126105d757612f5061324e565b602435612f5c81613800565b33151580613029575b80612ff6575b612fca5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6b565b50336001600160a01b0382161415612f65565b346105d75760203660031901126105d75760206120b46004356133dc565b346105d7575f3660031901126105d7576040515f6001548060011c9060018116801561310b575b6020831081146115bc5782855290811561159857506001146130ad57610bbb8361152681850382613388565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f157509091508101602001611526611516565b9192600181602092548385880101520191019092916130d9565b91607f1691613081565b346105d7575f3660031901126105d757602060405167016345785d8a00008152f35b346105d75760203660031901126105d757600435906001600160e01b031982168092036105d757817f490649060000000000000000000000000000000000000000000000000000000060209314908115613193575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131de575b81156131cd575b508361318c565b6301ffc9a760e01b915014836131c6565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131bf565b5f5b8381106132195750505f910152565b818101518382015260200161320a565b9060209161324281518092818552858086019101613208565b601f01601f1916010190565b600435906001600160a01b03821682036105d757565b602435906001600160a01b03821682036105d757565b60609060031901126105d7576004356001600160a01b03811681036105d757906024356001600160a01b03811681036105d7579060443590565b9181601f840112156105d75782359167ffffffffffffffff83116105d7576020808501948460051b0101116105d757565b610100810190811067ffffffffffffffff82111761330257604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330257604052565b610180810190811067ffffffffffffffff82111761330257604052565b610140810190811067ffffffffffffffff82111761330257604052565b6040810190811067ffffffffffffffff82111761330257604052565b90601f8019910116810190811067ffffffffffffffff82111761330257604052565b67ffffffffffffffff811161330257601f01601f191660200190565b604435906001600160801b03821682036105d757565b6133e581613800565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2057815f5260036020526001600160a01b0360405f205416151580613648575b8061362b575b613618577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613563575b6001600160a01b0393508561352c575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351457505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354b825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b3565b91929050806135c1575b1561357a578282916134a3565b828461359257637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135ef575b8061356d5750825f526005602052336001600160a01b0360405f2054161461356d565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135cc565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613453565b50600161344d565b908160209103126105d7575180151581036105d75790565b91908110156136785760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369982613316565b5f6040838281528260208201520152565b906040516136b781613316565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d75790565b906136fc83828461341e565b803b613709575b50505050565b60209161374f6001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613229565b03815f865af15f91816137bf575b5061378b575061376b6142ec565b805190816137865782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137ad57505f808080613703565b633250574960e11b5f5260045260245ffd5b6137d991925060203d6020116104d9576104cb8183613388565b905f61375d565b908160209103126105d757516001600160e01b0319811681036105d75790565b805f5260036020526001600160a01b0360405f205416908115612848575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138f9575b6138f357815f52600a60205264ffffffffff60405f205460c81c1690814210156138d6578061388892039042036144cf565b815f52600a6020526138ab6001600160801b03600260405f2001541680926145bb565b9081116138c0576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b5042811015613856565b805f52600a60205260ff600160405f20015460a01c165f146139255750600490565b805f52600a60205260405f205460f81c61399157805f52600a60205264ffffffffff60405f205460a01c16421061398c5761395f81613821565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398757600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613abf575b80613aa2575b612891577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6b575b1680613a53575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a0f565b613a8a835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a08565b50805f52600a60205260ff600160405f20015460b01c16156139bc565b506001600160a01b03821615156139b6565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0357565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b71575b508115613b58575090565b90506001600160a01b03613b6c33926133dc565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b4d565b805f52600a602052613bb4600260405f20016136aa565b90805f52600a60205260ff600160405f20015460a01c165f14613be25750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c045750613c0190613821565b90565b613c0191506001600160801b0360408183511692015116906133fe565b90613c426001600160801b03604084015116602060e0850151015190614398565b916001600160801b0383511660c082015190156142c45764ffffffffff8151161561429c576020810164ffffffffff81511680614210575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e257505064ffffffffff80421691511690818110156141b45750506007549280516001600160801b03169160405192613cd284613316565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d388961334f565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fb891906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614194575b50600185016007556001600160a01b036020820151168015610d2057614026866001600160a01b0392613997565b16614168576140516001600160a01b036060830151166001600160801b038451169030903390614475565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b0386511680614139575b506141306001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614162906001600160a01b036060880151166001600160a01b0360e08901515116903390614475565b5f61408c565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ff8565b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f5057f084000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561426e57505064ffffffffff90511664ffffffffff60408301511690818110613c7a577f9fee2691000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fb39831ea000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d15614316573d906142fd826133aa565b9161430b6040519384613388565b82523d5f602084013e565b606090565b613c019061432881613b9d565b905f52600a602052600260405f20015460801c906133fe565b614396926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252614391606483613388565b614669565b565b9190916040516143a78161336c565b5f81525f6020820152926001600160801b0382169081156144585767016345785d8a00008111614421576143e36001600160801b0391836145bb565b166020850191818352111561440d576001600160801b039182614408925116906133fe565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516144698161336c565b5f81525f602082015290565b9091926001600160a01b036143969481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252614391608483613388565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459a578184101561456057670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145a7570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465857670de0b6b3a7640000821015614628577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469293169360208151910182865af161468b6142ec565b90836146ee565b80519081151591826146d3575b50506146a85750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146e69250602080918301019101613650565b155f8061469f565b9061472b575080511561470357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614771575b61473c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473456fea164736f6c634300081a000a"; + hex"60a0604052346103bc57614b716040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478b90816103e6823960805181613adf0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313b57508063027b67441461311957806306fdde031461305e578063081812fc14613040578063095ea7b314612f3b5780631400ecec14612e8a5780631c1cdd4c14612e265780631e99d56914612e0957806323b872dd14612df2578063303acc8514612db5578063406887cb14612c4657806340e58ee51461296f578063425d30dd1461291f57806342842e0e146128f657806342966c6814612732578063442675701461270c5780634857501f1461269b5780634869e12d146126615780634cc55e11146122ba57806353b157271461218f57806357404b12146120c95780636352211e1461209a5780636d0cee751461209a57806370a082311461203057806375829def14611fc2578063780a82c814611f765780637cad6cd114611e995780637de6b1db14611d4c5780638659c27014611994578063894e9a0d146116ac5780638f69b9931461162c5780639067b677146115dd57806395d89b41146114d5578063a22cb46514611421578063a80fc071146113d0578063ab167ccc1461125f578063ad35efd414611200578063b2564569146111b0578063b88d4fde14611126578063b8a3be66146110f1578063b971302a146110a3578063bc2be1be14611054578063c156a11d14610c3e578063c87b56dd14610b33578063d4dbd20b14610ae2578063d511609f14610a97578063d975dfed14610a4c578063e985e9c5146109f3578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613268565b906102886133ca565b610290613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431f565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ae565b6001600160801b036103b68160208401511692826040818351169201511690613402565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338c565b8101906137e4565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061058684613b2f565b15610307565b8263b2ae763360e01b5f5260045260245ffd5b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613268565b906106d48161431f565b906106dd613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109e1576001600160a01b0383169182156109ce576001600160801b03169182156109bb57815f5260036020526001600160a01b0360405f2054169384821415806109ab575b610990576001600160801b036107698461431f565b168085116109765750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c890845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107df600260405f20016136ae565b6001600160801b036108038160208401511692826040818351169201511690613402565b161115610944575b825f52600a60205261082f846001600160a01b03600160405f200154169283614345565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092e575b61089f575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090f575b5016036108fc578180610894565b50636ade251160e01b5f5260045260245ffd5b610928915060203d6020116104d9576104cb818361338c565b856108ee565b50835f52600960205260ff60405f20541661088f565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561080b565b848463066920d760e01b5f5260045260245260445260645ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109b583613b2f565b15610754565b5063b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0c613252565b6001600160a01b03610a1c613268565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8660209161431f565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b5081613804565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bc1575b610bbd9060405191829160208352602083019061322d565b0390f35b503d805f833e610bd1818361338c565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c09836133ae565b91610c17604051938461338c565b838352602084830101116105d857610bbd92610c39916020808501910161320c565b610ba5565b346105d85760403660031901126105d857600435610c5a613268565b610c62613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103d576001600160801b03610cac8461431f565b169081158015610d35575b506001600160a01b03811615610d2257610cd9846001600160a01b039261399b565b169182610cf35783637e27328960e01b5f5260045260245ffd5b8084918403610d0757602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3d613ad5565b845f52600a60205260ff600160405f20015460a81c161561102a57845f52600a60205260ff600160405f20015460a01c1661101757831561100457610ff157835f5260036020526001600160a01b0360405f2054168084141580610fe1575b610fc6576001600160801b03610db18661431f565b16808411610fac5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e1090865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e27600260405f20016136ae565b6001600160801b03610e4b8160208401511692826040818351169201511690613402565b161115610f7a575b845f52600a6020526001600160a01b03600160405f20015416610e77848683614345565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f64575b15610cb7576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f45575b501614610cb757636ade251160e01b5f5260045260245ffd5b610f5e915060203d6020116104d9576104cb818361338c565b88610f2c565b50805f52600960205260ff60405f205416610ed7565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e53565b838663066920d760e01b5f5260045260245260445260645ffd5b838563350b320360e11b5f526004523360245260445260645ffd5b50610feb85613b2f565b15610d9c565b8363b2ae763360e01b5f5260045260245ffd5b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113f613252565b611147613268565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611174836133ae565b92611182604051948561338c565b80845236602482870101116105d8576020815f9260246111ae98018388013785010152604435916136f4565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123890613907565b604051600582101561124b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611279613ad5565b611281613690565b64ffffffffff421680825264ffffffffff61129a6136e0565b166113b5575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611343886132e9565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137d82613370565b61010435906001600160a01b03821682036105d857826113ad9260209452610124358482015260e0820152613c25565b604051908152f35b64ffffffffff6113c36136e0565b82011660208301526112a0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d85761143a613252565b602435908115158092036105d8576001600160a01b03169081156114a957335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d3575b6020831081146115bf5782855290811561159b575060011461153d575b610bbd836115298185038261338c565b60405191829160208352602083019061322d565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158157509091508101602001611529611519565b919260018160209254838588010152019101909291611569565b60ff191660208086019190915291151560051b840190910191506115299050611519565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fc565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166490613907565b60058110158061124b57600282149081156116a0575b811561168e575b6020826040519015158152f35b905061124b5760046020911482611681565b5050600381145f61167a565b346105d85760203660031901126105d8576004355f6101606040516116d081613336565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611713613690565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174e81613353565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ed600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ae565b61012083019081526117fe87613907565b600581101561124b5760021461198c575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188481613336565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180f565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c59036906004016132b8565b906119ce613ad5565b5f915b8083106119da57005b6119e583828461366c565b35926119ef613ad5565b835f52600a60205260ff600160405f20015460a81c1615611d3957835f52600a60205260ff600160405f20015460a01c165f14611a3957836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2757611a6e815f52600a6020526001600160a01b0360405f205416331490565b15611d1157611a7c81613825565b90805f52600a602052611a94600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081611ae8948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc6575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bfa6001600160a01b03600160405f2001541694611bd2888588614345565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4b575b505050505060010191906119d1565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca8575b50160361049f5780808080611c3c565b611cc0915060203d81116104d9576104cb818361338c565b87611c98565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b32565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d68613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8c81613907565b600581101561124b5760048103611db057506315efa0f360e11b5f5260045260245ffd5b60038103611dcb575063d0a172b360e01b5f5260045260245ffd5b600214611e8757611df0815f52600a6020526001600160a01b0360405f205416331490565b15611d1157805f52600a60205260ff60405f205460f01c1615611e75576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f60575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fdb613252565b5f546001600160a01b038116338103611f6057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612051613252565b16801561206e575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b8600435613804565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e5613690565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926121558461331a565b83526020830152604082015261218d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a9613ad5565b6040516121b5816132e9565b6121bd613252565b81526121c7613268565b60208201526121d46133ca565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222b8161331a565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d8576040519061228a82613370565b61012435906001600160a01b03821682036105d857826113ad9260209452610144358482015260e0820152613c25565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122eb9036906004016132b8565b60243567ffffffffffffffff81116105d85761230b9036906004016132b8565b612316939193613ad5565b808303612632575f5b83811061232857005b61233381858561366c565b3561233f82868661366c565b355f5260036020526001600160a01b0360405f2054169061236183858961366c565b356001600160801b038116908181036105d8575061237d613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109ce5780156109bb57815f5260036020526001600160a01b0360405f205416928381141580612622575b612608576001600160801b036123f48461431f565b168083116125ee5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261246a600260405f20016136ae565b6001600160801b0361248e8160208401511692826040818351169201511690613402565b1611156125bc575b825f52600a6020526001600160a01b03600160405f200154166124ba838383614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a6575b61252b575b5050505060010161231f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612588575b50160361049f5780808061251f565b6125a0915060203d81116104d9576104cb818361338c565b89612579565b50835f52600960205260ff60405f20541661251a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612496565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262c83613b2f565b156123df565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a86602091613ba1565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d482613907565b600581101561124b576002036126f2575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e5565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274e613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128cb5761278d81613b2f565b15611d1157805f5260036020526001600160a01b0360405f2054161515806128c4575b806128a7575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284c57005b637e27328960e01b5f5260045260245ffd5b61287d835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612804565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b6565b505f6127b0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ae6129073661327e565b906040519261291760208561338c565b5f84526136f4565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298b613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d4576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2757612a06815f52600a6020526001600160a01b0360405f205416331490565b15611d1157612a1481613825565b90805f52600a602052612a2c600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081612a80948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c21575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b6a6001600160a01b03600160405f2001541694611bd2888588614345565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bad57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c025750160361049f57005b612c1b915060203d6020116104d9576104cb818361338c565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612aca565b346105d85760203660031901126105d857612c5f613252565b6001600160a01b035f541690338203612d9e57806001600160a01b03913b15612d7257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d43575b5015612d1857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d65915060203d602011612d6b575b612d5d818361338c565b810190613654565b82612ccd565b503d612d53565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd6613252565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ae612e033661327e565b91613422565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5e90613907565b600581101561124b578060209115908115612e7f575b506040519015158152f35b600191501482612e74565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1f575b612eed575b506001600160801b0360405191168152f35b612f199150805f52600a8352612f136001600160801b03600260405f2001541691613825565b90613402565b82612edb565b50805f52600a835260ff600160405f20015460a01c1615612ed6565b346105d85760403660031901126105d857612f54613252565b602435612f6081613804565b3315158061302d575b80612ffa575b612fce5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6f565b50336001600160a01b0382161415612f69565b346105d85760203660031901126105d85760206120b86004356133e0565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310f575b6020831081146115bf5782855290811561159b57506001146130b157610bbd836115298185038261338c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f557509091508101602001611529611519565b9192600181602092548385880101520191019092916130dd565b91607f1691613085565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613197575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e2575b81156131d1575b5083613190565b6301ffc9a760e01b915014836131ca565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c3565b5f5b83811061321d5750505f910152565b818101518382015260200161320e565b906020916132468151809281855285808601910161320c565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330657604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330657604052565b610180810190811067ffffffffffffffff82111761330657604052565b610140810190811067ffffffffffffffff82111761330657604052565b6040810190811067ffffffffffffffff82111761330657604052565b90601f8019910116810190811067ffffffffffffffff82111761330657604052565b67ffffffffffffffff811161330657601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e981613804565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2257815f5260036020526001600160a01b0360405f20541615158061364c575b8061362f575b61361c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613567575b6001600160a01b03935085613530575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354f825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b7565b91929050806135c5575b1561357e578282916134a7565b828461359657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f3575b806135715750825f526005602052336001600160a01b0360405f20541614613571565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135d0565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613457565b506001613451565b908160209103126105d8575180151581036105d85790565b919081101561367c5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369d8261331a565b5f6040838281528260208201520152565b906040516136bb8161331a565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b90613700838284613422565b803b61370d575b50505050565b6020916137536001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322d565b03815f865af15f91816137c3575b5061378f575061376f6142f0565b8051908161378a5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b157505f808080613707565b633250574960e11b5f5260045260245ffd5b6137dd91925060203d6020116104d9576104cb818361338c565b905f613761565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284c575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fd575b6138f757815f52600a60205264ffffffffff60405f205460c81c1690814210156138da578061388c92039042036144d3565b815f52600a6020526138af6001600160801b03600260405f2001541680926145bf565b9081116138c4576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281101561385a565b805f52600a60205260ff600160405f20015460a01c165f146139295750600490565b805f52600a60205260405f205460f81c61399557805f52600a60205264ffffffffff60405f205460a01c1642106139905761396381613825565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398b57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac3575b80613aa6575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6f575b1680613a57575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a13565b613a8e835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0c565b50805f52600a60205260ff600160405f20015460b01c16156139c0565b506001600160a01b03821615156139ba565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0757565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b75575b508115613b5c575090565b90506001600160a01b03613b7033926133e0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b51565b805f52600a602052613bb8600260405f20016136ae565b90805f52600a60205260ff600160405f20015460a01c165f14613be65750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c085750613c0590613825565b90565b613c0591506001600160801b036040818351169201511690613402565b90613c466001600160801b03604084015116602060e085015101519061439c565b916001600160801b0383511660c082015190156142c85764ffffffffff815116156142a0576020810164ffffffffff81511680614214575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e657505064ffffffffff80421691511690818110156141b85750506007549280516001600160801b03169160405192613cd68461331a565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d3c89613353565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fbc91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614198575b50600185016007556001600160a01b036020820151168015610d225761402a866001600160a01b039261399b565b1661416c576140556001600160a01b036060830151166001600160801b038451169030903390614479565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061413d575b506141346001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614166906001600160a01b036060880151166001600160a01b0360e08901515116903390614479565b5f614090565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ffc565b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561427257505064ffffffffff90511664ffffffffff60408301511690818110613c7e577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561431a573d90614301826133ae565b9161430f604051938461338c565b82523d5f602084013e565b606090565b613c059061432c81613ba1565b905f52600a602052600260405f20015460801c90613402565b61439a926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261439560648361338c565b61466d565b565b9190916040516143ab81613370565b5f81525f6020820152926001600160801b03821690811561445c5767016345785d8a00008111614425576143e76001600160801b0391836145bf565b1660208501918183521115614411576001600160801b03918261440c92511690613402565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446d81613370565b5f81525f602082015290565b9091926001600160a01b0361439a9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261439560848361338c565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459e578184101561456457670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145ab570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465c57670de0b6b3a764000082101561462c577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469693169360208151910182865af161468f6142f0565b90836146f2565b80519081151591826146d7575b50506146ac5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146ea9250602080918301019101613654565b155f806146a3565b9061472f575080511561470757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614775575b614740575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473856fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = - hex"60c0604052346103e457614e2e6060813803918261001c816103e8565b9384928339810103126103e45780516001600160a01b038116908190036103e45760208201516001600160a01b03811692908390036103e4576040015161006360406103e8565b92601e84527f5361626c696572205632204c6f636b7570205472616e63686564204e46540000602085015261009860406103e8565b60118152705341422d56322d4c4f434b55502d54524160781b602082015230608052845190946001600160401b0382116102e75760015490600182811c921680156103da575b60208310146102c95781601f84931161036c575b50602090601f8311600114610306575f926102fb575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e757600254600181811c911680156102dd575b60208210146102c957601f8111610266575b50602094601f8211600114610203579481929394955f926101f8575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a20908161040e823960805181613e32015260a051818181612fa10152613edb0152f35b015190505f8061016c565b601f1982169560025f52805f20915f5b88811061024e57508360019596979810610236575b505050811b01600255610181565b01515f1960f88460031b161c191690555f8080610228565b91926020600181928685015181550194019201610213565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bf575b601f0160051c01905b8181106102b45750610150565b5f81556001016102a7565b909150819061029e565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013e565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610108565b60015f9081528281209350601f198516905b818110610354575090846001959493921061033c575b505050811b0160015561011d565b01515f1960f88460031b161c191690555f808061032e565b92936020600181928786015181550195019301610318565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103d0575b90601f859493920160051c01905b8181106103c257506100f2565b5f81558493506001016103b5565b90915081906103a7565b91607f16916100de565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e75760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461330d57508063027b6744146132eb57806306fdde0314613230578063081812fc14613212578063095ea7b31461310d5780631400ecec1461305c5780631c1cdd4c14612ff85780631e99d56914612fdb57806323b872dd14612fc45780632fe4304114612f8a578063303acc8514612f4d57806332fbe22b14612df0578063406887cb14612c8157806340e58ee5146129aa578063425d30dd1461295a57806342842e0e1461293157806342966c681461276d57806344267570146127475780634857501f146126d65780634869e12d1461269c5780634cc55e11146122f657806357404b12146122685780636352211e146122395780636d0cee751461223957806370a08231146121cf57806375829def146121615780637cad6cd1146120705780637de6b1db14611f235780637f5799f914611eca5780638659c27014611b13578063894e9a0d146117d4578063897f362b146115095780638f69b993146114895780639067b6771461143a57806395d89b4114611332578063a22cb4651461127e578063a80fc0711461122d578063ad35efd4146111ce578063b25645691461117e578063b88d4fde146110f4578063b8a3be66146110bf578063b971302a14611071578063bc2be1be14611022578063c156a11d14610c08578063c87b56dd14610afd578063d4dbd20b14610aac578063d511609f14610a61578063d975dfed14610a16578063e985e9c5146109bd578063ea5ead1914610690578063eac8f5b81461063f578063f590c176146105e4578063f851a440146105bf5763fdd46d601461026e575f80fd5b346105bb5760603660031901126105bb5760043561028a61343a565b90604435916001600160801b038316908184036105bb576102a9613e28565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614680565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146a6565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139ce565b6001600160801b036103ae8160208401511692826040818351169201511690613611565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b632187e5e760e21b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c3818361359d565b810190613b11565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663287ecaef60e21b5f5260045260245260445260645ffd5b828563b34359d360e01b5f526004523360245260445260645ffd5b5061056a8561455b565b15610316565b8363d2aabcd960e01b5f5260045260245ffd5b83630ff7ee2d60e31b5f5260045260245ffd5b82634a5541ef60e01b5f5260045260245ffd5b8262b8e7e760e51b5f5260045260245ffd5b5f80fd5b346105bb575f3660031901126105bb5760206001600160a01b035f5416604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060405f205460f81c6040519015158152f35b62b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bb5760403660031901126105bb576004356106ac61343a565b6106b582614680565b916106be613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c166109ab576001600160a01b0382168015610998576001600160801b03841692831561098557825f5260036020526001600160a01b0360405f205416948583141580610975575b61095a576001600160801b0361074a85614680565b16808611610940575061076f90845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107a9906139ce565b6001600160801b036107cd8160208401511692826040818351169201511690613611565b16111561090e575b825f52600a6020526107f9846001600160a01b03600160405f200154169283614804565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108f8575b610869575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108d9575b5016036108c657818061085e565b50632187e5e760e21b5f5260045260245ffd5b6108f2915060203d6020116104d1576104c3818361359d565b856108b8565b50835f52600960205260ff60405f205416610859565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d5565b858563287ecaef60e21b5f5260045260245260445260645ffd5b828463b34359d360e01b5f526004523360245260445260645ffd5b5061097f8461455b565b15610735565b8263d2aabcd960e01b5f5260045260245ffd5b50630ff7ee2d60e31b5f5260045260245ffd5b634a5541ef60e01b5f5260045260245ffd5b346105bb5760403660031901126105bb576109d6613424565b6001600160a01b036109e661343a565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a50602091614680565b6001600160801b0360405191168152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a6020526020600260405f20015460801c604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bb5760203660031901126105bb57600435610b1a81613b31565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8b575b610b87906040519182916020835260208301906133ff565b0390f35b503d805f833e610b9b818361359d565b8101906020818303126105bb5780519067ffffffffffffffff82116105bb57019080601f830112156105bb57815191610bd3836135bf565b91610be1604051938461359d565b838352602084830101116105bb57610b8792610c0391602080850191016133de565b610b6f565b346105bb5760403660031901126105bb57600435610c2461343a565b610c2c613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f5260036020526001600160a01b0360405f20541690813303610ff957610c6e83614680565b906001600160801b0382169182158015610d02575b50506001600160a01b03811615610cef57610ca6846001600160a01b0392613cee565b169182610cc05783637e27328960e01b5f5260045260245ffd5b8084918403610cd457602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0a613e28565b855f52600a60205260ff600160405f20015460a81c1615610fe757855f52600a60205260ff600160405f20015460a01c16610fd4578415610fc157610fae57845f5260036020526001600160a01b0360405f205416908185141580610f9e575b610f83576001600160801b03610d7f87614680565b16808511610f695750610da490865f52600a602052600260405f20015460801c6146a6565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610dde906139ce565b6001600160801b03610e028160208401511692826040818351169201511690613611565b161115610f37575b845f52600a6020526001600160a01b03600160405f20015416610e2e848683614804565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f21575b610e99575b80610c83565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f02575b501614610e9357632187e5e760e21b5f5260045260245ffd5b610f1b915060203d6020116104d1576104c3818361359d565b88610ee9565b50805f52600960205260ff60405f205416610e8e565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0a565b848763287ecaef60e21b5f5260045260245260445260645ffd5b848663b34359d360e01b5f526004523360245260445260645ffd5b50610fa88661455b565b15610d6a565b8463d2aabcd960e01b5f5260045260245ffd5b85630ff7ee2d60e31b5f5260045260245ffd5b85634a5541ef60e01b5f5260045260245ffd5b8562b8e7e760e51b5f5260045260245ffd5b8263216caf0d60e01b5f526004523360245260445ffd5b5062b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bb5760203660031901126105bb576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bb5760803660031901126105bb5761110d613424565b61111561343a565b6064359167ffffffffffffffff83116105bb57366023840112156105bb57826004013591611142836135bf565b92611150604051948561359d565b80845236602482870101116105bb576020815f92602461117c9801838801378501015260443591613a21565b005b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761120690613c5a565b6040516005821015611219576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bb5760403660031901126105bb57611297613424565b602435908115158092036105bb576001600160a01b031690811561130657335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb575f3660031901126105bb576040515f6002548060011c90600181168015611430575b60208310811461141c578285529081156113f8575060011461139a575b610b87836113868185038261359d565b6040519182916020835260208301906133ff565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113de57509091508101602001611386611376565b9192600181602092548385880101520191019092916113c6565b60ff191660208086019190915291151560051b840190910191506113869050611376565b634e487b7160e01b5f52602260045260245ffd5b91607f1691611359565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576114c190613c5a565b60058110158061121957600282149081156114fd575b81156114eb575b6020826040519015158152f35b905061121957600460209114826114de565b5050600381145f6114d7565b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb578036036101206003198201126105bb57611544613e28565b60c482013590602219018112156105bb5781019060048201359167ffffffffffffffff83116105bb5760248101908360061b80360383136105bb57600460209161158d87613875565b9661159b604051988961359d565b875282870193010101913683116105bb57905b8282106117ba575050508151916115c483613875565b926115d2604051948561359d565b808452601f196115e182613875565b015f5b81811061179757505064ffffffffff4216916001600160801b0361160782613b52565b51511664ffffffffff80602061161c85613b52565b510151168501166040519161163083613548565b8252602082015261164086613b52565b5261164a85613b52565b5060015b8281106117225750505061166482600401613a00565b9261167160248401613a00565b9261167e6044820161392e565b916064820135936001600160a01b0385168095036105bb5760209661171a966116da966001600160801b0361170f976001600160a01b036116c160848a01613a14565b94816116cf60a48c01613a14565b976040519d8e61352b565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c3565b610100820152613e82565b604051908152f35b806001600160801b0361173760019385613b5f565b51511664ffffffffff8060206117505f1986018c613b5f565b510151168160206117618689613b5f565b5101511601166040519161177483613548565b825260208201526117858289613b5f565b526117908188613b5f565b500161164e565b6020906040516117a681613548565b5f81525f83820152828289010152016115e4565b60206040916117c9368561388d565b8152019101906115ae565b346105bb5760203660031901126105bb5760043560606101606040516117f981613564565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161183f81613581565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611aff576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b038516875261193c600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139ce565b6101208b0190815261194d89613c5a565b600581101561121957600214611af7575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119cc8c613564565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a209061395a565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b87916134cf565b5f875261195e565b634e487b7160e01b5f52604160045260245ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb57611b4490369060040161349e565b90611b4d613e28565b5f915b808310611b5957005b611b6483828461390a565b3592611b6e613e28565b835f52600a60205260ff600160405f20015460a81c1615611eb857835f52600a60205260ff600160405f20015460a01c165f14611bb85783634a5541ef60e01b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611ea657611bed815f52600a6020526001600160a01b0360405f205416331490565b15611e9057611bfb81613b73565b90805f52600a602052611c13600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081611c67948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e45575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d796001600160a01b03600160405f2001541694611d51888588614804565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dca575b50505050506001019190611b50565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e27575b5016036104975780808080611dbb565b611e3f915060203d81116104d1576104c3818361359d565b87611e17565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb1565b506339c6dc7360e21b5f5260045260245ffd5b506322cad1af60e11b5f5260045260245ffd5b63216caf0d60e01b5f526004523360245260445ffd5b63fe19f19f60e01b5f5260045260245ffd5b8362b8e7e760e51b5f5260045260245ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600b602052610b87611f0f60405f2061395a565b6040519182916020835260208301906134cf565b346105bb5760203660031901126105bb57600435611f3f613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57611f6381613c5a565b60058110156112195760048103611f875750634a5541ef60e01b5f5260045260245ffd5b60038103611fa2575063fe19f19f60e01b5f5260045260245ffd5b60021461205e57611fc7815f52600a6020526001600160a01b0360405f205416331490565b15611e9057805f52600a60205260ff60405f205460f01c161561204c576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b6339c6dc7360e21b5f5260045260245ffd5b6322cad1af60e11b5f5260045260245ffd5b346105bb5760203660031901126105bb576004356001600160a01b0381168091036105bb576001600160a01b035f541633810361214b575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116121375760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5761217a613424565b5f546001600160a01b03811633810361214b57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bb5760203660031901126105bb576001600160a01b036121f0613424565b16801561220d575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bb5760203660031901126105bb576020612257600435613b31565b6001600160a01b0360405191168152f35b346105bb5760203660031901126105bb57600435612284613942565b50805f52600a60205260ff600160405f20015460a81c161561062e575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122ce83613548565b825260208201526122f48251809264ffffffffff60208092828151168552015116910152565bf35b346105bb5760403660031901126105bb5760043567ffffffffffffffff81116105bb5761232790369060040161349e565b9060243567ffffffffffffffff81116105bb5761234890369060040161349e565b919092612353613e28565b82810361266c575f5b81811061236557005b61237081838561390a565b3561237c82848661390a565b355f5260036020526001600160a01b0360405f205416906123a66123a184888a61390a565b61392e565b916123af613e28565b815f52600a60205260ff600160405f20015460a81c161561101057815f52600a60205260ff600160405f20015460a01c16612659578015610998576001600160801b03831690811561098557825f5260036020526001600160a01b0360405f205416938482141580612649575b61262e576001600160801b0361243185614680565b16808411612614575061245690845f52600a602052600260405f20015460801c6146a6565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612490906139ce565b6001600160801b036124b48160208401511692826040818351169201511690613611565b1611156125e2575b825f52600a6020526001600160a01b03600160405f200154166124e0838383614804565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125cc575b612551575b5050505060010161235c565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125ae575b50160361049757808080612545565b6125c6915060203d81116104d1576104c3818361359d565b8961259f565b50835f52600960205260ff60405f205416612540565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124bc565b838563287ecaef60e21b5f5260045260245260445260645ffd5b508263b34359d360e01b5f526004523360245260445260645ffd5b506126538461455b565b1561241c565b50634a5541ef60e01b5f5260045260245ffd5b90507faec93440000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e57610a506020916145cd565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f61270f82613c5a565b60058110156112195760020361272d575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612720565b346105bb575f3660031901126105bb5760206001600160a01b0360085416604051908152f35b346105bb5760203660031901126105bb57600435612789613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c1615612906576127c88161455b565b15611e9057805f5260036020526001600160a01b0360405f2054161515806128ff575b806128e2575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612899575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288757005b637e27328960e01b5f5260045260245ffd5b6128b8835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f19815401905561283f565b630da9b01360e01b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f1565b505f6127eb565b7f817cd639000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bb5761117c61294236613464565b906040519261295260208561359d565b5f8452613a21565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bb5760203660031901126105bb576004356129c6613e28565b805f52600a60205260ff600160405f20015460a81c161561062e57805f52600a60205260ff600160405f20015460a01c165f14612a0f57634a5541ef60e01b5f5260045260245ffd5b805f52600a60205260405f205460f81c611ea657612a41815f52600a6020526001600160a01b0360405f205416331490565b15611e9057612a4f81613b73565b90805f52600a602052612a67600260405f20016139ce565b916001600160801b038351166001600160801b0382161015611e7d57815f52600a60205260ff60405f205460f01c1615611e6a57806001600160801b03602081612abb948188511603169501511690613611565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c5c575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612ba56001600160a01b03600160405f2001541694611d51888588614804565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612be857005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c3d5750160361049757005b612c56915060203d6020116104d1576104c3818361359d565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b05565b346105bb5760203660031901126105bb57612c9a613424565b6001600160a01b035f541690338203612dd957806001600160a01b03913b15612dad57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d7e575b5015612d5357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f7fb843ea000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da0915060203d602011612da6575b612d98818361359d565b8101906138f2565b82612d08565b503d612d8e565b7f5a2b2d83000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bb5760203660031901126105bb5760043567ffffffffffffffff81116105bb5761014060031982360301126105bb57612e2a613e28565b604051612e368161352b565b612e4282600401613450565b8152612e5060248301613450565b6020820152612e61604483016135db565b604082015260648201356001600160a01b03811681036105bb576060820152612e8c6084830161351e565b6080820152612e9d60a4830161351e565b60a0820152612eae60c48301613863565b60c082015260e482013567ffffffffffffffff81116105bb57820191366023840112156105bb57600483013592612ee484613875565b90612ef2604051928361359d565b848252602060048184019660061b83010101903682116105bb57602401945b818610612f3357602061171a8661170f878760e08401526101043691016138c3565b6020604091612f42368961388d565b815201950194612f11565b346105bb5760203660031901126105bb576001600160a01b03612f6e613424565b165f526009602052602060ff60405f2054166040519015158152f35b346105bb575f3660031901126105bb5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bb5761117c612fd536613464565b91613631565b346105bb575f3660031901126105bb576020600754604051908152f35b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e5761303090613c5a565b6005811015611219578060209115908115613051575b506040519015158152f35b600191501482613046565b346105bb5760203660031901126105bb57600435805f52600a60205260ff600160405f20015460a81c161561062e576020905f90805f52600a835260ff60405f205460f01c16806130f1575b6130bf575b506001600160801b0360405191168152f35b6130eb9150805f52600a83526130e56001600160801b03600260405f2001541691613b73565b90613611565b826130ad565b50805f52600a835260ff600160405f20015460a01c16156130a8565b346105bb5760403660031901126105bb57613126613424565b60243561313281613b31565b331515806131ff575b806131cc575b6131a05781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613141565b50336001600160a01b038216141561313b565b346105bb5760203660031901126105bb5760206122576004356135ef565b346105bb575f3660031901126105bb576040515f6001548060011c906001811680156132e1575b60208310811461141c578285529081156113f8575060011461328357610b87836113868185038261359d565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132c757509091508101602001611386611376565b9192600181602092548385880101520191019092916132af565b91607f1691613257565b346105bb575f3660031901126105bb57602060405167016345785d8a00008152f35b346105bb5760203660031901126105bb57600435906001600160e01b031982168092036105bb57817f490649060000000000000000000000000000000000000000000000000000000060209314908115613369575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b4575b81156133a3575b5083613362565b6301ffc9a760e01b9150148361339c565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613395565b5f5b8381106133ef5750505f910152565b81810151838201526020016133e0565b90602091613418815180928185528580860191016133de565b601f01601f1916010190565b600435906001600160a01b03821682036105bb57565b602435906001600160a01b03821682036105bb57565b35906001600160a01b03821682036105bb57565b60609060031901126105bb576004356001600160a01b03811681036105bb57906024356001600160a01b03811681036105bb579060443590565b9181601f840112156105bb5782359167ffffffffffffffff83116105bb576020808501948460051b0101116105bb57565b90602080835192838152019201905f5b8181106134ec5750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134df565b359081151582036105bb57565b610120810190811067ffffffffffffffff821117611aff57604052565b6040810190811067ffffffffffffffff821117611aff57604052565b610180810190811067ffffffffffffffff821117611aff57604052565b6060810190811067ffffffffffffffff821117611aff57604052565b90601f8019910116810190811067ffffffffffffffff821117611aff57604052565b67ffffffffffffffff8111611aff57601f01601f191660200190565b35906001600160801b03821682036105bb57565b6135f881613b31565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213757565b91906001600160a01b03168015610cef57815f5260036020526001600160a01b0360405f20541615158061385b575b8061383e575b61382b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613776575b6001600160a01b0393508561373f575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61375e825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136c6565b91929050806137d4575b1561378d578282916136b6565b82846137a557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613802575b806137805750825f526005602052336001600160a01b0360405f20541614613780565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137df565b50630da9b01360e01b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613666565b506001613660565b359064ffffffffff821682036105bb57565b67ffffffffffffffff8111611aff5760051b60200190565b91908260409103126105bb576040516138a581613548565b60206138be8183956138b6816135db565b855201613863565b910152565b91908260409103126105bb576040516138db81613548565b60208082946138e981613450565b84520135910152565b908160209103126105bb575180151581036105bb5790565b919081101561391a5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bb5790565b6040519061394f82613548565b5f6020838281520152565b90815461396681613875565b92613974604051948561359d565b81845260208401905f5260205f205f915b8383106139925750505050565b6001602081926040516139a481613548565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190613985565b906040516139db81613581565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bb5790565b3580151581036105bb5790565b90613a2d838284613631565b803b613a3a575b50505050565b602091613a806001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906133ff565b03815f865af15f9181613af0575b50613abc5750613a9c614651565b80519081613ab75782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ade57505f808080613a34565b633250574960e11b5f5260045260245ffd5b613b0a91925060203d6020116104d1576104c3818361359d565b905f613a8e565b908160209103126105bb57516001600160e01b0319811681036105bb5790565b805f5260036020526001600160a01b0360405f205416908115612887575090565b80511561391a5760200190565b805182101561391a5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9160405f2061395a565b908364ffffffffff6020613ba485613b52565b5101511611613c5357805f52600a6020528364ffffffffff60405f205460c81c161115613c3457506001600160801b03613bdd82613b52565b515116916001925b8251841015613c2d578464ffffffffff6020613c018787613b5f565b5101511611613c2d576001600160801b0360019181613c208787613b5f565b5151160116930192613be5565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c7c5750600490565b805f52600a60205260405f205460f81c613ce857805f52600a60205264ffffffffff60405f205460a01c164210613ce357613cb681613b73565b905f52600a6020526001600160801b0380600260405f200154169116105f14613cde57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e16575b80613df9575b6128d0577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc2575b1680613daa575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d66565b613de1835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d5f565b50805f52600a60205260ff600160405f20015460b01c1615613d13565b506001600160a01b0382161515613d0d565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5a57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea46001600160801b0360408401511660206101008501510151906146c6565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453357801561450b57815180156144e3577f000000000000000000000000000000000000000000000000000000000000000081116144b8575064ffffffffff6020613f1284613b52565b5101511681101561447457505f905f905f81515f905b8082106143ec575050505064ffffffffff804216911690818110156143be5750506001600160801b03169081810361439057505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f48751975f19890190613b5f565b51015160c81b169360a01b169116171785555f5b8181106142de575050600187016007556001600160a01b036020830151168015610cef5761413e886001600160a01b0392613cee565b166142b257868261418c6001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a3565b6001600160801b0360208401511680614282575b506001600160a01b03815116946142776142596001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996141fe8b613548565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134cf565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142ac906001600160a01b036060840151166001600160a01b0361010085015151169033906147a3565b5f6141a0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142f98160e0870151613b5f565b5182549268010000000000000000841015611aff576001840180825584101561391a576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b16911617905501614108565b7f6375ff13000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f210aec0e000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614410906001600160801b036144078588613b5f565b515116906146a6565b9364ffffffffff8060206144248685613b5f565b5101511694168085111561444057506001849301909291613f28565b8490847fd97494c6000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448584613b52565b51015116907ff1fb2cc5000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f73627f74000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f7ea4ccdf000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fd572dbcb000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f6095d3bc000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a1575b508115614588575090565b90506001600160a01b0361459c33926135ef565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f61457d565b805f52600a6020526145e4600260405f20016139ce565b90805f52600a60205260ff600160405f20015460a01c165f146146125750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614634575061463190613b73565b90565b61463191506001600160801b036040818351169201511690613611565b3d1561467b573d90614662826135bf565b91614670604051938461359d565b82523d5f602084013e565b606090565b6146319061468d816145cd565b905f52600a602052600260405f20015460801c90613611565b906001600160801b03809116911601906001600160801b03821161213757565b9190916040516146d581613548565b5f81525f6020820152926001600160801b0382169081156147865767016345785d8a0000811161474f576147116001600160801b0391836148d9565b166020850191818352111561473b576001600160801b03918261473692511690613611565b168252565b634e487b7160e01b5f52600160045260245ffd5b7f4fea5c1a000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479781613548565b5f81525f602082015290565b9091926001600160a01b036148029481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526147fd60848361359d565b614854565b565b614802926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526147fd60648361359d565b5f806001600160a01b0361487d93169360208151910182865af1614876614651565b9083614987565b80519081151591826148be575b50506148935750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d192506020809183010191016138f2565b155f8061488a565b9091905f198382098382029182808310920391808303921461497657670de0b6b3a7640000821015614946577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c4575080511561499c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0a575b6149d5575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149cd56fea164736f6c634300081a000a"; + hex"60c0604052346103e157614e306060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a25908161040b823960805181613e37015260a051818181612fa60152613ee00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fb57806357404b121461226d5780636352211e1461223e5780636d0cee751461223e57806370a08231146121d457806375829def146121665780637cad6cd1146120755780637de6b1db14611f285780637f5799f914611ecf5780638659c27014611b17578063894e9a0d146117d8578063897f362b1461150d5780638f69b9931461148d5780639067b6771461143e57806395d89b4114611336578063a22cb46514611282578063a80fc07114611231578063ad35efd4146111d2578063b256456914611182578063b88d4fde146110f8578063b8a3be66146110c3578063b971302a14611075578063bc2be1be14611026578063c156a11d14610c0a578063c87b56dd14610aff578063d4dbd20b14610aae578063d511609f14610a63578063d975dfed14610a18578063e985e9c5146109bf578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614685565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146ab565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061056a85614560565b15610316565b8363b2ae763360e01b5f5260045260245ffd5b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b6106b782614685565b916106c0613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ad576001600160a01b038216801561099a576001600160801b03841692831561098757825f5260036020526001600160a01b0360405f205416948583141580610977575b61095c576001600160801b0361074c85614685565b16808611610942575061077190845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ab906139d3565b6001600160801b036107cf8160208401511692826040818351169201511690613616565b161115610910575b825f52600a6020526107fb846001600160a01b03600160405f200154169283614809565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fa575b61086b575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108db575b5016036108c8578180610860565b50636ade251160e01b5f5260045260245ffd5b6108f4915060203d6020116104d1576104c381836135a2565b856108ba565b50835f52600960205260ff60405f20541661085b565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d7565b858563066920d760e01b5f5260045260245260445260645ffd5b828463350b320360e11b5f526004523360245260445260645ffd5b5061098184614560565b15610737565b8263b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d8613429565b6001600160a01b036109e861343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a52602091614685565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1c81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8d575b610b8990604051918291602083526020830190613404565b0390f35b503d805f833e610b9d81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd5836135c4565b91610be360405193846135a2565b838352602084830101116105bc57610b8992610c0591602080850191016133e3565b610b71565b346105bc5760403660031901126105bc57600435610c2661343f565b610c2e613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f5260036020526001600160a01b0360405f20541690813303610ffc57610c7083614685565b906001600160801b0382169182158015610d04575b50506001600160a01b03811615610cf157610ca8846001600160a01b0392613cf3565b169182610cc25783637e27328960e01b5f5260045260245ffd5b8084918403610cd657602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0c613e2d565b855f52600a60205260ff600160405f20015460a81c1615610fe957855f52600a60205260ff600160405f20015460a01c16610fd6578415610fc357610fb057845f5260036020526001600160a01b0360405f205416908185141580610fa0575b610f85576001600160801b03610d8187614685565b16808511610f6b5750610da690865f52600a602052600260405f20015460801c6146ab565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de0906139d3565b6001600160801b03610e048160208401511692826040818351169201511690613616565b161115610f39575b845f52600a6020526001600160a01b03600160405f20015416610e30848683614809565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f23575b610e9b575b80610c85565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f04575b501614610e9557636ade251160e01b5f5260045260245ffd5b610f1d915060203d6020116104d1576104c381836135a2565b88610eeb565b50805f52600960205260ff60405f205416610e90565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0c565b848763066920d760e01b5f5260045260245260445260645ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610faa86614560565b15610d6c565b8463b2ae763360e01b5f5260045260245ffd5b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611111613429565b61111961343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611146836135c4565b9261115460405194856135a2565b80845236602482870101116105bc576020815f9260246111809801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120a90613c5f565b604051600582101561121d576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129b613429565b602435908115158092036105bc576001600160a01b031690811561130a57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611434575b602083108114611420578285529081156113fc575060011461139e575b610b898361138a818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e25750909150810160200161138a61137a565b9192600181602092548385880101520191019092916113ca565b60ff191660208086019190915291151560051b8401909101915061138a905061137a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135d565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c590613c5f565b60058110158061121d5760028214908115611501575b81156114ef575b6020826040519015158152f35b905061121d57600460209114826114e2565b5050600381145f6114db565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc57611548613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115918761387a565b9661159f60405198896135a2565b875282870193010101913683116105bc57905b8282106117be575050508151916115c88361387a565b926115d660405194856135a2565b808452601f196115e58261387a565b015f5b81811061179b57505064ffffffffff4216916001600160801b0361160b82613b57565b51511664ffffffffff80602061162085613b57565b51015116850116604051916116348361354d565b8252602082015261164486613b57565b5261164e85613b57565b5060015b8281106117265750505061166882600401613a05565b9261167560248401613a05565b9261168260448201613933565b916064820135936001600160a01b0385168095036105bc5760209661171e966116de966001600160801b03611713976001600160a01b036116c560848a01613a19565b94816116d360a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173b60019385613b64565b51511664ffffffffff8060206117545f1986018c613b64565b510151168160206117658689613b64565b510151160116604051916117788361354d565b825260208201526117898289613b64565b526117948188613b64565b5001611652565b6020906040516117aa8161354d565b5f81525f83820152828289010152016115e8565b60206040916117cd3685613892565b8152019101906115b2565b346105bc5760203660031901126105bc5760043560606101606040516117fd81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184381613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b03576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611940600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195189613c5f565b600581101561121d57600214611afb575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d08c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a249061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b89916134d4565b5f8752611962565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b489036906004016134a3565b90611b51613e2d565b5f915b808310611b5d57005b611b6883828461390f565b3592611b72613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebc57835f52600a60205260ff600160405f20015460a01c165f14611bbc57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eaa57611bf1815f52600a6020526001600160a01b0360405f205416331490565b15611e9457611bff81613b78565b90805f52600a602052611c17600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081611c6b948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e49575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7d6001600160a01b03600160405f2001541694611d55888588614809565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dce575b50505050506001019190611b54565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2b575b5016036104975780808080611dbf565b611e43915060203d81116104d1576104c381836135a2565b87611e1b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb5565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b89611f1460405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f44613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6881613c5f565b600581101561121d5760048103611f8c57506315efa0f360e11b5f5260045260245ffd5b60038103611fa7575063d0a172b360e01b5f5260045260245ffd5b60021461206357611fcc815f52600a6020526001600160a01b0360405f205416331490565b15611e9457805f52600a60205260ff60405f205460f01c1615612051576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612150575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5761217f613429565b5f546001600160a01b03811633810361215057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f5613429565b168015612212575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225c600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc57600435612289613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d38361354d565b825260208201526122f98251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232c9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234d9036906004016134a3565b919092612358613e2d565b828103612671575f5b81811061236a57005b61237581838561390f565b3561238182848661390f565b355f5260036020526001600160a01b0360405f205416906123ab6123a684888a61390f565b613933565b916123b4613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f52600a60205260ff600160405f20015460a01c1661265e57801561099a576001600160801b03831690811561098757825f5260036020526001600160a01b0360405f20541693848214158061264e575b612633576001600160801b0361243685614685565b16808411612619575061245b90845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612495906139d3565b6001600160801b036124b98160208401511692826040818351169201511690613616565b1611156125e7575b825f52600a6020526001600160a01b03600160405f200154166124e5838383614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d1575b612556575b50505050600101612361565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b3575b5016036104975780808061254a565b6125cb915060203d81116104d1576104c381836135a2565b896125a4565b50835f52600960205260ff60405f205416612545565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c1565b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061265884614560565b15612421565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a526020916145d2565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121d57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd81614560565b15611e9457805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118061294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eaa57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9457612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d55888588614809565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061171e86611713878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611180612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121d578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225c6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611420578285529081156113fc575060011461328857610b898361138a818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138a61137a565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0357604052565b6040810190811067ffffffffffffffff821117611b0357604052565b610180810190811067ffffffffffffffff821117611b0357604052565b6060810190811067ffffffffffffffff821117611b0357604052565b90601f8019910116810190811067ffffffffffffffff821117611b0357604052565b67ffffffffffffffff8111611b0357601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213c57565b91906001600160a01b03168015610cf157815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b035760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614656565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146cb565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453857801561451057815180156144e8577f000000000000000000000000000000000000000000000000000000000000000081116144bd575064ffffffffff6020613f1784613b57565b5101511681101561447957505f905f905f81515f905b8082106143f1575050505064ffffffffff804216911690818110156143c35750506001600160801b03169081810361439557505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f98751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142e3575050600187016007556001600160a01b036020830151168015610cf157614143886001600160a01b0392613cf3565b166142b75786826141916001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a8565b6001600160801b0360208401511680614287575b506001600160a01b038151169461427c61425e6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142038b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142b1906001600160a01b036060840151166001600160a01b0361010085015151169033906147a8565b5f6141a5565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142fe8160e0870151613b64565b5182549268010000000000000000841015611b03576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161410d565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614415906001600160801b0361440c8588613b64565b515116906146ab565b9364ffffffffff8060206144298685613b64565b5101511694168085111561444557506001849301909291613f2d565b8490847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448a84613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a6575b50811561458d575090565b90506001600160a01b036145a133926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614582565b805f52600a6020526145e9600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146175750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614639575061463690613b78565b90565b61463691506001600160801b036040818351169201511690613616565b3d15614680573d90614667826135c4565b9161467560405193846135a2565b82523d5f602084013e565b606090565b61463690614692816145d2565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213c57565b9190916040516146da8161354d565b5f81525f6020820152926001600160801b03821690811561478b5767016345785d8a00008111614754576147166001600160801b0391836148de565b1660208501918183521115614740576001600160801b03918261473b92511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479c8161354d565b5f81525f602082015290565b9091926001600160a01b036148079481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148026084836135a2565b614859565b565b614807926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148026064836135a2565b5f806001600160a01b0361488293169360208151910182865af161487b614656565b908361498c565b80519081151591826148c3575b50506148985750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d692506020809183010191016138f7565b155f8061488f565b9091905f198382098382029182808310920391808303921461497b57670de0b6b3a764000082101561494b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c957508051156149a157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0f575b6149da575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149d256fea164736f6c634300081a000a"; bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = - hex"608080604052346015576141d4908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e323876146105285780634d7c0f111461041e5763769bed201461003a575f80fd5b3461041a5760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610089903690600401610a26565b6024359073ffffffffffffffffffffffffffffffffffffffff82169182810361041a5760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc36011261041a57604051906100e382610972565b60443564ffffffffff8116810361041a57825260643564ffffffffff8116810361041a57602083015282519060208401511515836040860151926060870151608088015191604051806020810194602086526040820161014291610b48565b03601f1981018252610154908261098e565b60a08a01519360c08b015160405181819251908160208401916020019161017a92610b27565b81010380825261018d906020018261098e565b61019690610b6d565b9060e08c0151151592604051956020870198896101c59164ffffffffff60208092828151168552015116910152565b604087526101d460608861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161027c92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016102cb92610b27565b0160620103605501601f19810182526102e4908261098e565b51902060405161174880820182811067ffffffffffffffff8211176103ed578291610c9f83396080815261034160406103206080840189610bfe565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103e2576103a56103c7937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb89273ffffffffffffffffffffffffffffffffffffffff6020971695869560405194859460c0865260c0860190610bfe565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80fd5b3461041a5760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a573660238201121561041a5780600401359067ffffffffffffffff821161041a573660248360061b8301011161041a575f90815b838310156105095760248360061b830101359067ffffffffffffffff821680920361041a5767ffffffffffffffff160167ffffffffffffffff81116104dc57600190920191610492565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461041a5760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261041a5760043567ffffffffffffffff811161041a57610577903690600401610a26565b60243573ffffffffffffffffffffffffffffffffffffffff81169081810361041a576044359067ffffffffffffffff821161041a573660238301121561041a57816004013567ffffffffffffffff81116103ed57604051926105df60208360051b018561098e565b8184526024602085019260061b8201019036821161041a57602401915b818310610925575050505f9082515f905b8082106108cd5750508451906020860151151584604088015192606089015160808a015191604051806020810194602086526040820161064c91610b48565b03601f198101825261065e908261098e565b8b60a08101519460c082015160405181819251908160208401916020019161068592610b27565b810103808252610698906020018261098e565b6106a190610b6d565b9160e001511515926040519586602081019960208b52604082016106c491610bae565b03601f19810188526106d6908861098e565b6040519a8b9a60208c019d8e3360601b905260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b015260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016604e8a015251908160628a0161077e92610b27565b8701946062860152608285015260f81b60a284015260601b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a383015251918260b783016107cd92610b27565b0160620103605501601f19810182526107e6908261098e565b519020604051611de18082019082821067ffffffffffffffff8311176103ed578291610837916123e7843960608152610822606082018a610bfe565b90886020820152604081830391015286610bae565b03905ff580156103e2576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926108ac73ffffffffffffffffffffffffffffffffffffffff61089a941696879660405195869560c0875260c0870190610bfe565b918a8601528482036040860152610bae565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156108f85760019064ffffffffff6020808760051b890101510151160193019061060d565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b60408336031261041a576040519061093c82610972565b83359067ffffffffffffffff8216820361041a5782602092604094526109638387016109be565b838201528152019201916105fc565b6040810190811067ffffffffffffffff8211176103ed57604052565b90601f601f19910116810190811067ffffffffffffffff8211176103ed57604052565b3590811515820361041a57565b359064ffffffffff8216820361041a57565b81601f8201121561041a5780359067ffffffffffffffff82116103ed5760405192610a056020601f19601f860116018561098e565b8284526020838301011161041a57815f926020809301838601378301015290565b9190916101008184031261041a5760405190610100820182811067ffffffffffffffff8211176103ed576040528193813573ffffffffffffffffffffffffffffffffffffffff8116810361041a578352610a82602083016109b1565b6020840152610a93604083016109be565b6040840152606082013573ffffffffffffffffffffffffffffffffffffffff8116810361041a576060840152608082013567ffffffffffffffff811161041a5781610adf9184016109d0565b608084015260a082013560a084015260c08201359067ffffffffffffffff821161041a5782610b1760e09492610b22948694016109d0565b60c0860152016109b1565b910152565b5f5b838110610b385750505f910152565b8181015183820152602001610b29565b90601f19601f602093610b6681518092818752878088019101610b27565b0116010190565b602081519101519060208110610b81575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90602080835192838152019201905f5b818110610bcb5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610bbe565b9073ffffffffffffffffffffffffffffffffffffffff825116815260208201511515602082015264ffffffffff604083015116604082015273ffffffffffffffffffffffffffffffffffffffff606083015116606082015260e080610c93610c7760808601516101006080870152610100860190610b48565b60a086015160a086015260c086015185820360c0870152610b48565b93015115159101529056fe610160806040523461042857611748803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b60405161102490816107248239608051818181610481015281816106d60152610c20015260a0518181816107140152610b11015260c05181818161015f01528181610a6801528181610d8a0152610f49015260e0518181816102d3015261062201526101005181610e2801526101205181818161073e0152610ad50152610140518181816101af01526108870152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b63a52d539b60e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e12575080631686c90914610b3657806316c3549d14610afa5780631bfd681414610abe5780633bfe03a814610a905780633f31ae3f146104a55780634800d97f1461045557806349fc73dd1461031a5780634e390d3e146102f657806351e75e8b146102bc57806375829def146101ed57806390e64d13146101d35780639e93e57714610183578063bb4b573414610142578063ce516507146101025763f851a440146100cc575f80fd5b346100fe575f6003193601126100fe57602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b346100fe5760206003193601126100fe57602061013860043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fe575f6003193601126100fe57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe575f6003193601126100fe576020610138610f41565b346100fe5760206003193601126100fe57610206610ec1565b5f5473ffffffffffffffffffffffffffffffffffffffff811633810361028d575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fe575f6003193601126100fe5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fe575f6003193601126100fe57602064ffffffffff60035416604051908152f35b346100fe575f6003193601126100fe576040515f6001548060011c9060018116801561044b575b60208310811461041e578285529081156103dc575060011461037e575b61037a8361036e81850382610f00565b60405191829182610e5b565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106103c25750909150810160200161036e61035e565b9192600181602092548385880101520191019092916103aa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b8401909101915061036e905061035e565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610341565b346100fe575f6003193601126100fe57602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fe5760806003193601126100fe5760043560243573ffffffffffffffffffffffffffffffffffffffff81168091036100fe57604435916fffffffffffffffffffffffffffffffff83168093036100fe576064359067ffffffffffffffff82116100fe57366023830112156100fe57816004013567ffffffffffffffff81116100fe578060051b92602484820101903682116100fe57604051602081019085825287604082015288606082015260608152610563608082610f00565b519020604051602081019182526020815261057f604082610f00565b5190209261058b610f41565b610a39576105b08560ff6001918060081c5f526002602052161b60405f205416151590565b610a0d576105c46020604051970187610f00565b8552602401602085015b8282106109fd57505050935f945b835186101561061e5760208660051b85010151908181105f1461060d575f52602052600160405f205b9501946105dc565b905f52602052600160405f20610605565b84907f0000000000000000000000000000000000000000000000000000000000000000036109d55760035464ffffffffff8116156109a1575b508260081c5f52600260205260405f20600160ff85161b815417905573ffffffffffffffffffffffffffffffffffffffff5f54169160405161069881610ee4565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176109745760405284526020840183815260408501838152606086017f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f0000000000000000000000000000000000000000000000000000000000000000151584526040519461076e86610ee4565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b525173ffffffffffffffffffffffffffffffffffffffff1660048b01525173ffffffffffffffffffffffffffffffffffffffff1660248a0152516fffffffffffffffffffffffffffffffff1660448901525173ffffffffffffffffffffffffffffffffffffffff166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e485015251805173ffffffffffffffffffffffffffffffffffffffff166101048501526020015161012484015282807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff165a925f61014492602095f1928315610969575f93610911575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610961575b8161092e60209383610f00565b810103126100fe5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6108d5565b3d9150610921565b6040513d5f823e3d90fd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff161760035583610657565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016105ce565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100fe575f6003193601126100fe57604060045464ffffffffff825191818116835260281c166020820152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe575f6003193601126100fe5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fe5760406003193601126100fe57610b4f610ec1565b6024356fffffffffffffffffffffffffffffffff81168091036100fe5773ffffffffffffffffffffffffffffffffffffffff5f541633810361028d575064ffffffffff6003541680151580610dc4575b80610db5575b610d5b57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610c09606485610f00565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d4f573d67ffffffffffffffff811161097457610ca79160405191610c9760207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f00565b82523d5f602084013e5b83610f7e565b8051908115159182610d2b575b5050610d0057507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fe57602001518015908115036100fe578480610cb4565b610ca790606090610ca1565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610dbe610f41565b15610ba5565b5062093a80810164ffffffffff8111610de55764ffffffffff164211610b9f565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b346100fe575f6003193601126100fe5761037a907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036e604082610f00565b919091602081528251928360208301525f5b848110610eab5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201610e6d565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100fe57565b6040810190811067ffffffffffffffff82111761097457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761097457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f76575090565b905042101590565b90610fbb5750805115610f9357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061100e575b610fcc575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610fc456fea164736f6c634300081a000a610180806040523461044857611de1803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b60405161155e908161088382396080518181816105d10152818161095d0152611061015260a0518181816109870152610f52015260c0518181816102bb01528181610eac015281816111cb015261135d015260e05181818161042301526107b40152610100518161123c0152610120518181816109c20152610f160152610140518181816101390152610ac20152610160518181816102ff01526106980152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b63a52d539b60e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611226575080631686c90914610f7757806316c3549d14610f3b5780631bfd681414610eff5780633f31ae3f146105f55780634800d97f146105a557806349fc73dd1461046a5780634e390d3e1461044657806351e75e8b1461040c57806375829def1461033d57806390e64d1314610323578063936c63d9146102df578063bb4b57341461029e578063bf4ed03f1461019d578063ce5165071461015d578063da7924681461010d5763f851a440146100d7575f80fd5b34610109575f60031936011261010957602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b5f80fd5b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461010957602060031936011261010957602061019360043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610109575f600319360112610109576004546101b981611392565b906101c76040519283611314565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610261578486604051918291602083019060208452518091526040830191905f5b81811061022b575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff16818601528695506040909401939092019160010161021d565b600160208192604051610273816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101f9565b34610109575f60031936011261010957602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f60031936011261010957602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109575f600319360112610109576020610193611355565b34610109576020600319360112610109576103566112d5565b5f5473ffffffffffffffffffffffffffffffffffffffff81163381036103dd575073ffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610109575f6003193601126101095760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610109575f60031936011261010957602064ffffffffff60035416604051908152f35b34610109575f600319360112610109576040515f6001548060011c9060018116801561059b575b60208310811461056e5782855290811561052c57506001146104ce575b6104ca836104be81850382611314565b6040519182918261126f565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610512575090915081016020016104be6104ae565b9192600181602092548385880101520191019092916104fa565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660208086019190915291151560051b840190910191506104be90506104ae565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b91607f1691610491565b34610109575f60031936011261010957602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610109576080600319360112610109576004356024359073ffffffffffffffffffffffffffffffffffffffff821680920361010957604435916fffffffffffffffffffffffffffffffff831691828403610109576064359367ffffffffffffffff851161010957366023860112156101095784600401359467ffffffffffffffff86116101095760248660051b8201013681116101095767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ed457506040516020810190858252866040820152876060820152606081526106ee608082611314565b519020604051602081019182526020815261070a604082611314565b51902091610716611355565b610e7d5761073b8560ff6001918060081c5f526002602052161b60405f205416151590565b610e515761074888611392565b97610756604051998a611314565b8852602401602088015b828210610e4157505050925f935b86518510156107b05761078185886113aa565b51908181101561079f575f52602052600160405f205b94019361076e565b905f52602052600160405f20610797565b85907f000000000000000000000000000000000000000000000000000000000000000003610e195760035464ffffffffff811615610de5575b50600454926107f784611392565b936108056040519586611314565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610da857505050505f845161084b81611392565b956108596040519788611314565b8187527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061088683611392565b015f5b818110610d855750505f905b828210610c7c5750506fffffffffffffffffffffffffffffffff8216848111610c4f578411610bfc575b5050508360081c5f52600260205260405f20600160ff86161b815417905573ffffffffffffffffffffffffffffffffffffffff5f541692604051610902816112f8565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610bcf5773ffffffffffffffffffffffffffffffffffffffff9660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526fffffffffffffffffffffffffffffffff60a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610b91575050508190602080945173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015203815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610b86575f93610b2e575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610b7e575b81610b4b60209383611314565b810103126101095792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af2565b3d9150610b3e565b6040513d5f823e3d90fd5b825180516fffffffffffffffffffffffffffffffff16855260209081015164ffffffffff168186015289955060409094019390920191600101610a71565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6fffffffffffffffffffffffffffffffff91610c3b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff849301886113aa565b5193031681835116011690528480806108bf565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52600160045260245ffd5b9092610c9d67ffffffffffffffff610c9486856113aa565b515116876113eb565b6fffffffffffffffffffffffffffffffff8111610d5a576fffffffffffffffffffffffffffffffff8091169164ffffffffff6020610cdb88876113aa565b5101511660405190610cec826112f8565b8482526020820152610cfe878c6113aa565b52610d09868b6113aa565b5016016fffffffffffffffffffffffffffffffff8111610d2d579260010190610895565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610d94816112f8565b5f81525f8382015282828c01015201610889565b600160208192604051610dba816112f8565b64ffffffffff865467ffffffffffffffff8116835260401c1683820152815201920192019190610834565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000164264ffffffffff1617600355846107e9565b7f0fa7d73c000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610760565b847f712b37a3000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f442b1841000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f4557880f000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610109575f6003193601126101095760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461010957604060031936011261010957610f906112d5565b6024356fffffffffffffffffffffffffffffffff81168091036101095773ffffffffffffffffffffffffffffffffffffffff5f54163381036103dd575064ffffffffff6003541680151580611205575b806111f6575b61119c57506040515f8073ffffffffffffffffffffffffffffffffffffffff60208401957fa9059cbb00000000000000000000000000000000000000000000000000000000875216948560248501528460448501526044845261104a606485611314565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15611190573d67ffffffffffffffff8111610bcf576110e891604051916110d860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184611314565b82523d5f602084013e5b836114b8565b805190811515918261116c575b505061114157507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f602073ffffffffffffffffffffffffffffffffffffffff5f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b819250906020918101031261010957602001518015908115036101095784806110f5565b6110e8906060906110e2565b7f92b66697000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506111ff611355565b15610fe6565b5062093a80810164ffffffffff8111610d2d5764ffffffffff164211610fe0565b34610109575f600319360112610109576104ca907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104be604082611314565b919091602081528251928360208301525f5b8481106112bf5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f845f6040809697860101520116010190565b8060208092840101516040828601015201611281565b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361010957565b6040810190811067ffffffffffffffff821117610bcf57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bcf57604052565b64ffffffffff7f000000000000000000000000000000000000000000000000000000000000000016801515908161138a575090565b905042101590565b67ffffffffffffffff8111610bcf5760051b60200190565b80518210156113be5760209160051b010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146114a757670de0b6b3a7640000821015611477577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906114f557508051156114cd57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611548575b611506575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156114fe56fea164736f6c634300081a000aa164736f6c634300081a000a"; + hex"60808060405234601557613bb9908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e3238761461044c5780634d7c0f11146103795763769bed201461003a575f80fd5b346103755760c03660031901126103755760043567ffffffffffffffff81116103755761006b9036906004016108c2565b602435906001600160a01b03821691828103610375576040366043190112610375576040519061009a8261080f565b60443564ffffffffff8116810361037557825260643564ffffffffff811681036103755760208301528251906020840151151583604086015192606087015160808801519160405180602081019460208652604082016100f9916109ca565b03601f198101825261010b908261082b565b60a08a01519360c08b0151604051818192519081602084019160200191610131926109a9565b810103808252610144906020018261082b565b61014d906109ef565b9060e08c01511515926040519560208701988961017c9164ffffffffff60208092828151168552015116910152565b6040875261018b60608861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a0161020f926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b7830161024c926109a9565b0160620103605501601f1981018252610265908261082b565b51902060405161157280820182811067ffffffffffffffff821117610361578291610ae88339608081526102c260406102a16080840189610a61565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103565761031961033b937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb8926001600160a01b036020971695869560405194859460c0865260c0860190610a61565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b346103755760203660031901126103755760043567ffffffffffffffff811161037557366023820112156103755780600401359067ffffffffffffffff8211610375573660248360061b83010111610375575f90815b8383101561042d5760248360061b830101359067ffffffffffffffff82168092036103755767ffffffffffffffff160167ffffffffffffffff8111610419576001909201916103cf565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346103755760a03660031901126103755760043567ffffffffffffffff81116103755761047d9036906004016108c2565b6024356001600160a01b03811690818103610375576044359067ffffffffffffffff8211610375573660238301121561037557816004013567ffffffffffffffff811161036157604051926104d860208360051b018561082b565b8184526024602085019260061b8201019036821161037557602401915b8183106107c2575050505f9082515f905b8082106107835750508451906020860151151584604088015192606089015160808a0151916040518060208101946020865260408201610545916109ca565b03601f1981018252610557908261082b565b8b60a08101519460c082015160405181819251908160208401916020019161057e926109a9565b810103808252610591906020018261082b565b61059a906109ef565b9160e001511515926040519586602081019960208b52604082016105bd91610a11565b03601f19810188526105cf908861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a01610653926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b78301610690926109a9565b0160620103605501601f19810182526106a9908261082b565b519020604051611b538082019082821067ffffffffffffffff8311176103615782916106fa9161205a8439606081526106e5606082018a610a61565b90886020820152604081830391015286610a11565b03905ff58015610356576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926107626001600160a01b03610750941696879660405195869560c0875260c0870190610a61565b918a8601528482036040860152610a11565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156107ae5760019064ffffffffff6020808760051b8901015101511601930190610506565b634e487b7160e01b5f52603260045260245ffd5b60408336031261037557604051906107d98261080f565b83359067ffffffffffffffff8216820361037557826020926040945261080083870161085a565b838201528152019201916104f5565b6040810190811067ffffffffffffffff82111761036157604052565b90601f8019910116810190811067ffffffffffffffff82111761036157604052565b3590811515820361037557565b359064ffffffffff8216820361037557565b81601f820112156103755780359067ffffffffffffffff821161036157604051926108a1601f8401601f19166020018561082b565b8284526020838301011161037557815f926020809301838601378301015290565b919091610100818403126103755760405190610100820182811067ffffffffffffffff82111761036157604052819381356001600160a01b03811681036103755783526109116020830161084d565b60208401526109226040830161085a565b604084015260608201356001600160a01b0381168103610375576060840152608082013567ffffffffffffffff8111610375578161096191840161086c565b608084015260a082013560a084015260c08201359067ffffffffffffffff8211610375578261099960e094926109a49486940161086c565b60c08601520161084d565b910152565b5f5b8381106109ba5750505f910152565b81810151838201526020016109ab565b906020916109e3815180928185528580860191016109a9565b601f01601f1916010190565b602081519101519060208110610a03575090565b5f199060200360031b1b1690565b90602080835192838152019201905f5b818110610a2e5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610a21565b906001600160a01b03825116815260208201511515602082015264ffffffffff60408301511660408201526001600160a01b03606083015116606082015260e080610adc610ac0608086015161010060808701526101008601906109ca565b60a086015160a086015260c086015185820360c08701526109ca565b93015115159101529056fe610160806040523461042857611572803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b604051610e4e90816107248239608051818181610409015281816106440152610ae6015260a05181818161067501526109fe015260c0518181816101520152818161095501528181610c250152610d80015260e05181818161029f015261059d01526101005181610caa01526101205181818161069f01526109c201526101405181818161019501526107b40152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b630f39860960e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610c94575080631686c90914610a2357806316c3549d146109e75780631bfd6814146109ab5780633bfe03a81461097d5780633f31ae3f1461042d5780634800d97f146103ea57806349fc73dd146102e65780634e390d3e146102c257806351e75e8b1461028857806375829def146101d357806390e64d13146101b95780639e93e57714610176578063bb4b573414610135578063ce516507146100f55763f851a440146100cc575f80fd5b346100f1575f3660031901126100f15760206001600160a01b035f5416604051908152f35b5f80fd5b346100f15760203660031901126100f157602061012b60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100f1575f3660031901126100f157602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f157602061012b610d78565b346100f15760203660031901126100f1576101ec610d24565b5f546001600160a01b03811633810361025957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100f1575f3660031901126100f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f1575f3660031901126100f157602064ffffffffff60035416604051908152f35b346100f1575f3660031901126100f1576040515f6001548060011c906001811680156103e0575b6020831081146103cc578285529081156103a8575060011461034a575b6103468361033a81850382610d56565b60405191829182610cdd565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061038e5750909150810160200161033a61032a565b919260018160209254838588010152019101909291610376565b60ff191660208086019190915291151560051b8401909101915061033a905061032a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161030d565b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f15760803660031901126100f1576004356024356001600160a01b0381168091036100f157604435916fffffffffffffffffffffffffffffffff83168093036100f1576064359067ffffffffffffffff82116100f157366023830112156100f157816004013567ffffffffffffffff81116100f1578060051b92602484820101903682116100f1576040516020810190858252876040820152886060820152606081526104de608082610d56565b51902060405160208101918252602081526104fa604082610d56565b51902092610506610d78565b6109265761052b8560ff6001918060081c5f526002602052161b60405f205416151590565b6108fa5761053f6020604051970187610d56565b8552602401602085015b8282106108ea57505050935f945b83518610156105995760208660051b85010151908181105f14610588575f52602052600160405f205b950194610557565b905f52602052600160405f20610580565b84907f0000000000000000000000000000000000000000000000000000000000000000036108c25760035464ffffffffff8116156108a8575b508260081c5f52600260205260405f20600160ff85161b81541790556001600160a01b035f54169160405161060681610d3a565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176108945760405284526020840183815260408501838152606086017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f000000000000000000000000000000000000000000000000000000000000000015158452604051946106cf86610d3a565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b52516001600160a01b031660048b0152516001600160a01b031660248a0152516fffffffffffffffffffffffffffffffff166044890152516001600160a01b03166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e48501525180516001600160a01b03166101048501526020015161012484015282807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61014492602095f1928315610889575f93610831575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610881575b8161084e60209383610d56565b810103126100f15792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6107f5565b3d9150610841565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff19164264ffffffffff1617600355836105d2565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610549565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100f1575f3660031901126100f157604060045464ffffffffff825191818116835260281c166020820152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f15760403660031901126100f157610a3c610d24565b6024356fffffffffffffffffffffffffffffffff81168091036100f1576001600160a01b035f5416338103610259575064ffffffffff6003541680151580610c5f575b80610c50575b610bf657506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610adc606485610d56565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610bea573d67ffffffffffffffff811161089457610b4f9160405191610b3f6020601f19601f8401160184610d56565b82523d5f602084013e5b83610db5565b8051908115159182610bc6575b5050610b9b57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100f157602001518015908115036100f1578480610b5c565b610b4f90606090610b49565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610c59610d78565b15610a85565b5062093a80810164ffffffffff8111610c805764ffffffffff164211610a7f565b634e487b7160e01b5f52601160045260245ffd5b346100f1575f3660031901126100f157610346907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261033a604082610d56565b9190916020815282518060208301525f5b818110610d0e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610cee565b600435906001600160a01b03821682036100f157565b6040810190811067ffffffffffffffff82111761089457604052565b90601f8019910116810190811067ffffffffffffffff82111761089457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610dad575090565b905042101590565b90610df25750805115610dca57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610e38575b610e03575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610dfb56fea164736f6c634300081a000a610180806040523461044857611b53803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b6040516112d0908161088382396080518181816105590152818161088e0152610e8e015260a0518181816108b80152610daf015260c0518181816102a101528181610d0901528181610fcd0152611114015260e0518181816103ef01526107260152610100518161103e0152610120518181816108ea0152610d7301526101405181818161011f01526109d00152610160518181816102e5015261060a0152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b630f39860960e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611028575080631686c90914610dd457806316c3549d14610d985780631bfd681414610d5c5780633f31ae3f1461057d5780634800d97f1461053a57806349fc73dd146104365780634e390d3e1461041257806351e75e8b146103d857806375829def1461032357806390e64d1314610309578063936c63d9146102c5578063bb4b573414610284578063bf4ed03f14610183578063ce51650714610143578063da792468146101005763f851a440146100d7575f80fd5b346100fc575f3660031901126100fc5760206001600160a01b035f5416604051908152f35b5f80fd5b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760203660031901126100fc57602061017960043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fc575f3660031901126100fc5760045461019f81611149565b906101ad60405192836110ea565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610247578486604051918291602083019060208452518091526040830191905f5b818110610211575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610203565b600160208192604051610259816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101df565b346100fc575f3660031901126100fc57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602061017961110c565b346100fc5760203660031901126100fc5761033c6110b8565b5f546001600160a01b0381163381036103a957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fc575f3660031901126100fc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fc575f3660031901126100fc57602064ffffffffff60035416604051908152f35b346100fc575f3660031901126100fc576040515f6001548060011c90600181168015610530575b60208310811461051c578285529081156104f8575060011461049a575b6104968361048a818503826110ea565b60405191829182611071565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104de5750909150810160200161048a61047a565b9192600181602092548385880101520191019092916104c6565b60ff191660208086019190915291151560051b8401909101915061048a905061047a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161045d565b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760803660031901126100fc57600435602435906001600160a01b0382168092036100fc57604435916001600160801b038316918284036100fc576064359367ffffffffffffffff85116100fc57366023860112156100fc5784600401359467ffffffffffffffff86116100fc5760248660051b8201013681116100fc5767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610d3157506040516020810190858252866040820152876060820152606081526106606080826110ea565b519020604051602081019182526020815261067c6040826110ea565b5190209161068861110c565b610cda576106ad8560ff6001918060081c5f526002602052161b60405f205416151590565b610cae576106ba88611149565b976106c8604051998a6110ea565b8852602401602088015b828210610c9e57505050925f935b8651851015610722576106f38588611161565b519081811015610711575f52602052600160405f205b9401936106e0565b905f52602052600160405f20610709565b85907f000000000000000000000000000000000000000000000000000000000000000003610c765760035464ffffffffff811615610c5c575b506004549261076984611149565b9361077760405195866110ea565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610c1f57505050505f84516107bd81611149565b956107cb60405197886110ea565b818752601f196107da83611149565b015f5b818110610bfc5750505f905b828210610b275750506001600160801b038216848111610b13578411610ae8575b5050508360081c5f52600260205260405f20600160ff86161b81541790556001600160a01b035f541692604051610840816110ce565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610ad4576001600160a01b039660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526001600160801b0360a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610a9f57505050819060208094516001600160a01b03815116610104850152015161012483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1928315610a94575f93610a3c575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610a8c575b81610a59602093836110ea565b810103126100fc5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610a00565b3d9150610a4c565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610999565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610aff83925f190188611161565b51930316818351160116905284808061080a565b634e487b7160e01b5f52600160045260245ffd5b9092610b4867ffffffffffffffff610b3f8685611161565b51511687611189565b6001600160801b038111610bd1576001600160801b038091169164ffffffffff6020610b748887611161565b5101511660405190610b85826110ce565b8482526020820152610b97878c611161565b52610ba2868b611161565b5016016001600160801b038111610bbd5792600101906107e9565b634e487b7160e01b5f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610c0b816110ce565b5f81525f8382015282828c010152016107dd565b600160208192604051610c31816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906107a6565b64ffffffffff19164264ffffffffff16176003558461075b565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106d2565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc5760403660031901126100fc57610ded6110b8565b6024356001600160801b0381168091036100fc576001600160a01b035f54163381036103a9575064ffffffffff6003541680151580611007575b80610ff8575b610f9e57506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610e846064856110ea565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610f92573d67ffffffffffffffff8111610ad457610ef79160405191610ee76020601f19601f84011601846110ea565b82523d5f602084013e5b83611237565b8051908115159182610f6e575b5050610f4357507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fc57602001518015908115036100fc578480610f04565b610ef790606090610ef1565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b5061100161110c565b15610e2d565b5062093a80810164ffffffffff8111610bbd5764ffffffffff164211610e27565b346100fc575f3660031901126100fc57610496907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261048a6040826110ea565b9190916020815282518060208301525f5b8181106110a2575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611082565b600435906001600160a01b03821682036100fc57565b6040810190811067ffffffffffffffff821117610ad457604052565b90601f8019910116810190811067ffffffffffffffff821117610ad457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611141575090565b905042101590565b67ffffffffffffffff8111610ad45760051b60200190565b80518210156111755760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b9091905f198382098382029182808310920391808303921461122657670de0b6b3a76400008210156111f6577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90611274575080511561124c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806112ba575b611285575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561127d56fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615eaf908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bf5760403660031901126141bf576001600160a01b036004351680600435036141bf576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614827565b61032052614a3d565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f91614684575b506001600160a01b0361012791168061024052614b39565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb576fffffffffffffffffffffffffffffffff915f91614665575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145bb575f90614628575b6101f59150614cdb565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145bb575f916145f9575b50610280516fffffffffffffffffffffffffffffffff1680156145e5576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614713565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615408565b970116615408565b980116615408565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146cd565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146cd565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146cd565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ddb565b1690614f41565b9061045a6001600160a01b036102405116614a3d565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb576024915f916145c6575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145bb5764ffffffffff8091610521945f9161458c575b50169116615237565b610340516103a05190939091906105ac600161054a60646105438188066158b3565b9604615408565b6020604051968261056489945180928580880191016146cd565b8301610578825180938580850191016146cd565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614713565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614578576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457857604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c06101605101516101605151906159b4565b60b76106ed5f615ca7565b985f6102205260206102205261071560405161070c6102205182614713565b5f8152846156d2565b1561456e57601b60909a5b6107298c615408565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146cd565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146cd565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146cd565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146cd565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146cd565b0101631e17b39f60e11b838201520301601b19810184520182614713565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614713565b5f815260b7610a0c6001615ca7565b98601b6028610a1a8c615db2565b610a2384615e2a565b8082111561456757505b019a6107298c615408565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614713565b5f815260b7610a0c6002615ca7565b8252602082015260286080610160510151604051610a9a6102205182614713565b5f81526108eb610ae46004600760276058610ab56003615ca7565b9660b7610ac189615db2565b610aca8b615e2a565b8082111561455f5750995b601b8c8c019a6107298c615408565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614ed4565b60608201526101006101208190526040516101a0819052610b949190614713565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614713565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614713565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614713565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614713565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615979565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146cd565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146cd565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614713565b61165585602361154c615979565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614713565b6117df60726023611664615979565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146cd565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146cd565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614713565b6117e7615979565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146cd565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146cd565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614713565b614ed4565b60e05261195561194f614c65565b856156d2565b938415614544575b5060c061010081905260405191906119759083614713565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614713565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432f57604051611dcd6102205182614713565b5f8152955b156141dc57604051611de66101e082614713565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614713565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146cd565b840160c051519060328101826102205160c0510191612a0c926146cd565b016032018082518093610220510191612a24926146cd565b018082518093610220510191612a39926146cd565b018082518093610220510191612a4e926146cd565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614713565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146cd565b60805101815191826026830191610220510191612ada926146cd565b016026018082518093610220510191612af2926146cd565b0160a051519080826102205160a0510191612b0c926146cd565b0160e051519080826102205160e0510191612b26926146cd565b018082518093610220510191612b3b926146cd565b01610140515190808261022051610140510191612b57926146cd565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614713565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615bf8565b916040958651612bd78882614713565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614713565b612dc891615bf8565b928551612dd58782614713565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614713565b612fc08282615c62565b918651612fcd8882614713565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614713565b6131b791615c62565b9085516131c48782614713565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146cd565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146cd565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614713565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146cd565b840181519182604583019161022051019161342b926146cd565b016045018082518093610220510191613443926146cd565b018082518093610220510191613458926146cd565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614713565b610140820151916101a08101519060408101519060e001519361349d90615408565b916134a790615408565b906134b190615408565b936134bb90615408565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146cd565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146cd565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146cd565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146cd565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614713565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146cd565b84016080515190607b810182610220516080510191613855926146cd565b01607b01808251809361022051019161386d926146cd565b0191829151809361387d926146cd565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614713565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614713565b515a925f93928493fa61391c614796565b6102e0819052901580156103c0526141d45761022051818051810103126141bf5761022051015180151581036141bf575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141ca575f9161417e575b50600360236139be613ad693614a3d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146cd565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146cd565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146cd565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614713565b6103205161026051610340516102405191939291613afc906001600160a01b0316614a3d565b613b07602435615408565b6102a051909190156140f25761010051875190613b249082614713565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c6965722056322000000000000000000000009052805190610220518101918060558a0190613c5c91856146cd565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546055918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460758201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609582015284516102205186019691613cea8260b183018a6146cd565b01605501605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146cd565b01605c0190601282016302e3716960e51b905251918260168301613d50926146cd565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146cd565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146cd565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146cd565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146cd565b01600a0103600401601f1981018452613e2f9084614713565b61032051613e3e602435615408565b85518091610220518201936a029b0b13634b2b9102b19160ad1b855280519081602b850191610220510191613e72926146cd565b8201602b81017f2023000000000000000000000000000000000000000000000000000000000000905281519182602d830191610220510191613eb3926146cd565b01602b0103600201601f1981018252613ecc9082614713565b61038051613ed990615567565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f20926146cd565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f5a926146cd565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fbd926146cd565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614027926146cd565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d198101825260020161406a9082614713565b6102c081905261407990615567565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bf926146cd565b810103603d01601f19810183526140d69083614713565b5180916102205182526102205182016140ee916146ee565b0390f35b86516140ff608082614713565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c3575b6141998183614713565b816102205191810103126141bf57516001600160a01b03811681036141bf5760036139ad565b5f80fd5b503d61418f565b83513d5f823e3d90fd5b50600161394d565b6040516141eb61012082614713565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433e6101c082614713565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b614558919450614552614ca0565b906156d2565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ae915060203d6020116145b4575b6145a68183614713565b81019061475d565b5f610518565b503d61459c565b6040513d5f823e3d90fd5b6145df915060203d6020116145b4576145a68183614713565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b61461b915060203d602011614621575b6146138183614713565b810190614735565b5f61024e565b503d614609565b506020813d60201161465d575b8161464260209383614713565b810103126141bf575160058110156141bf576101f5906101eb565b3d9150614635565b61467e915060203d602011614621576146138183614713565b5f610191565b90506020813d6020116146c5575b8161469f60209383614713565b810103126141bf57516001600160a01b03811681036141bf576001600160a01b0361010f565b3d9150614692565b5f5b8381106146de5750505f910152565b81810151838201526020016146cf565b90602091614707815180928185528580860191016146cd565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457857604052565b908160209103126141bf57516fffffffffffffffffffffffffffffffff811681036141bf5790565b908160209103126141bf575164ffffffffff811681036141bf5790565b67ffffffffffffffff811161457857601f01601f191660200190565b3d156147c0573d906147a78261477a565b916147b56040519384614713565b82523d5f602084013e565b606090565b6020818303126141bf5780519067ffffffffffffffff82116141bf570181601f820112156141bf5780516147f88161477a565b926148066040519485614713565b818452602082840101116141bf5761482491602080850191016146cd565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145bb575f92614a19575b5060409161489783516148678582614713565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826156d2565b156148d75750506148aa81519182614713565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491683516148e68582614713565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826156d2565b1561495657505061492981519182614713565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b61499583516149658582614713565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826156d2565b156149d55750506149a881519182614713565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a159083519384937f814a8a2e0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146ee565b0390fd5b614a369192503d805f833e614a2e8183614713565b8101906147c5565b905f614854565b6001600160a01b03168060405191614a56606084614713565b602a8352602083016040368237835115614b255760309053825160011015614b25576078602184015360295b60018111614ac35750614a93575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614b25577f3031323334353637383961626364656600000000000000000000000000000000901a614afe83866156ff565b5360041c908015614b11575f1901614a82565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614b5d602482614713565b51915afa614b69614796565b90158015614c59575b614c1d5780602080614b89935183010191016147c5565b601e8151115f14614bd05750604051614ba3604082614713565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614bd981615710565b15614be15790565b50604051614bf0604082614713565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614c2c604082614713565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614b72565b60405190614c74604083614713565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614caf604083614713565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614dc75760048103614cf55750614824614ca0565b60038103614d395750604051614d0c604082614713565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614d7d5750604051614d50604082614713565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614d8c57614824614c65565b604051614d9a604082614713565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614e18602482614713565b51915afa614e24614796565b9080614e53575b15614e4e576020818051810103126141bf576020015160ff811681036141bf5790565b505f90565b506020815114614e2b565b60405190614e6d604083614713565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614ea8604083614713565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614eff9493614f306020614f3f95614f22828096816040519c8d8b83829d519485930191016146cd565b8901614f13825180938580850191016146cd565b010191828151948592016146cd565b0191828151948592016146cd565b0103601f198101845283614713565b565b908115615216578061520657505b806001811015614fb8575050614f63614e99565b6148246002602060405184614f8182965180928580860191016146cd565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614713565b66038d7ea4c6800011156151a8576040519060a0820182811067ffffffffffffffff82111761457857604052602091604051614ff48482614713565b5f8152815260409182516150088482614713565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516150418482614713565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161507a8482614713565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516150b48482614713565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561518e578451946150fe8187614713565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061517b575050600160fd1b602786015250600884526151629061515c90615157602887614713565b615408565b916158b3565b916005851015614b25576148249460051b015192614ed4565b818101830151878201840152820161512b565b9490915060016103e86064600a85040693049101946150e7565b506151b1614e5e565b61482460086020604051846151cf82965180928580860191016146cd565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614713565b600a0a9081156145e55704614f4f565b5050604051615226604082614713565b60018152600360fc1b602082015290565b62015180910304806152a1575061524c614e99565b614824600660206040518461526a82965180928580860191016146cd565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614713565b61270f81116153785760018103615334576148246152f66040516152c6604082614713565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615408565b6020604051938261531086945180928580880191016146cd565b8301615324825180938580850191016146cd565b010103601f198101835282614713565b6148246152f6604051615348604082614713565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615408565b50615381614e5e565b614824600a60206040518461539f82965180928580860191016146cd565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614713565b906153e08261477a565b6153ed6040519182614713565b82815280926153fe601f199161477a565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561553f575b806d04ee2d6d415b85acef8100000000600a921015615524575b662386f26fc10000811015615510575b6305f5e1008110156154ff575b6127108110156154f0575b60648110156154e2575b10156154d7575b600a6021615492600185016153d6565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156154d257600a9091615497565b505090565b600190910190615482565b60646002910493019261547b565b61271060049104930192615471565b6305f5e10060089104930192615466565b662386f26fc1000060109104930192615459565b6d04ee2d6d415b85acef810000000060209104930192615449565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461542f565b908151156156bc576040519161557e606084614713565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614b1157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614b11576156149060021b6153d6565b90602082019080815182019560208701908151925f83525b88811061566e575050600393949596505251068060011461565c57600214615652575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761562c565b90506040516156cc602082614713565b5f815290565b90815181519081811493846156e9575b5050505090565b602092939450820120920120145f8080806156e2565b908151811015614b25570160200190565b8051905f5b82811061572457505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061574f82846156ff565b5116600160fd1b811490600360fc1b81101580615889575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161585e575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615833575b8415615809575b508315615801575b5082156157f9575b5081156157f1575b50156157ea57600101615715565b5050505f90565b90505f6157dc565b91505f6157d4565b92505f6157cc565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6157c4565b7f7a0000000000000000000000000000000000000000000000000000000000000081111593506157bd565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615792565b507f3900000000000000000000000000000000000000000000000000000000000000811115615767565b806158c757506040516156cc602082614713565b600a81101561592d576158d990615408565b614824602260405180937f2e30000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b81010301601f198101835282614713565b61593690615408565b614824602160405180937f2e00000000000000000000000000000000000000000000000000000000000000602083015261591c81518092602086860191016146cd565b60405190615988604083614713565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615be8576159c2615979565b9061271003906127108211614b1157602e60619160506159e461482495615408565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615a71815180926020868a0191016146cd565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615af882518093602060a7850191016146cd565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615b59825180936020607e850191016146cd565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614713565b50506040516156cc602082614713565b6010614f3f9193929360206040519582615c1b88945180928580880191016146cd565b830164010714051160dd1b838201526a029b0b13634b2b9102b19160ad1b6025820152615c5182518093856030850191016146cd565b01010301601f198101845283614713565b6005614f3f9193929360206040519582615c8588945180928580880191016146cd565b830164010714051160dd1b83820152615c5182518093856025850191016146cd565b6004811015614dc75780615cf15750604051615cc4604082614713565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615d355750604051615d08604082614713565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615d7757604051615d4a604082614713565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615d85604082614713565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156157ea5790600d915f925f925b828410615dd85750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e0c88856156ff565b511614615e22575b820194600101929190615dc5565b859450615e14565b5f90805180156157ea57906010915f925f925b828410615e50575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615e8488856156ff565b511614615e9a575b820194600101929190615e3d565b859450615e8c56fea164736f6c634300081a000a"; + hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614824565b61032052614b1e565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610521945f91614589575b50169116615318565b610340516103a05190939091906105ac600161054a6064610543818806615994565b96046154e9565b6020604051968261056489945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614710565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615a95565b60b76106ed5f615d85565b985f6102205260206102205261071560405161070c6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b6107298c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614710565b5f815260b7610a0c6001615d85565b98601b6028610a1a8c615e90565b610a2384615f08565b8082111561456457505b019a6107298c6154e9565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614710565b5f815260b7610a0c6002615d85565b8252602082015260286080610160510151604051610a9a6102205182614710565b5f81526108eb610ae46004600760276058610ab56003615d85565b9660b7610ac189615e90565b610aca8b615f08565b8082111561455c5750995b601b8c8c019a6107298c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b949190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165585602361154c615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117df60726023611664615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e7615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e05261195561194f614d46565b856157b3565b938415614541575b5060c061010081905260405191906119759083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dcd6102205182614710565b5f8152955b156141d957604051611de66101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0c926146ca565b016032018082518093610220510191612a24926146ca565b018082518093610220510191612a39926146ca565b018082518093610220510191612a4e926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146ca565b60805101815191826026830191610220510191612ada926146ca565b016026018082518093610220510191612af2926146ca565b0160a051519080826102205160a0510191612b0c926146ca565b0160e051519080826102205160e0510191612b26926146ca565b018082518093610220510191612b3b926146ca565b01610140515190808261022051610140510191612b57926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614710565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b6102e0819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103205161026051610340516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61032051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b61455591945061454f614d81565b906157b3565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610518565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a279083519384937f7498e3a50000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; uint256 public constant MAX_SEGMENT_COUNT = 500; uint256 public constant MAX_TRANCHE_COUNT = 500; @@ -40,49 +40,49 @@ contract Precompiles { CORE //////////////////////////////////////////////////////////////////////////*/ - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode, passing a default value for the + /// @notice Deploys {SablierLockupDynamic} from precompiled bytecode, passing a default value for the /// `maxSegmentCount` parameter. /// @dev Notes: /// - A default value is passed for `maxSegmentCount`. - /// - A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupDynamic(address initialAdmin) public returns (ISablierV2LockupDynamic lockupDynamic) { + /// - A dummy {LockupNFTDescriptor} is deployed so that the user does not have to provide one. + function deployLockupDynamic(address initialAdmin) public returns (ISablierLockupDynamic lockupDynamic) { uint256 maxSegmentCount = MAX_SEGMENT_COUNT; lockupDynamic = deployLockupDynamic(initialAdmin, maxSegmentCount); } - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. - /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. + /// @notice Deploys {SablierLockupDynamic} from precompiled bytecode. + /// @dev A dummy {LockupNFTDescriptor} is deployed so that the user does not have to provide one. function deployLockupDynamic( address initialAdmin, uint256 maxSegmentCount ) public - returns (ISablierV2LockupDynamic lockupDynamic) + returns (ISablierLockupDynamic lockupDynamic) { - ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); + ILockupNFTDescriptor nftDescriptor = new LockupNFTDescriptor(); lockupDynamic = deployLockupDynamic(initialAdmin, nftDescriptor, maxSegmentCount); } - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. + /// @notice Deploys {SablierLockupDynamic} from precompiled bytecode. /// @dev A default value is passed for `maxSegmentCount`. function deployLockupDynamic( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor ) public - returns (ISablierV2LockupDynamic lockupDynamic) + returns (ISablierLockupDynamic lockupDynamic) { lockupDynamic = deployLockupDynamic(initialAdmin, nftDescriptor, MAX_SEGMENT_COUNT); } - /// @notice Deploys {SablierV2LockupDynamic} from precompiled bytecode. + /// @notice Deploys {SablierLockupDynamic} from precompiled bytecode. function deployLockupDynamic( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor, + ILockupNFTDescriptor nftDescriptor, uint256 maxSegmentCount ) public - returns (ISablierV2LockupDynamic lockupDynamic) + returns (ISablierLockupDynamic lockupDynamic) { bytes memory creationBytecode = bytes.concat(BYTECODE_LOCKUP_DYNAMIC, abi.encode(initialAdmin, nftDescriptor, maxSegmentCount)); @@ -90,77 +90,75 @@ contract Precompiles { lockupDynamic := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } require( - address(lockupDynamic) != address(0), "Sablier V2 Precompiles: deployment failed for LockupDynamic contract" + address(lockupDynamic) != address(0), "Lockup Precompiles: deployment failed for LockupDynamic contract" ); } - /// @notice Deploys {SablierV2LockupLinear} from precompiled bytecode. - /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupLinear(address initialAdmin) public returns (ISablierV2LockupLinear lockupLinear) { - ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); + /// @notice Deploys {SablierLockupLinear} from precompiled bytecode. + /// @dev A dummy {LockupNFTDescriptor} is deployed so that the user does not have to provide one. + function deployLockupLinear(address initialAdmin) public returns (ISablierLockupLinear lockupLinear) { + ILockupNFTDescriptor nftDescriptor = new LockupNFTDescriptor(); lockupLinear = deployLockupLinear(initialAdmin, nftDescriptor); } - /// @notice Deploys {SablierV2LockupLinear} from precompiled bytecode. + /// @notice Deploys {SablierLockupLinear} from precompiled bytecode. function deployLockupLinear( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor ) public - returns (ISablierV2LockupLinear lockupLinear) + returns (ISablierLockupLinear lockupLinear) { bytes memory creationBytecode = bytes.concat(BYTECODE_LOCKUP_LINEAR, abi.encode(initialAdmin, nftDescriptor)); assembly { lockupLinear := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } - require( - address(lockupLinear) != address(0), "Sablier V2 Precompiles: deployment failed for LockupLinear contract" - ); + require(address(lockupLinear) != address(0), "Lockup Precompiles: deployment failed for LockupLinear contract"); } - /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode, passing a default value for the + /// @notice Deploys {SablierLockupTranched} from precompiled bytecode, passing a default value for the /// `maxTrancheCount` parameter. /// @dev Notes: /// - A default value is passed for `maxTrancheCount`. - /// - A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. - function deployLockupTranched(address initialAdmin) public returns (ISablierV2LockupTranched lockupTranched) { + /// - A dummy {LockupNFTDescriptor} is deployed so that the user does not have to provide one. + function deployLockupTranched(address initialAdmin) public returns (ISablierLockupTranched lockupTranched) { uint256 maxTrancheCount = MAX_TRANCHE_COUNT; lockupTranched = deployLockupTranched(initialAdmin, maxTrancheCount); } - /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. - /// @dev A dummy {SablierV2NFTDescriptor} is deployed so that the user does not have to provide one. + /// @notice Deploys {SablierLockupTranched} from precompiled bytecode. + /// @dev A dummy {LockupNFTDescriptor} is deployed so that the user does not have to provide one. function deployLockupTranched( address initialAdmin, uint256 maxTrancheCount ) public - returns (ISablierV2LockupTranched lockupTranched) + returns (ISablierLockupTranched lockupTranched) { - ISablierV2NFTDescriptor nftDescriptor = new SablierV2NFTDescriptor(); + ILockupNFTDescriptor nftDescriptor = new LockupNFTDescriptor(); lockupTranched = deployLockupTranched(initialAdmin, nftDescriptor, maxTrancheCount); } - /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. + /// @notice Deploys {SablierLockupTranched} from precompiled bytecode. /// @dev A default value is passed for `maxTrancheCount`. function deployLockupTranched( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor ) public - returns (ISablierV2LockupTranched lockupTranched) + returns (ISablierLockupTranched lockupTranched) { lockupTranched = deployLockupTranched(initialAdmin, nftDescriptor, MAX_TRANCHE_COUNT); } - /// @notice Deploys {SablierV2LockupTranched} from precompiled bytecode. + /// @notice Deploys {SablierLockupTranched} from precompiled bytecode. function deployLockupTranched( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor, + ILockupNFTDescriptor nftDescriptor, uint256 maxTrancheCount ) public - returns (ISablierV2LockupTranched lockupTranched) + returns (ISablierLockupTranched lockupTranched) { bytes memory creationBytecode = bytes.concat(BYTECODE_LOCKUP_TRANCHED, abi.encode(initialAdmin, nftDescriptor, maxTrancheCount)); @@ -168,30 +166,29 @@ contract Precompiles { lockupTranched := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } require( - address(lockupTranched) != address(0), - "Sablier V2 Precompiles: deployment failed for LockupTranched contract" + address(lockupTranched) != address(0), "Lockup Precompiles: deployment failed for LockupTranched contract" ); } - /// @notice Deploys {SablierV2NFTDescriptor} from precompiled bytecode. - function deployNFTDescriptor() public returns (ISablierV2NFTDescriptor nftDescriptor) { + /// @notice Deploys {LockupNFTDescriptor} from precompiled bytecode. + function deployNFTDescriptor() public returns (ILockupNFTDescriptor nftDescriptor) { bytes memory bytecode = BYTECODE_NFT_DESCRIPTOR; assembly { nftDescriptor := create(0, add(bytecode, 0x20), mload(bytecode)) } require( - address(nftDescriptor) != address(0), "Sablier V2 Precompiles: deployment failed for NFTDescriptor contract" + address(nftDescriptor) != address(0), "Lockup Precompiles: deployment failed for NFTDescriptor contract" ); } - /// @notice Deploys all V2 Core contracts. + /// @notice Deploys all Core contracts. function deployCore(address initialAdmin) public returns ( - ISablierV2LockupDynamic lockupDynamic, - ISablierV2LockupLinear lockupLinear, - ISablierV2LockupTranched lockupTranched, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor, + ISablierLockupDynamic lockupDynamic, + ISablierLockupLinear lockupLinear, + ISablierLockupTranched lockupTranched ) { nftDescriptor = deployNFTDescriptor(); @@ -204,63 +201,61 @@ contract Precompiles { PERIPHERY //////////////////////////////////////////////////////////////////////////*/ - /// @notice Deploys {SablierV2BatchLockup} from precompiled bytecode. - function deployBatchLockup() public returns (ISablierV2BatchLockup batchLockup) { + /// @notice Deploys {SablierBatchLockup} from precompiled bytecode. + function deployBatchLockup() public returns (ISablierBatchLockup batchLockup) { bytes memory creationBytecode = BYTECODE_BATCH_LOCKUP; assembly { batchLockup := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } - require( - address(batchLockup) != address(0), "Sablier V2 Precompiles: deployment failed for BatchLockup contract" - ); + require(address(batchLockup) != address(0), "Lockup Precompiles: deployment failed for BatchLockup contract"); } - /// @notice Deploys {SablierV2MerkleLockupFactory} from precompiled bytecode. - function deployMerkleLockupFactory() public returns (ISablierV2MerkleLockupFactory factory) { + /// @notice Deploys {SablierMerkleLockupFactory} from precompiled bytecode. + function deployMerkleLockupFactory() public returns (ISablierMerkleLockupFactory factory) { bytes memory creationBytecode = BYTECODE_MERKLE_LOCKUP_FACTORY; assembly { factory := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } require( - address(factory) != address(0), "Sablier V2 Precompiles: deployment failed for MerkleLockupFactory contract" + address(factory) != address(0), "Lockup Precompiles: deployment failed for MerkleLockupFactory contract" ); } - /// @notice Deploys all V2 Periphery contracts in the following order: + /// @notice Deploys all Periphery contracts in the following order: /// - /// 1. {SablierV2BatchLockup} - /// 2. {SablierV2MerkleLockupFactory} + /// 1. {SablierBatchLockup} + /// 2. {SablierMerkleLockupFactory} function deployPeriphery() public - returns (ISablierV2BatchLockup batchLockup, ISablierV2MerkleLockupFactory merkleLockupFactory) + returns (ISablierBatchLockup batchLockup, ISablierMerkleLockupFactory merkleLockupFactory) { batchLockup = deployBatchLockup(); merkleLockupFactory = deployMerkleLockupFactory(); } - /// @notice Deploys the entire Sablier V2 Protocol from precompiled bytecode. + /// @notice Deploys the entire Lockup Protocol from precompiled bytecode. /// - /// 1. {SablierV2NFTDescriptor} - /// 2. {SablierV2LockupDynamic} - /// 3. {SablierV2LockupLinear} - /// 4. {SablierV2LockupTranched} - /// 5. {SablierV2BatchLockup} - /// 6. {SablierV2MerkleLockupFactory} + /// 1. {LockupNFTDescriptor} + /// 2. {SablierLockupDynamic} + /// 3. {SablierLockupLinear} + /// 4. {SablierLockupTranched} + /// 5. {SablierBatchLockup} + /// 6. {SablierMerkleLockupFactory} function deployProtocol(address initialAdmin) public returns ( - ISablierV2LockupDynamic lockupDynamic, - ISablierV2LockupLinear lockupLinear, - ISablierV2LockupTranched lockupTranched, - ISablierV2NFTDescriptor nftDescriptor, - ISablierV2BatchLockup batchLockup, - ISablierV2MerkleLockupFactory merkleLockupFactory + ILockupNFTDescriptor nftDescriptor, + ISablierLockupDynamic lockupDynamic, + ISablierLockupLinear lockupLinear, + ISablierLockupTranched lockupTranched, + ISablierBatchLockup batchLockup, + ISablierMerkleLockupFactory merkleLockupFactory ) { - // Deploy V2 Core. - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor) = deployCore(initialAdmin); + // Deploy Core. + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched) = deployCore(initialAdmin); - // Deploy V2 Periphery. + // Deploy Periphery. (batchLockup, merkleLockupFactory) = deployPeriphery(); } } diff --git a/script/DeployDeterministicProtocol.s.sol b/script/DeployDeterministicProtocol.s.sol index 3f915c8b2..b506fdece 100644 --- a/script/DeployDeterministicProtocol.s.sol +++ b/script/DeployDeterministicProtocol.s.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; -import { SablierV2MerkleLockupFactory } from "../src/periphery/SablierV2MerkleLockupFactory.sol"; -import { SablierV2BatchLockup } from "../src/periphery/SablierV2BatchLockup.sol"; +import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; +import { SablierMerkleLockupFactory } from "../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys the Sablier V2 Protocol at deterministic addresses across chains. +/// @notice Deploys the Lockup Protocol at deterministic addresses across chains. contract DeployDeterministicProtocol is BaseScript { /// @dev Deploy via Forge. function run(address initialAdmin) @@ -18,26 +18,26 @@ contract DeployDeterministicProtocol is BaseScript { virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor, - SablierV2BatchLockup batchLockup, - SablierV2MerkleLockupFactory merkleLockupFactory + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory ) { bytes32 salt = constructCreate2Salt(); - // Deploy V2 Core. - nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); + // Deploy Core. + nftDescriptor = new LockupNFTDescriptor{ salt: salt }(); lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + new SablierLockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, nftDescriptor); lockupTranched = - new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + new SablierLockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); - // Deploy V2 Periphery. - batchLockup = new SablierV2BatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierV2MerkleLockupFactory{ salt: salt }(); + // Deploy Periphery. + batchLockup = new SablierBatchLockup{ salt: salt }(); + merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); } } diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol index 6e0d907b8..5c5ce05d1 100644 --- a/script/DeployProtocol.s.sol +++ b/script/DeployProtocol.s.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../src/core/SablierV2NFTDescriptor.sol"; -import { SablierV2MerkleLockupFactory } from "../src/periphery/SablierV2MerkleLockupFactory.sol"; -import { SablierV2BatchLockup } from "../src/periphery/SablierV2BatchLockup.sol"; +import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; +import { SablierMerkleLockupFactory } from "../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "./Base.s.sol"; -/// @notice Deploys the Sablier V2 Protocol. +/// @notice Deploys the Lockup Protocol. contract DeployProtocol is BaseScript { /// @dev Deploy via Forge. function run(address initialAdmin) @@ -18,22 +18,22 @@ contract DeployProtocol is BaseScript { virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor, - SablierV2BatchLockup batchLockup, - SablierV2MerkleLockupFactory merkleLockupFactory + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory ) { - // Deploy V2 Core. - nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + // Deploy Core. + nftDescriptor = new LockupNFTDescriptor(); + lockupDynamic = new SablierLockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); - // Deploy V2 Periphery. - batchLockup = new SablierV2BatchLockup(); - merkleLockupFactory = new SablierV2MerkleLockupFactory(); + // Deploy Periphery. + batchLockup = new SablierBatchLockup(); + merkleLockupFactory = new SablierMerkleLockupFactory(); } } diff --git a/script/core/DeployCore.s.sol b/script/core/DeployCore.s.sol index 8c5e99609..b1a803176 100644 --- a/script/core/DeployCore.s.sol +++ b/script/core/DeployCore.s.sol @@ -1,29 +1,29 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys all V2 Core contracts. +/// @notice Deploys all Core contracts. contract DeployCore is BaseScript { function run(address initialAdmin) public virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched ) { - nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + nftDescriptor = new LockupNFTDescriptor(); + lockupDynamic = new SablierLockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployCore2.s.sol b/script/core/DeployCore2.s.sol index 8ab6481d4..027b8d51c 100644 --- a/script/core/DeployCore2.s.sol +++ b/script/core/DeployCore2.s.sol @@ -1,29 +1,29 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployCore2 is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor ) public virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched ) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + lockupDynamic = new SablierLockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployDeterministicCore.s.sol b/script/core/DeployDeterministicCore.s.sol index 78dc11f88..13964749b 100644 --- a/script/core/DeployDeterministicCore.s.sol +++ b/script/core/DeployDeterministicCore.s.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys all V2 Core contracts at deterministic addresses across chains. +/// @notice Deploys all Core contracts at deterministic addresses across chains. /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { function run(address initialAdmin) @@ -16,18 +16,18 @@ contract DeployDeterministicCore is BaseScript { virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched, - SablierV2NFTDescriptor nftDescriptor + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched ) { bytes32 salt = constructCreate2Salt(); - nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); + nftDescriptor = new LockupNFTDescriptor{ salt: salt }(); lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + new SablierLockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, nftDescriptor); lockupTranched = - new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + new SablierLockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployDeterministicCore2.s.sol b/script/core/DeployDeterministicCore2.s.sol index 6895dc331..f453fcc6a 100644 --- a/script/core/DeployDeterministicCore2.s.sol +++ b/script/core/DeployDeterministicCore2.s.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; @@ -12,22 +12,22 @@ import { BaseScript } from "../Base.s.sol"; contract DeployDeterministicCore2 is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor + ILockupNFTDescriptor nftDescriptor ) public virtual broadcast returns ( - SablierV2LockupDynamic lockupDynamic, - SablierV2LockupLinear lockupLinear, - SablierV2LockupTranched lockupTranched + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched ) { bytes32 salt = constructCreate2Salt(); lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + new SablierLockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, nftDescriptor); lockupTranched = - new SablierV2LockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + new SablierLockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployDeterministicLockupDynamic.s.sol b/script/core/DeployDeterministicLockupDynamic.s.sol index 2c2c39c7c..124d4fee1 100644 --- a/script/core/DeployDeterministicLockupDynamic.s.sol +++ b/script/core/DeployDeterministicLockupDynamic.s.sol @@ -1,25 +1,25 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys {SablierV2LockupDynamic} at a deterministic address across chains. +/// @notice Deploys {SablierLockupDynamic} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupDynamic is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupDynamic lockupDynamic) + returns (SablierLockupDynamic lockupDynamic) { bytes32 salt = constructCreate2Salt(); lockupDynamic = - new SablierV2LockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); + new SablierLockupDynamic{ salt: salt }(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); } } diff --git a/script/core/DeployDeterministicLockupLinear.s.sol b/script/core/DeployDeterministicLockupLinear.s.sol index abb62d93c..a1e0d177b 100644 --- a/script/core/DeployDeterministicLockupLinear.s.sol +++ b/script/core/DeployDeterministicLockupLinear.s.sol @@ -1,24 +1,24 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { BaseScript } from "../Base.s.sol"; -/// @dev Deploys {SablierV2LockupLinear} at a deterministic address across chains. +/// @dev Deploys {SablierLockupLinear} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupLinear is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupLinear lockupLinear) + returns (SablierLockupLinear lockupLinear) { bytes32 salt = constructCreate2Salt(); - lockupLinear = new SablierV2LockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor); + lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, initialNFTDescriptor); } } diff --git a/script/core/DeployDeterministicLockupTranched.s.sol b/script/core/DeployDeterministicLockupTranched.s.sol index e69c23772..4990a2a71 100644 --- a/script/core/DeployDeterministicLockupTranched.s.sol +++ b/script/core/DeployDeterministicLockupTranched.s.sol @@ -1,26 +1,25 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; -/// @dev Deploys {SablierV2LockupTranched} at a deterministic address across chains. +/// @dev Deploys {SablierLockupTranched} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicLockupTranched is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupTranched lockupTranched) + returns (SablierLockupTranched lockupTranched) { bytes32 salt = constructCreate2Salt(); - lockupTranched = new SablierV2LockupTranched{ salt: salt }( - initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid] - ); + lockupTranched = + new SablierLockupTranched{ salt: salt }(initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployDeterministicNFTDescriptor.s.sol b/script/core/DeployDeterministicNFTDescriptor.s.sol index 3b28e5f62..4b8530117 100644 --- a/script/core/DeployDeterministicNFTDescriptor.s.sol +++ b/script/core/DeployDeterministicNFTDescriptor.s.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { BaseScript } from "../Base.s.sol"; -/// @dev Deploys {SablierV2NFTDescriptor} at a deterministic address across chains. +/// @dev Deploys {LockupNFTDescriptor} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicNFTDescriptor is BaseScript { - function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { + function run() public virtual broadcast returns (LockupNFTDescriptor nftDescriptor) { bytes32 salt = constructCreate2Salt(); - nftDescriptor = new SablierV2NFTDescriptor{ salt: salt }(); + nftDescriptor = new LockupNFTDescriptor{ salt: salt }(); } } diff --git a/script/core/DeployLockupDynamic.s.sol b/script/core/DeployLockupDynamic.s.sol index 28571f9bf..1ee3f167c 100644 --- a/script/core/DeployLockupDynamic.s.sol +++ b/script/core/DeployLockupDynamic.s.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "../../src/core/SablierV2LockupDynamic.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployLockupDynamic is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupDynamic lockupDynamic) + returns (SablierLockupDynamic lockupDynamic) { - lockupDynamic = new SablierV2LockupDynamic(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); + lockupDynamic = new SablierLockupDynamic(initialAdmin, initialNFTDescriptor, segmentCountMap[block.chainid]); } } diff --git a/script/core/DeployLockupLinear.s.sol b/script/core/DeployLockupLinear.s.sol index 2c49151f6..82ec8349b 100644 --- a/script/core/DeployLockupLinear.s.sol +++ b/script/core/DeployLockupLinear.s.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupLinear } from "../../src/core/SablierV2LockupLinear.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployLockupLinear is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupLinear lockupLinear) + returns (SablierLockupLinear lockupLinear) { - lockupLinear = new SablierV2LockupLinear(initialAdmin, initialNFTDescriptor); + lockupLinear = new SablierLockupLinear(initialAdmin, initialNFTDescriptor); } } diff --git a/script/core/DeployLockupTranched.s.sol b/script/core/DeployLockupTranched.s.sol index 75e7e5b15..3a0c3d47d 100644 --- a/script/core/DeployLockupTranched.s.sol +++ b/script/core/DeployLockupTranched.s.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupTranched } from "../../src/core/SablierV2LockupTranched.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployLockupTranched is BaseScript { function run( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) public virtual broadcast - returns (SablierV2LockupTranched lockupTranched) + returns (SablierLockupTranched lockupTranched) { - lockupTranched = new SablierV2LockupTranched(initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid]); + lockupTranched = new SablierLockupTranched(initialAdmin, initialNFTDescriptor, trancheCountMap[block.chainid]); } } diff --git a/script/core/DeployNFTDescriptor.s.sol b/script/core/DeployNFTDescriptor.s.sol index a454d49b3..1cb0063f0 100644 --- a/script/core/DeployNFTDescriptor.s.sol +++ b/script/core/DeployNFTDescriptor.s.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployNFTDescriptor is BaseScript { - function run() public virtual broadcast returns (SablierV2NFTDescriptor nftDescriptor) { - nftDescriptor = new SablierV2NFTDescriptor(); + function run() public virtual broadcast returns (LockupNFTDescriptor nftDescriptor) { + nftDescriptor = new LockupNFTDescriptor(); } } diff --git a/script/core/GenerateSVG.s.sol b/script/core/GenerateSVG.s.sol index 9348acf34..5f559ffac 100644 --- a/script/core/GenerateSVG.s.sol +++ b/script/core/GenerateSVG.s.sol @@ -3,19 +3,19 @@ pragma solidity >=0.8.22 <0.9.0; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { NFTSVG } from "../../src/core/libraries/NFTSVG.sol"; import { SVGElements } from "../../src/core/libraries/SVGElements.sol"; -import { SablierV2NFTDescriptor } from "../../src/core/SablierV2NFTDescriptor.sol"; import { BaseScript } from "../Base.s.sol"; /// @notice Generates an NFT SVG using the user-provided parameters. -contract GenerateSVG is BaseScript, SablierV2NFTDescriptor { +contract GenerateSVG is BaseScript, LockupNFTDescriptor { using Strings for address; using Strings for string; address internal constant DAI = address(uint160(uint256(keccak256("DAI")))); - address internal constant LOCKUP_LINEAR = address(uint160(uint256(keccak256("SablierV2LockupLinear")))); + address internal constant LOCKUP_LINEAR = address(uint160(uint256(keccak256("SablierLockupLinear")))); /// @param progress The streamed amount as a numerical percentage with 4 implied decimals. /// @param status The status of the stream, as a string. @@ -40,8 +40,8 @@ contract GenerateSVG is BaseScript, SablierV2NFTDescriptor { duration: calculateDurationInDays({ startTime: 0, endTime: duration * 1 days }), progress: stringifyPercentage(progress), progressNumerical: progress, - sablierAddress: LOCKUP_LINEAR.toHexString(), - sablierModel: "Lockup Linear", + lockupAddress: LOCKUP_LINEAR.toHexString(), + lockupModel: "Lockup Linear", status: status }) ); diff --git a/script/core/Init.s.sol b/script/core/Init.s.sol index 6a9248317..021eeec87 100644 --- a/script/core/Init.s.sol +++ b/script/core/Init.s.sol @@ -7,8 +7,8 @@ import { ud60x18 } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2LockupDynamic } from "../../src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupDynamic } from "../../src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { Broker, LockupDynamic, LockupLinear } from "../../src/core/types/DataTypes.sol"; import { BaseScript } from "../Base.s.sol"; @@ -20,8 +20,8 @@ interface IERC20Mint { /// @notice Initializes the protocol by creating some streams. contract Init is BaseScript { function run( - ISablierV2LockupLinear lockupLinear, - ISablierV2LockupDynamic lockupDynamic, + ISablierLockupLinear lockupLinear, + ISablierLockupDynamic lockupDynamic, IERC20 asset ) public @@ -37,7 +37,7 @@ contract Init is BaseScript { // Mint enough assets to the sender. IERC20Mint(address(asset)).mint({ beneficiary: sender, value: 131_601.1e18 + 10_000e18 }); - // Approve the Sablier contracts to transfer the ERC-20 assets from the sender. + // Approve the Lockup contracts to transfer the ERC-20 assets from the sender. asset.approve({ spender: address(lockupLinear), value: type(uint256).max }); asset.approve({ spender: address(lockupDynamic), value: type(uint256).max }); diff --git a/script/periphery/CreateMerkleLL.s.sol b/script/periphery/CreateMerkleLL.s.sol index 685fca6f6..d780b97a9 100644 --- a/script/periphery/CreateMerkleLL.s.sol +++ b/script/periphery/CreateMerkleLL.s.sol @@ -3,20 +3,20 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { LockupLinear } from "../../src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "../../src/periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ISablierMerkleLL } from "../../src/periphery/interfaces/ISablierMerkleLL.sol"; +import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; import { MerkleLockup } from "../../src/periphery/types/DataTypes.sol"; import { BaseScript } from "../Base.s.sol"; contract CreateMerkleLL is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (ISablierV2MerkleLL merkleLL) { + function run() public virtual broadcast returns (ISablierMerkleLL merkleLL) { // Prepare the constructor parameters. - ISablierV2MerkleLockupFactory merkleLockupFactory = - ISablierV2MerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); + ISablierMerkleLockupFactory merkleLockupFactory = + ISablierMerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); // TODO: Update address once deployed. MerkleLockup.ConstructorParams memory baseParams; baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -28,7 +28,8 @@ contract CreateMerkleLL is BaseScript { baseParams.name = "The Boys LL"; baseParams.transferable = true; - ISablierV2LockupLinear lockupLinear = ISablierV2LockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); + // TODO: Update address once deployed. + ISablierLockupLinear lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); LockupLinear.Durations memory streamDurations; streamDurations.cliff = 0; streamDurations.total = 3600; diff --git a/script/periphery/CreateMerkleLT.s.sol b/script/periphery/CreateMerkleLT.s.sol index 817723c02..3195c6f9b 100644 --- a/script/periphery/CreateMerkleLT.s.sol +++ b/script/periphery/CreateMerkleLT.s.sol @@ -4,19 +4,19 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD2x18 } from "@prb/math/src/UD2x18.sol"; -import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; -import { ISablierV2MerkleLT } from "../../src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleLT } from "../../src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; import { BaseScript } from "../Base.s.sol"; contract CreateMerkleLT is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (ISablierV2MerkleLT merkleLT) { + function run() public virtual broadcast returns (ISablierMerkleLT merkleLT) { // Prepare the constructor parameters. - ISablierV2MerkleLockupFactory merkleLockupFactory = - ISablierV2MerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); + ISablierMerkleLockupFactory merkleLockupFactory = + ISablierMerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); // TODO: Update address once deployed. MerkleLockup.ConstructorParams memory baseParams; baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -28,7 +28,8 @@ contract CreateMerkleLT is BaseScript { baseParams.name = "The Boys LT"; baseParams.transferable = true; - ISablierV2LockupTranched lockupTranched = ISablierV2LockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + // TODO: Update address once deployed. + ISablierLockupTranched lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = new MerkleLT.TrancheWithPercentage[](2); tranchesWithPercentages[0] = MerkleLT.TrancheWithPercentage({ unlockPercentage: UD2x18.wrap(50), duration: 3600 }); diff --git a/script/periphery/DeployBatchLockup.t.sol b/script/periphery/DeployBatchLockup.t.sol index ad6bc831b..188738fb5 100644 --- a/script/periphery/DeployBatchLockup.t.sol +++ b/script/periphery/DeployBatchLockup.t.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployBatchLockup is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (SablierV2BatchLockup batchLockup) { - batchLockup = new SablierV2BatchLockup(); + function run() public virtual broadcast returns (SablierBatchLockup batchLockup) { + batchLockup = new SablierBatchLockup(); } } diff --git a/script/periphery/DeployDeterministicBatchLockup.s.sol b/script/periphery/DeployDeterministicBatchLockup.s.sol index de3aa68d0..94e39e448 100644 --- a/script/periphery/DeployDeterministicBatchLockup.s.sol +++ b/script/periphery/DeployDeterministicBatchLockup.s.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys {SablierV2BatchLockup} at a deterministic address across chains. +/// @notice Deploys {SablierBatchLockup} at a deterministic address across chains. /// @dev Reverts if the contract has already been deployed. contract DeployDeterministicBatchLockup is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (SablierV2BatchLockup batchLockup) { + function run() public virtual broadcast returns (SablierBatchLockup batchLockup) { bytes32 salt = constructCreate2Salt(); - batchLockup = new SablierV2BatchLockup{ salt: salt }(); + batchLockup = new SablierBatchLockup{ salt: salt }(); } } diff --git a/script/periphery/DeployDeterministicPeriphery.s.sol b/script/periphery/DeployDeterministicPeriphery.s.sol index f7db44b84..8cde8dc60 100644 --- a/script/periphery/DeployDeterministicPeriphery.s.sol +++ b/script/periphery/DeployDeterministicPeriphery.s.sol @@ -1,15 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; -import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; +import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys all V2 Periphery contracts at deterministic addresses across chains, in the following order: +/// @notice Deploys all Periphery contracts at deterministic addresses across chains, in the following order: /// -/// 1. {SablierV2BatchLockup} -/// 2. {SablierV2MerkleLockupFactory} +/// 1. {SablierBatchLockup} +/// 2. {SablierMerkleLockupFactory} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicPeriphery is BaseScript { @@ -18,10 +18,10 @@ contract DeployDeterministicPeriphery is BaseScript { public virtual broadcast - returns (SablierV2BatchLockup batchLockup, SablierV2MerkleLockupFactory merkleLockupFactory) + returns (SablierBatchLockup batchLockup, SablierMerkleLockupFactory merkleLockupFactory) { bytes32 salt = constructCreate2Salt(); - batchLockup = new SablierV2BatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierV2MerkleLockupFactory{ salt: salt }(); + batchLockup = new SablierBatchLockup{ salt: salt }(); + merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); } } diff --git a/script/periphery/DeployMerkleLockupFactory.s.sol b/script/periphery/DeployMerkleLockupFactory.s.sol index 65b57327a..4b84e4c62 100644 --- a/script/periphery/DeployMerkleLockupFactory.s.sol +++ b/script/periphery/DeployMerkleLockupFactory.s.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; +import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; import { BaseScript } from "../Base.s.sol"; contract DeployMerkleLockupFactory is BaseScript { /// @dev Deploy via Forge. - function run() public virtual broadcast returns (SablierV2MerkleLockupFactory merkleLockupFactory) { - merkleLockupFactory = new SablierV2MerkleLockupFactory(); + function run() public virtual broadcast returns (SablierMerkleLockupFactory merkleLockupFactory) { + merkleLockupFactory = new SablierMerkleLockupFactory(); } } diff --git a/script/periphery/DeployPeriphery.s.sol b/script/periphery/DeployPeriphery.s.sol index 3255b334b..519272717 100644 --- a/script/periphery/DeployPeriphery.s.sol +++ b/script/periphery/DeployPeriphery.s.sol @@ -1,24 +1,24 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierV2MerkleLockupFactory } from "../../src/periphery/SablierV2MerkleLockupFactory.sol"; -import { SablierV2BatchLockup } from "../../src/periphery/SablierV2BatchLockup.sol"; +import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "../Base.s.sol"; -/// @notice Deploys all V2 Periphery contract in the following order: +/// @notice Deploys all Periphery contract in the following order: /// -/// 1. {SablierV2BatchLockup} -/// 2. {SablierV2MerkleLockupFactory} +/// 1. {SablierBatchLockup} +/// 2. {SablierMerkleLockupFactory} contract DeployPeriphery is BaseScript { /// @dev Deploy via Forge. function run() public virtual broadcast - returns (SablierV2BatchLockup batchLockup, SablierV2MerkleLockupFactory merkleLockupFactory) + returns (SablierBatchLockup batchLockup, SablierMerkleLockupFactory merkleLockupFactory) { - batchLockup = new SablierV2BatchLockup(); - merkleLockupFactory = new SablierV2MerkleLockupFactory(); + batchLockup = new SablierBatchLockup(); + merkleLockupFactory = new SablierMerkleLockupFactory(); } } diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index f67e93a02..89dec2660 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -366,13 +366,13 @@ for chain in "${provided_chains[@]}"; do # Save to the chain file { echo "Core Contracts" - echo "SablierV2LockupDynamic = ${lockupDynamic_address}" - echo "SablierV2LockupLinear = ${lockupLinear_address}" - echo "SablierV2LockupTranched = ${lockupTranched_address}" - echo "SablierV2NFTDescriptor = ${nftDescriptor_address}" + echo "LockupNFTDescriptor = ${nftDescriptor_address}" + echo "SablierLockupDynamic = ${lockupDynamic_address}" + echo "SablierLockupLinear = ${lockupLinear_address}" + echo "SablierLockupTranched = ${lockupTranched_address}" echo "Periphery Contracts" - echo "SablierV2BatchLockup = ${batchLockup_address}" - echo "SablierV2MerkleLockupFactory = ${merkleLockupFactory_address}" + echo "SablierBatchLockup = ${batchLockup_address}" + echo "SablierMerkleLockupFactory = ${merkleLockupFactory_address}" } >> "$chain_file" echo -e "${SC}${TICK} Deployed on ${chain}. You can find the addresses in ${chain_file}${NC}" diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index e696f46db..9a57d1775 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -30,18 +30,18 @@ mkdir $artifacts \ ################################################ core=./artifacts/core -cp out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json $core -cp out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json $core -cp out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json $core -cp out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json $core +cp out-optimized/LockupNFTDescriptor.sol/LockupNFTDescriptor.json $core +cp out-optimized/SablierLockupDynamic.sol/SablierLockupDynamic.json $core +cp out-optimized/SablierLockupLinear.sol/SablierLockupLinear.json $core +cp out-optimized/SablierLockupTranched.sol/SablierLockupTranched.json $core core_interfaces=./artifacts/core/interfaces +cp out-optimized/ILockupNFTDescriptor.sol/ILockupNFTDescriptor.json $core_interfaces cp out-optimized/ISablierLockupRecipient.sol/ISablierLockupRecipient.json $core_interfaces -cp out-optimized/ISablierV2Lockup.sol/ISablierV2Lockup.json $core_interfaces -cp out-optimized/ISablierV2LockupDynamic.sol/ISablierV2LockupDynamic.json $core_interfaces -cp out-optimized/ISablierV2LockupLinear.sol/ISablierV2LockupLinear.json $core_interfaces -cp out-optimized/ISablierV2LockupTranched.sol/ISablierV2LockupTranched.json $core_interfaces -cp out-optimized/ISablierV2NFTDescriptor.sol/ISablierV2NFTDescriptor.json $core_interfaces +cp out-optimized/ISablierLockup.sol/ISablierLockup.json $core_interfaces +cp out-optimized/ISablierLockupDynamic.sol/ISablierLockupDynamic.json $core_interfaces +cp out-optimized/ISablierLockupLinear.sol/ISablierLockupLinear.json $core_interfaces +cp out-optimized/ISablierLockupTranched.sol/ISablierLockupTranched.json $core_interfaces core_libraries=./artifacts/core/libraries cp out-optimized/Errors.sol/Errors.json $core_libraries @@ -51,16 +51,16 @@ cp out-optimized/Errors.sol/Errors.json $core_libraries ################################################ periphery=./artifacts/periphery -cp out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json $periphery -cp out-optimized/SablierV2MerkleLL.sol/SablierV2MerkleLL.json $periphery -cp out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json $periphery -cp out-optimized/SablierV2MerkleLT.sol/SablierV2MerkleLT.json $periphery +cp out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json $periphery +cp out-optimized/SablierMerkleLL.sol/SablierMerkleLL.json $periphery +cp out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json $periphery +cp out-optimized/SablierMerkleLT.sol/SablierMerkleLT.json $periphery periphery_interfaces=./artifacts/periphery/interfaces -cp out-optimized/ISablierV2BatchLockup.sol/ISablierV2BatchLockup.json $periphery_interfaces -cp out-optimized/ISablierV2MerkleLL.sol/ISablierV2MerkleLL.json $periphery_interfaces -cp out-optimized/ISablierV2MerkleLockupFactory.sol/ISablierV2MerkleLockupFactory.json $periphery_interfaces -cp out-optimized/ISablierV2MerkleLT.sol/ISablierV2MerkleLT.json $periphery_interfaces +cp out-optimized/ISablierBatchLockup.sol/ISablierBatchLockup.json $periphery_interfaces +cp out-optimized/ISablierMerkleLL.sol/ISablierMerkleLL.json $periphery_interfaces +cp out-optimized/ISablierMerkleLockupFactory.sol/ISablierMerkleLockupFactory.json $periphery_interfaces +cp out-optimized/ISablierMerkleLT.sol/ISablierMerkleLT.json $periphery_interfaces periphery_libraries=./artifacts/periphery/libraries cp out-optimized/libraries/Errors.sol/Errors.json $periphery_libraries diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index a50926ead..4b1b0a80e 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -12,12 +12,12 @@ set -euo pipefail FOUNDRY_PROFILE=optimized forge build # Retrieve the raw bytecodes, removing the "0x" prefix -batch_lockup=$(cat out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json | jq -r '.bytecode.object' | cut -c 3-) -lockup_dynamic=$(cat out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) -lockup_linear=$(cat out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) -lockup_tranched=$(cat out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) -merkle_lockup_factory=$(cat out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json | jq -r '.bytecode.object' | cut -c 3-) -nft_descriptor=$(cat out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) +batch_lockup=$(cat out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json | jq -r '.bytecode.object' | cut -c 3-) +lockup_dynamic=$(cat out-optimized/SablierLockupDynamic.sol/SablierLockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) +lockup_linear=$(cat out-optimized/SablierLockupLinear.sol/SablierLockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) +lockup_tranched=$(cat out-optimized/SablierLockupTranched.sol/SablierLockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) +merkle_lockup_factory=$(cat out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json | jq -r '.bytecode.object' | cut -c 3-) +nft_descriptor=$(cat out-optimized/LockupNFTDescriptor.sol/LockupNFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) precompiles_path="precompiles/Precompiles.sol" if [ ! -f $precompiles_path ]; then diff --git a/src/core/SablierV2NFTDescriptor.sol b/src/core/LockupNFTDescriptor.sol similarity index 78% rename from src/core/SablierV2NFTDescriptor.sol rename to src/core/LockupNFTDescriptor.sol index 171dc4878..51161a7bf 100644 --- a/src/core/SablierV2NFTDescriptor.sol +++ b/src/core/LockupNFTDescriptor.sol @@ -7,8 +7,8 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions import { Base64 } from "@openzeppelin/contracts/utils/Base64.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { ISablierV2Lockup } from "./interfaces/ISablierV2Lockup.sol"; -import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; +import { ILockupNFTDescriptor } from "./interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockup } from "./interfaces/ISablierLockup.sol"; import { Lockup } from "./types/DataTypes.sol"; import { Errors } from "./libraries/Errors.sol"; @@ -17,25 +17,27 @@ import { SVGElements } from "./libraries/SVGElements.sol"; /* -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ███╗ ██╗███████╗████████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ████╗ ██║██╔════╝╚══██╔══╝ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██╔██╗ ██║█████╗ ██║ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ██║╚██╗██║██╔══╝ ██║ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ██║ ╚████║██║ ██║ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝ + + +██████╗ ███████╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ +██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ +██║ ██║█████╗ ███████╗██║ ██████╔╝██║██████╔╝ ██║ ██║ ██║██████╔╝ +██║ ██║██╔══╝ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ██║ ██║██╔══██╗ +██████╔╝███████╗███████║╚██████╗██║ ██║██║██║ ██║ ╚██████╔╝██║ ██║ +╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ -███╗ ██╗███████╗████████╗ ██████╗ ███████╗███████╗ ██████╗██████╗ ██╗██████╗ ████████╗ ██████╗ ██████╗ -████╗ ██║██╔════╝╚══██╔══╝ ██╔══██╗██╔════╝██╔════╝██╔════╝██╔══██╗██║██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ -██╔██╗ ██║█████╗ ██║ ██║ ██║█████╗ ███████╗██║ ██████╔╝██║██████╔╝ ██║ ██║ ██║██████╔╝ -██║╚██╗██║██╔══╝ ██║ ██║ ██║██╔══╝ ╚════██║██║ ██╔══██╗██║██╔═══╝ ██║ ██║ ██║██╔══██╗ -██║ ╚████║██║ ██║ ██████╔╝███████╗███████║╚██████╗██║ ██║██║██║ ██║ ╚██████╔╝██║ ██║ -╚═╝ ╚═══╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ */ -/// @title SablierV2NFTDescriptor -/// @notice See the documentation in {ISablierV2NFTDescriptor}. -contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { +/// @title LockupNFTDescriptor +/// @notice See the documentation in {ILockupNFTDescriptor}. +contract LockupNFTDescriptor is ILockupNFTDescriptor { using Strings for address; using Strings for string; using Strings for uint256; @@ -51,57 +53,57 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { uint128 depositedAmount; bool isTransferable; string json; + ISablierLockup lockup; + string lockupModel; + string lockupStringified; bytes returnData; - ISablierV2Lockup sablier; - string sablierModel; - string sablierStringified; string status; string svg; uint256 streamedPercentage; bool success; } - /// @inheritdoc ISablierV2NFTDescriptor - function tokenURI(IERC721Metadata sablier, uint256 streamId) external view override returns (string memory uri) { + /// @inheritdoc ILockupNFTDescriptor + function tokenURI(IERC721Metadata lockup, uint256 streamId) external view override returns (string memory uri) { TokenURIVars memory vars; // Load the contracts. - vars.sablier = ISablierV2Lockup(address(sablier)); - vars.sablierModel = mapSymbol(sablier); - vars.sablierStringified = address(sablier).toHexString(); - vars.asset = address(vars.sablier.getAsset(streamId)); + vars.lockup = ISablierLockup(address(lockup)); + vars.lockupModel = mapSymbol(lockup); + vars.lockupStringified = address(lockup).toHexString(); + vars.asset = address(vars.lockup.getAsset(streamId)); vars.assetSymbol = safeAssetSymbol(vars.asset); - vars.depositedAmount = vars.sablier.getDepositedAmount(streamId); + vars.depositedAmount = vars.lockup.getDepositedAmount(streamId); // Load the stream's data. - vars.status = stringifyStatus(vars.sablier.statusOf(streamId)); + vars.status = stringifyStatus(vars.lockup.statusOf(streamId)); vars.streamedPercentage = calculateStreamedPercentage({ - streamedAmount: vars.sablier.streamedAmountOf(streamId), + streamedAmount: vars.lockup.streamedAmountOf(streamId), depositedAmount: vars.depositedAmount }); // Generate the SVG. vars.svg = NFTSVG.generateSVG( NFTSVG.SVGParams({ - accentColor: generateAccentColor(address(sablier), streamId), + accentColor: generateAccentColor(address(lockup), streamId), amount: abbreviateAmount({ amount: vars.depositedAmount, decimals: safeAssetDecimals(vars.asset) }), assetAddress: vars.asset.toHexString(), assetSymbol: vars.assetSymbol, duration: calculateDurationInDays({ - startTime: vars.sablier.getStartTime(streamId), - endTime: vars.sablier.getEndTime(streamId) + startTime: vars.lockup.getStartTime(streamId), + endTime: vars.lockup.getEndTime(streamId) }), - sablierAddress: vars.sablierStringified, + lockupAddress: vars.lockupStringified, progress: stringifyPercentage(vars.streamedPercentage), progressNumerical: vars.streamedPercentage, status: vars.status, - sablierModel: vars.sablierModel + lockupModel: vars.lockupModel }) ); // Performs a low-level call to handle older deployments that miss the `isTransferable` function. (vars.success, vars.returnData) = - address(vars.sablier).staticcall(abi.encodeCall(ISablierV2Lockup.isTransferable, (streamId))); + address(vars.lockup).staticcall(abi.encodeCall(ISablierLockup.isTransferable, (streamId))); // When the call has failed, the stream NFT is assumed to be transferable. vars.isTransferable = vars.success ? abi.decode(vars.returnData, (bool)) : true; @@ -111,20 +113,20 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { '{"attributes":', generateAttributes({ assetSymbol: vars.assetSymbol, - sender: vars.sablier.getSender(streamId).toHexString(), + sender: vars.lockup.getSender(streamId).toHexString(), status: vars.status }), ',"description":"', generateDescription({ - sablierModel: vars.sablierModel, + lockupModel: vars.lockupModel, assetSymbol: vars.assetSymbol, - sablierStringified: vars.sablierStringified, + lockupStringified: vars.lockupStringified, assetAddress: vars.asset.toHexString(), streamId: streamId.toString(), isTransferable: vars.isTransferable }), '","external_url":"https://sablier.com","name":"', - generateName({ sablierModel: vars.sablierModel, streamId: streamId.toString() }), + generateName({ lockupModel: vars.lockupModel, streamId: streamId.toString() }), '","image":"data:image/svg+xml;base64,', Base64.encode(bytes(vars.svg)), '"}' @@ -277,9 +279,9 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @notice Generates a string with the NFT's JSON metadata description, which provides a high-level overview. function generateDescription( - string memory sablierModel, + string memory lockupModel, string memory assetSymbol, - string memory sablierStringified, + string memory lockupStringified, string memory assetAddress, string memory streamId, bool isTransferable @@ -295,16 +297,16 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { : unicode"❕INFO: This NFT is non-transferable. It cannot be sold or transferred to another account."; return string.concat( - "This NFT represents a payment stream in a Sablier V2 ", - sablierModel, + "This NFT represents a payment stream in a Sablier Lockup ", + lockupModel, " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", assetSymbol, ".\\n\\n- Stream ID: ", streamId, "\\n- ", - sablierModel, + lockupModel, " Address: ", - sablierStringified, + lockupStringified, "\\n- ", assetSymbol, " Address: ", @@ -316,8 +318,8 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @notice Generates a string with the NFT's JSON metadata name, which is unique for each stream. /// @dev The `streamId` is equivalent to the ERC-721 `tokenId`. - function generateName(string memory sablierModel, string memory streamId) internal pure returns (string memory) { - return string.concat("Sablier V2 ", sablierModel, " #", streamId); + function generateName(string memory lockupModel, string memory streamId) internal pure returns (string memory) { + return string.concat("Sablier ", lockupModel, " #", streamId); } /// @notice Checks whether the provided string contains only alphanumeric characters, spaces, and dashes. @@ -347,14 +349,14 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor { /// @dev Reverts if the symbol is unknown. function mapSymbol(IERC721Metadata sablier) internal view returns (string memory) { string memory symbol = sablier.symbol(); - if (symbol.equal("SAB-V2-LOCKUP-LIN")) { - return "Lockup Linear"; - } else if (symbol.equal("SAB-V2-LOCKUP-DYN")) { - return "Lockup Dynamic"; - } else if (symbol.equal("SAB-V2-LOCKUP-TRA")) { - return "Lockup Tranched"; + if (symbol.equal("SAB-LOCKUP-LIN") || symbol.equal("SAB-V2-LOCKUP-LIN")) { + return "Sablier Lockup Linear"; + } else if (symbol.equal("SAB-LOCKUP-DYN") || symbol.equal("SAB-V2-LOCKUP-DYN")) { + return "Sablier Lockup Dynamic"; + } else if (symbol.equal("SAB-LOCKUP-TRA") || symbol.equal("SAB-V2-LOCKUP-TRA")) { + return "Sablier Lockup Tranched"; } else { - revert Errors.SablierV2NFTDescriptor_UnknownNFT(sablier, symbol); + revert Errors.LockupNFTDescriptor_UnknownNFT(sablier, symbol); } } diff --git a/src/core/SablierV2LockupDynamic.sol b/src/core/SablierLockupDynamic.sol similarity index 84% rename from src/core/SablierV2LockupDynamic.sol rename to src/core/SablierLockupDynamic.sol index b06b15c64..f43622933 100644 --- a/src/core/SablierV2LockupDynamic.sol +++ b/src/core/SablierLockupDynamic.sol @@ -8,35 +8,35 @@ import { PRBMathCastingUint128 as CastingUint128 } from "@prb/math/src/casting/U import { PRBMathCastingUint40 as CastingUint40 } from "@prb/math/src/casting/Uint40.sol"; import { SD59x18 } from "@prb/math/src/SD59x18.sol"; -import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2LockupDynamic } from "./interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierLockup } from "./abstracts/SablierLockup.sol"; +import { ILockupNFTDescriptor } from "./interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupDynamic } from "./interfaces/ISablierLockupDynamic.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupDynamic } from "./types/DataTypes.sol"; /* -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ -██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ██████╗ ██╗ ██╗███╗ ██╗ █████╗ ███╗ ███╗██╗ ██████╗ -██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ ██╔══██╗╚██╗ ██╔╝████╗ ██║██╔══██╗████╗ ████║██║██╔════╝ -██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ ██║ ██║ ╚████╔╝ ██╔██╗ ██║███████║██╔████╔██║██║██║ -██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ ██║ ██║ ╚██╔╝ ██║╚██╗██║██╔══██║██║╚██╔╝██║██║██║ -███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ ██████╔╝ ██║ ██║ ╚████║██║ ██║██║ ╚═╝ ██║██║╚██████╗ -╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═════╝ +██████╗ ██╗ ██╗███╗ ██╗ █████╗ ███╗ ███╗██╗ ██████╗ +██╔══██╗╚██╗ ██╔╝████╗ ██║██╔══██╗████╗ ████║██║██╔════╝ +██║ ██║ ╚████╔╝ ██╔██╗ ██║███████║██╔████╔██║██║██║ +██║ ██║ ╚██╔╝ ██║╚██╗██║██╔══██║██║╚██╔╝██║██║██║ +██████╔╝ ██║ ██║ ╚████║██║ ██║██║ ╚═╝ ██║██║╚██████╗ +╚═════╝ ╚═╝ ╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═════╝ */ -/// @title SablierV2LockupDynamic -/// @notice See the documentation in {ISablierV2LockupDynamic}. -contract SablierV2LockupDynamic is - ISablierV2LockupDynamic, // 5 inherited components - SablierV2Lockup // 14 inherited components +/// @title SablierLockupDynamic +/// @notice See the documentation in {ISablierLockupDynamic}. +contract SablierLockupDynamic is + ISablierLockupDynamic, // 5 inherited components + SablierLockup // 14 inherited components { using CastingUint128 for uint128; using CastingUint40 for uint40; @@ -46,10 +46,10 @@ contract SablierV2LockupDynamic is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic uint256 public immutable override MAX_SEGMENT_COUNT; - /// @dev Stream segments mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. + /// @dev Stream segments mapped by stream IDs. This complements the `_streams` mapping in {SablierLockup}. mapping(uint256 id => LockupDynamic.Segment[] segments) internal _segments; /*////////////////////////////////////////////////////////////////////////// @@ -62,11 +62,11 @@ contract SablierV2LockupDynamic is /// @param maxSegmentCount The maximum number of segments allowed in a stream. constructor( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor, + ILockupNFTDescriptor initialNFTDescriptor, uint256 maxSegmentCount ) - ERC721("Sablier V2 Lockup Dynamic NFT", "SAB-V2-LOCKUP-DYN") - SablierV2Lockup(initialAdmin, initialNFTDescriptor) + ERC721("Sablier Lockup Dynamic NFT", "SAB-LOCKUP-DYN") + SablierLockup(initialAdmin, initialNFTDescriptor) { MAX_SEGMENT_COUNT = maxSegmentCount; nextStreamId = 1; @@ -76,7 +76,7 @@ contract SablierV2LockupDynamic is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic function getSegments(uint256 streamId) external view @@ -87,7 +87,7 @@ contract SablierV2LockupDynamic is segments = _segments[streamId]; } - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic function getStream(uint256 streamId) external view @@ -119,7 +119,7 @@ contract SablierV2LockupDynamic is }); } - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic function getTimestamps(uint256 streamId) external view @@ -134,7 +134,7 @@ contract SablierV2LockupDynamic is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic function createWithDurations(LockupDynamic.CreateWithDurations calldata params) external override @@ -160,7 +160,7 @@ contract SablierV2LockupDynamic is ); } - /// @inheritdoc ISablierV2LockupDynamic + /// @inheritdoc ISablierLockupDynamic function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) external override @@ -175,7 +175,7 @@ contract SablierV2LockupDynamic is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc SablierV2Lockup + /// @inheritdoc SablierLockup /// @dev The distribution function is: /// /// $$ @@ -362,7 +362,7 @@ contract SablierV2LockupDynamic is } // Log the newly created stream. - emit ISablierV2LockupDynamic.CreateLockupDynamicStream({ + emit ISablierLockupDynamic.CreateLockupDynamicStream({ streamId: streamId, funder: msg.sender, sender: params.sender, diff --git a/src/core/SablierV2LockupLinear.sol b/src/core/SablierLockupLinear.sol similarity index 79% rename from src/core/SablierV2LockupLinear.sol rename to src/core/SablierLockupLinear.sol index d8380cc93..7f5822023 100644 --- a/src/core/SablierV2LockupLinear.sol +++ b/src/core/SablierLockupLinear.sol @@ -6,36 +6,36 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2LockupLinear } from "./interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierLockup } from "./abstracts/SablierLockup.sol"; +import { SablierLockup } from "./abstracts/SablierLockup.sol"; +import { ILockupNFTDescriptor } from "./interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupLinear } from "./interfaces/ISablierLockupLinear.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupLinear } from "./types/DataTypes.sol"; /* -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ -██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ██╗ ██╗███╗ ██╗███████╗ █████╗ ██████╗ -██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ ██║ ██║████╗ ██║██╔════╝██╔══██╗██╔══██╗ -██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ ██║ ██║██╔██╗ ██║█████╗ ███████║██████╔╝ -██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ ██║ ██║██║╚██╗██║██╔══╝ ██╔══██║██╔══██╗ -███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ ███████╗██║██║ ╚████║███████╗██║ ██║██║ ██║ -╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ +██╗ ██╗███╗ ██╗███████╗ █████╗ ██████╗ +██║ ██║████╗ ██║██╔════╝██╔══██╗██╔══██╗ +██║ ██║██╔██╗ ██║█████╗ ███████║██████╔╝ +██║ ██║██║╚██╗██║██╔══╝ ██╔══██║██╔══██╗ +███████╗██║██║ ╚████║███████╗██║ ██║██║ ██║ +╚══════╝╚═╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ */ -/// @title SablierV2LockupLinear -/// @notice See the documentation in {ISablierV2LockupLinear}. -contract SablierV2LockupLinear is - ISablierV2LockupLinear, // 5 inherited components - SablierV2Lockup // 14 inherited components +/// @title SablierLockupLinear +/// @notice See the documentation in {ISablierLockupLinear}. +contract SablierLockupLinear is + ISablierLockupLinear, // 5 inherited components + SablierLockup // 14 inherited components { using SafeERC20 for IERC20; @@ -43,7 +43,7 @@ contract SablierV2LockupLinear is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @dev Cliff times mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. + /// @dev Cliff times mapped by stream IDs. This complements the `_streams` mapping in {SablierLockup}. mapping(uint256 id => uint40 cliff) internal _cliffs; /*////////////////////////////////////////////////////////////////////////// @@ -55,10 +55,10 @@ contract SablierV2LockupLinear is /// @param initialNFTDescriptor The address of the initial NFT descriptor. constructor( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor + ILockupNFTDescriptor initialNFTDescriptor ) - ERC721("Sablier V2 Lockup Linear NFT", "SAB-V2-LOCKUP-LIN") - SablierV2Lockup(initialAdmin, initialNFTDescriptor) + ERC721("Sablier Lockup Linear NFT", "SAB-LOCKUP-LIN") + SablierLockup(initialAdmin, initialNFTDescriptor) { nextStreamId = 1; } @@ -67,12 +67,12 @@ contract SablierV2LockupLinear is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupLinear + /// @inheritdoc ISablierLockupLinear function getCliffTime(uint256 streamId) external view override notNull(streamId) returns (uint40 cliffTime) { cliffTime = _cliffs[streamId]; } - /// @inheritdoc ISablierV2LockupLinear + /// @inheritdoc ISablierLockupLinear function getStream(uint256 streamId) external view @@ -104,7 +104,7 @@ contract SablierV2LockupLinear is }); } - /// @inheritdoc ISablierV2LockupLinear + /// @inheritdoc ISablierLockupLinear function getTimestamps(uint256 streamId) external view @@ -123,7 +123,7 @@ contract SablierV2LockupLinear is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupLinear + /// @inheritdoc ISablierLockupLinear function createWithDurations(LockupLinear.CreateWithDurations calldata params) external override @@ -159,7 +159,7 @@ contract SablierV2LockupLinear is ); } - /// @inheritdoc ISablierV2LockupLinear + /// @inheritdoc ISablierLockupLinear function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) external override @@ -174,7 +174,7 @@ contract SablierV2LockupLinear is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc SablierV2Lockup + /// @inheritdoc SablierLockup /// @dev The distribution function is: /// /// $$ @@ -283,7 +283,7 @@ contract SablierV2LockupLinear is } // Log the newly created stream. - emit ISablierV2LockupLinear.CreateLockupLinearStream({ + emit ISablierLockupLinear.CreateLockupLinearStream({ streamId: streamId, funder: msg.sender, sender: params.sender, diff --git a/src/core/SablierV2LockupTranched.sol b/src/core/SablierLockupTranched.sol similarity index 76% rename from src/core/SablierV2LockupTranched.sol rename to src/core/SablierLockupTranched.sol index aaf0105a1..d80a79791 100644 --- a/src/core/SablierV2LockupTranched.sol +++ b/src/core/SablierLockupTranched.sol @@ -5,35 +5,35 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ERC721 } from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import { SablierV2Lockup } from "./abstracts/SablierV2Lockup.sol"; -import { ISablierV2LockupTranched } from "./interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol"; +import { SablierLockup } from "./abstracts/SablierLockup.sol"; +import { ILockupNFTDescriptor } from "./interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupTranched } from "./interfaces/ISablierLockupTranched.sol"; import { Helpers } from "./libraries/Helpers.sol"; import { Lockup, LockupTranched } from "./types/DataTypes.sol"; /* -███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██╗██████╗ -██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██║╚════██╗ -███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ █████╔╝ -╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ╚██╗ ██╔╝██╔═══╝ -███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ╚████╔╝ ███████╗ -╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝ +███████╗ █████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ +██╔════╝██╔══██╗██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ +███████╗███████║██████╔╝██║ ██║█████╗ ██████╔╝ ██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ +╚════██║██╔══██║██╔══██╗██║ ██║██╔══╝ ██╔══██╗ ██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ +███████║██║ ██║██████╔╝███████╗██║███████╗██║ ██║ ███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ +╚══════╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝╚══════╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ -██╗ ██████╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ████████╗██████╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗███████╗██████╗ -██║ ██╔═══██╗██╔════╝██║ ██╔╝██║ ██║██╔══██╗ ╚══██╔══╝██╔══██╗██╔══██╗████╗ ██║██╔════╝██║ ██║██╔════╝██╔══██╗ -██║ ██║ ██║██║ █████╔╝ ██║ ██║██████╔╝ ██║ ██████╔╝███████║██╔██╗ ██║██║ ███████║█████╗ ██║ ██║ -██║ ██║ ██║██║ ██╔═██╗ ██║ ██║██╔═══╝ ██║ ██╔══██╗██╔══██║██║╚██╗██║██║ ██╔══██║██╔══╝ ██║ ██║ -███████╗╚██████╔╝╚██████╗██║ ██╗╚██████╔╝██║ ██║ ██║ ██║██║ ██║██║ ╚████║╚██████╗██║ ██║███████╗██████╔╝ -╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═════╝ +████████╗██████╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗███████╗██████╗ +╚══██╔══╝██╔══██╗██╔══██╗████╗ ██║██╔════╝██║ ██║██╔════╝██╔══██╗ + ██║ ██████╔╝███████║██╔██╗ ██║██║ ███████║█████╗ ██║ ██║ + ██║ ██╔══██╗██╔══██║██║╚██╗██║██║ ██╔══██║██╔══╝ ██║ ██║ + ██║ ██║ ██║██║ ██║██║ ╚████║╚██████╗██║ ██║███████╗██████╔╝ + ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═════╝ */ -/// @title SablierV2LockupTranched -/// @notice See the documentation in {ISablierV2LockupTranched}. -contract SablierV2LockupTranched is - ISablierV2LockupTranched, // 5 inherited components - SablierV2Lockup // 14 inherited components +/// @title SablierLockupTranched +/// @notice See the documentation in {ISablierLockupTranched}. +contract SablierLockupTranched is + ISablierLockupTranched, // 5 inherited components + SablierLockup // 14 inherited components { using SafeERC20 for IERC20; @@ -41,10 +41,10 @@ contract SablierV2LockupTranched is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched uint256 public immutable override MAX_TRANCHE_COUNT; - /// @dev Stream tranches mapped by stream IDs. This complements the `_streams` mapping in {SablierV2Lockup}. + /// @dev Stream tranches mapped by stream IDs. This complements the `_streams` mapping in {SablierLockup}. mapping(uint256 id => LockupTranched.Tranche[] tranches) internal _tranches; /*////////////////////////////////////////////////////////////////////////// @@ -57,11 +57,11 @@ contract SablierV2LockupTranched is /// @param maxTrancheCount The maximum number of tranches allowed in a stream. constructor( address initialAdmin, - ISablierV2NFTDescriptor initialNFTDescriptor, + ILockupNFTDescriptor initialNFTDescriptor, uint256 maxTrancheCount ) - ERC721("Sablier V2 Lockup Tranched NFT", "SAB-V2-LOCKUP-TRA") - SablierV2Lockup(initialAdmin, initialNFTDescriptor) + ERC721("Sablier Lockup Tranched NFT", "SAB-LOCKUP-TRA") + SablierLockup(initialAdmin, initialNFTDescriptor) { MAX_TRANCHE_COUNT = maxTrancheCount; nextStreamId = 1; @@ -71,7 +71,7 @@ contract SablierV2LockupTranched is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched function getStream(uint256 streamId) external view @@ -103,7 +103,7 @@ contract SablierV2LockupTranched is }); } - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched function getTimestamps(uint256 streamId) external view @@ -114,7 +114,7 @@ contract SablierV2LockupTranched is timestamps = LockupTranched.Timestamps({ start: _streams[streamId].startTime, end: _streams[streamId].endTime }); } - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched function getTranches(uint256 streamId) external view @@ -129,7 +129,7 @@ contract SablierV2LockupTranched is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched function createWithDurations(LockupTranched.CreateWithDurations calldata params) external override @@ -155,7 +155,7 @@ contract SablierV2LockupTranched is ); } - /// @inheritdoc ISablierV2LockupTranched + /// @inheritdoc ISablierLockupTranched function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) external override @@ -170,7 +170,7 @@ contract SablierV2LockupTranched is INTERNAL CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc SablierV2Lockup + /// @inheritdoc SablierLockup /// @dev The distribution function is: /// /// $$ @@ -266,7 +266,7 @@ contract SablierV2LockupTranched is } // Log the newly created stream. - emit ISablierV2LockupTranched.CreateLockupTranchedStream({ + emit ISablierLockupTranched.CreateLockupTranchedStream({ streamId: streamId, funder: msg.sender, sender: params.sender, diff --git a/src/core/abstracts/SablierV2Lockup.sol b/src/core/abstracts/SablierLockup.sol similarity index 84% rename from src/core/abstracts/SablierV2Lockup.sol rename to src/core/abstracts/SablierLockup.sol index 95166bd86..9deecb6f9 100644 --- a/src/core/abstracts/SablierV2Lockup.sol +++ b/src/core/abstracts/SablierLockup.sol @@ -8,20 +8,20 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; +import { ILockupNFTDescriptor } from "../interfaces/ILockupNFTDescriptor.sol"; import { ISablierLockupRecipient } from "../interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "../interfaces/ISablierV2Lockup.sol"; -import { ISablierV2NFTDescriptor } from "../interfaces/ISablierV2NFTDescriptor.sol"; +import { ISablierLockup } from "../interfaces/ISablierLockup.sol"; import { Errors } from "../libraries/Errors.sol"; import { Lockup } from "../types/DataTypes.sol"; import { Adminable } from "./Adminable.sol"; import { NoDelegateCall } from "./NoDelegateCall.sol"; -/// @title SablierV2Lockup -/// @notice See the documentation in {ISablierV2Lockup}. -abstract contract SablierV2Lockup is +/// @title SablierLockup +/// @notice See the documentation in {ISablierLockup}. +abstract contract SablierLockup is NoDelegateCall, // 0 inherited components Adminable, // 1 inherited components - ISablierV2Lockup, // 7 inherited components + ISablierLockup, // 7 inherited components ERC721 // 6 inherited components { using SafeERC20 for IERC20; @@ -30,19 +30,19 @@ abstract contract SablierV2Lockup is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup UD60x18 public constant override MAX_BROKER_FEE = UD60x18.wrap(0.1e18); - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup uint256 public override nextStreamId; - /// @inheritdoc ISablierV2Lockup - ISablierV2NFTDescriptor public override nftDescriptor; + /// @inheritdoc ISablierLockup + ILockupNFTDescriptor public override nftDescriptor; /// @dev Mapping of contracts allowed to hook to Sablier when a stream is canceled or when assets are withdrawn. mapping(address recipient => bool allowed) internal _allowedToHook; - /// @dev Sablier V2 Lockup streams mapped by unsigned integers. + /// @dev Lockup streams mapped by unsigned integers. mapping(uint256 id => Lockup.Stream stream) internal _streams; /*////////////////////////////////////////////////////////////////////////// @@ -52,7 +52,7 @@ abstract contract SablierV2Lockup is /// @dev Emits a {TransferAdmin} event. /// @param initialAdmin The address of the initial contract admin. /// @param initialNFTDescriptor The address of the initial NFT descriptor. - constructor(address initialAdmin, ISablierV2NFTDescriptor initialNFTDescriptor) { + constructor(address initialAdmin, ILockupNFTDescriptor initialNFTDescriptor) { admin = initialAdmin; nftDescriptor = initialNFTDescriptor; emit TransferAdmin({ oldAdmin: address(0), newAdmin: initialAdmin }); @@ -65,7 +65,7 @@ abstract contract SablierV2Lockup is /// @dev Checks that `streamId` does not reference a null stream. modifier notNull(uint256 streamId) { if (!_streams[streamId].isStream) { - revert Errors.SablierV2Lockup_Null(streamId); + revert Errors.SablierLockup_Null(streamId); } _; } @@ -74,12 +74,12 @@ abstract contract SablierV2Lockup is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getAsset(uint256 streamId) external view override notNull(streamId) returns (IERC20 asset) { asset = _streams[streamId].asset; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getDepositedAmount(uint256 streamId) external view @@ -90,18 +90,18 @@ abstract contract SablierV2Lockup is depositedAmount = _streams[streamId].amounts.deposited; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getEndTime(uint256 streamId) external view override notNull(streamId) returns (uint40 endTime) { endTime = _streams[streamId].endTime; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getRecipient(uint256 streamId) external view override returns (address recipient) { // Check the stream NFT exists and return the owner, which is the stream's recipient. recipient = _requireOwned({ tokenId: streamId }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getRefundedAmount(uint256 streamId) external view @@ -112,17 +112,17 @@ abstract contract SablierV2Lockup is refundedAmount = _streams[streamId].amounts.refunded; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getSender(uint256 streamId) external view override notNull(streamId) returns (address sender) { sender = _streams[streamId].sender; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getStartTime(uint256 streamId) external view override notNull(streamId) returns (uint40 startTime) { startTime = _streams[streamId].startTime; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function getWithdrawnAmount(uint256 streamId) external view @@ -133,46 +133,46 @@ abstract contract SablierV2Lockup is withdrawnAmount = _streams[streamId].amounts.withdrawn; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isAllowedToHook(address recipient) external view returns (bool result) { result = _allowedToHook[recipient]; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isCancelable(uint256 streamId) external view override notNull(streamId) returns (bool result) { if (_statusOf(streamId) != Lockup.Status.SETTLED) { result = _streams[streamId].isCancelable; } } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isCold(uint256 streamId) external view override notNull(streamId) returns (bool result) { Lockup.Status status = _statusOf(streamId); result = status == Lockup.Status.SETTLED || status == Lockup.Status.CANCELED || status == Lockup.Status.DEPLETED; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isDepleted(uint256 streamId) external view override notNull(streamId) returns (bool result) { result = _streams[streamId].isDepleted; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isStream(uint256 streamId) external view override returns (bool result) { result = _streams[streamId].isStream; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isTransferable(uint256 streamId) external view override notNull(streamId) returns (bool result) { result = _streams[streamId].isTransferable; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function isWarm(uint256 streamId) external view override notNull(streamId) returns (bool result) { Lockup.Status status = _statusOf(streamId); result = status == Lockup.Status.PENDING || status == Lockup.Status.STREAMING; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function refundableAmountOf(uint256 streamId) external view @@ -189,12 +189,12 @@ abstract contract SablierV2Lockup is // Otherwise, the result is implicitly zero. } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function statusOf(uint256 streamId) external view override notNull(streamId) returns (Lockup.Status status) { status = _statusOf(streamId); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function streamedAmountOf(uint256 streamId) public view @@ -220,12 +220,12 @@ abstract contract SablierV2Lockup is uri = nftDescriptor.tokenURI({ sablier: this, streamId: streamId }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function wasCanceled(uint256 streamId) external view override notNull(streamId) returns (bool result) { result = _streams[streamId].wasCanceled; } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function withdrawableAmountOf(uint256 streamId) external view @@ -240,63 +240,63 @@ abstract contract SablierV2Lockup is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function allowToHook(address recipient) external override onlyAdmin { // Check: non-zero code size. if (recipient.code.length == 0) { - revert Errors.SablierV2Lockup_AllowToHookZeroCodeSize(recipient); + revert Errors.SablierLockup_AllowToHookZeroCodeSize(recipient); } // Check: recipients implements the ERC-165 interface ID required by {ISablierLockupRecipient}. bytes4 interfaceId = type(ISablierLockupRecipient).interfaceId; if (!ISablierLockupRecipient(recipient).supportsInterface(interfaceId)) { - revert Errors.SablierV2Lockup_AllowToHookUnsupportedInterface(recipient); + revert Errors.SablierLockup_AllowToHookUnsupportedInterface(recipient); } // Effect: put the recipient on the allowlist. _allowedToHook[recipient] = true; // Log the allowlist addition. - emit ISablierV2Lockup.AllowToHook({ admin: msg.sender, recipient: recipient }); + emit ISablierLockup.AllowToHook({ admin: msg.sender, recipient: recipient }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function burn(uint256 streamId) external override noDelegateCall notNull(streamId) { // Check: only depleted streams can be burned. if (!_streams[streamId].isDepleted) { - revert Errors.SablierV2Lockup_StreamNotDepleted(streamId); + revert Errors.SablierLockup_StreamNotDepleted(streamId); } // Check: // 1. NFT exists (see {IERC721.getApproved}). // 2. `msg.sender` is either the owner of the NFT or an approved third party. if (!_isCallerStreamRecipientOrApproved(streamId)) { - revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); + revert Errors.SablierLockup_Unauthorized(streamId, msg.sender); } // Effect: burn the NFT. _burn({ tokenId: streamId }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function cancel(uint256 streamId) public override noDelegateCall notNull(streamId) { // Check: the stream is neither depleted nor canceled. if (_streams[streamId].isDepleted) { - revert Errors.SablierV2Lockup_StreamDepleted(streamId); + revert Errors.SablierLockup_StreamDepleted(streamId); } else if (_streams[streamId].wasCanceled) { - revert Errors.SablierV2Lockup_StreamCanceled(streamId); + revert Errors.SablierLockup_StreamCanceled(streamId); } // Check: `msg.sender` is the stream's sender. if (!_isCallerStreamSender(streamId)) { - revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); + revert Errors.SablierLockup_Unauthorized(streamId, msg.sender); } // Checks, Effects and Interactions: cancel the stream. _cancel(streamId); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function cancelMultiple(uint256[] calldata streamIds) external override noDelegateCall { // Iterate over the provided array of stream IDs and cancel each stream. uint256 count = streamIds.length; @@ -306,41 +306,41 @@ abstract contract SablierV2Lockup is } } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function renounce(uint256 streamId) external override noDelegateCall notNull(streamId) { // Check: the stream is not cold. Lockup.Status status = _statusOf(streamId); if (status == Lockup.Status.DEPLETED) { - revert Errors.SablierV2Lockup_StreamDepleted(streamId); + revert Errors.SablierLockup_StreamDepleted(streamId); } else if (status == Lockup.Status.CANCELED) { - revert Errors.SablierV2Lockup_StreamCanceled(streamId); + revert Errors.SablierLockup_StreamCanceled(streamId); } else if (status == Lockup.Status.SETTLED) { - revert Errors.SablierV2Lockup_StreamSettled(streamId); + revert Errors.SablierLockup_StreamSettled(streamId); } // Check: `msg.sender` is the stream's sender. if (!_isCallerStreamSender(streamId)) { - revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); + revert Errors.SablierLockup_Unauthorized(streamId, msg.sender); } // Checks and Effects: renounce the stream. _renounce(streamId); // Log the renouncement. - emit ISablierV2Lockup.RenounceLockupStream(streamId); + emit ISablierLockup.RenounceLockupStream(streamId); // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); } - /// @inheritdoc ISablierV2Lockup - function setNFTDescriptor(ISablierV2NFTDescriptor newNFTDescriptor) external override onlyAdmin { + /// @inheritdoc ISablierLockup + function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external override onlyAdmin { // Effect: set the NFT descriptor. - ISablierV2NFTDescriptor oldNftDescriptor = nftDescriptor; + ILockupNFTDescriptor oldNftDescriptor = nftDescriptor; nftDescriptor = newNFTDescriptor; // Log the change of the NFT descriptor. - emit ISablierV2Lockup.SetNFTDescriptor({ + emit ISablierLockup.SetNFTDescriptor({ admin: msg.sender, oldNFTDescriptor: oldNftDescriptor, newNFTDescriptor: newNFTDescriptor @@ -350,21 +350,21 @@ abstract contract SablierV2Lockup is emit BatchMetadataUpdate({ _fromTokenId: 1, _toTokenId: nextStreamId - 1 }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function withdraw(uint256 streamId, address to, uint128 amount) public override noDelegateCall notNull(streamId) { // Check: the stream is not depleted. if (_streams[streamId].isDepleted) { - revert Errors.SablierV2Lockup_StreamDepleted(streamId); + revert Errors.SablierLockup_StreamDepleted(streamId); } // Check: the withdrawal address is not zero. if (to == address(0)) { - revert Errors.SablierV2Lockup_WithdrawToZeroAddress(streamId); + revert Errors.SablierLockup_WithdrawToZeroAddress(streamId); } // Check: the withdraw amount is not zero. if (amount == 0) { - revert Errors.SablierV2Lockup_WithdrawAmountZero(streamId); + revert Errors.SablierLockup_WithdrawAmountZero(streamId); } // Retrieve the recipient from storage. @@ -373,13 +373,13 @@ abstract contract SablierV2Lockup is // Check: if `msg.sender` is neither the stream's recipient nor an approved third party, the withdrawal address // must be the recipient. if (to != recipient && !_isCallerStreamRecipientOrApproved(streamId)) { - revert Errors.SablierV2Lockup_WithdrawalAddressNotRecipient(streamId, msg.sender, to); + revert Errors.SablierLockup_WithdrawalAddressNotRecipient(streamId, msg.sender, to); } // Check: the withdraw amount is not greater than the withdrawable amount. uint128 withdrawableAmount = _withdrawableAmountOf(streamId); if (amount > withdrawableAmount) { - revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount); + revert Errors.SablierLockup_Overdraw(streamId, amount, withdrawableAmount); } // Effects and Interactions: make the withdrawal. @@ -399,18 +399,18 @@ abstract contract SablierV2Lockup is // Check: the recipient's hook returned the correct selector. if (selector != ISablierLockupRecipient.onSablierLockupWithdraw.selector) { - revert Errors.SablierV2Lockup_InvalidHookSelector(recipient); + revert Errors.SablierLockup_InvalidHookSelector(recipient); } } } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function withdrawMax(uint256 streamId, address to) external override returns (uint128 withdrawnAmount) { withdrawnAmount = _withdrawableAmountOf(streamId); withdraw({ streamId: streamId, to: to, amount: withdrawnAmount }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function withdrawMaxAndTransfer( uint256 streamId, address newRecipient @@ -424,7 +424,7 @@ abstract contract SablierV2Lockup is // Check: the caller is the current recipient. This also checks that the NFT was not burned. address currentRecipient = _ownerOf(streamId); if (msg.sender != currentRecipient) { - revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender); + revert Errors.SablierLockup_Unauthorized(streamId, msg.sender); } // Skip the withdrawal if the withdrawable amount is zero. @@ -437,7 +437,7 @@ abstract contract SablierV2Lockup is _transfer({ from: currentRecipient, to: newRecipient, tokenId: streamId }); } - /// @inheritdoc ISablierV2Lockup + /// @inheritdoc ISablierLockup function withdrawMultiple( uint256[] calldata streamIds, uint128[] calldata amounts @@ -450,7 +450,7 @@ abstract contract SablierV2Lockup is uint256 streamIdsCount = streamIds.length; uint256 amountsCount = amounts.length; if (streamIdsCount != amountsCount) { - revert Errors.SablierV2Lockup_WithdrawArrayCountsNotEqual(streamIdsCount, amountsCount); + revert Errors.SablierLockup_WithdrawArrayCountsNotEqual(streamIdsCount, amountsCount); } // Iterate over the provided array of stream IDs, and withdraw from each stream to the recipient. @@ -533,12 +533,12 @@ abstract contract SablierV2Lockup is // Check: the stream is not settled. if (streamedAmount >= amounts.deposited) { - revert Errors.SablierV2Lockup_StreamSettled(streamId); + revert Errors.SablierLockup_StreamSettled(streamId); } // Check: the stream is cancelable. if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); + revert Errors.SablierLockup_StreamNotCancelable(streamId); } // Calculate the sender's amount. @@ -575,7 +575,7 @@ abstract contract SablierV2Lockup is asset.safeTransfer({ to: sender, value: senderAmount }); // Log the cancellation. - emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount); + emit ISablierLockup.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount); // Emit an ERC-4906 event to trigger an update of the NFT metadata. emit MetadataUpdate({ _tokenId: streamId }); @@ -591,7 +591,7 @@ abstract contract SablierV2Lockup is // Check: the recipient's hook returned the correct selector. if (selector != ISablierLockupRecipient.onSablierLockupCancel.selector) { - revert Errors.SablierV2Lockup_InvalidHookSelector(recipient); + revert Errors.SablierLockup_InvalidHookSelector(recipient); } } } @@ -600,7 +600,7 @@ abstract contract SablierV2Lockup is function _renounce(uint256 streamId) internal { // Check: the stream is cancelable. if (!_streams[streamId].isCancelable) { - revert Errors.SablierV2Lockup_StreamNotCancelable(streamId); + revert Errors.SablierLockup_StreamNotCancelable(streamId); } // Effect: renounce the stream by making it not cancelable. @@ -621,7 +621,7 @@ abstract contract SablierV2Lockup is address from = _ownerOf(streamId); if (from != address(0) && to != address(0) && !_streams[streamId].isTransferable) { - revert Errors.SablierV2Lockup_NotTransferable(streamId); + revert Errors.SablierLockup_NotTransferable(streamId); } // Emit an ERC-4906 event to trigger an update of the NFT metadata. @@ -655,6 +655,6 @@ abstract contract SablierV2Lockup is asset.safeTransfer({ to: to, value: amount }); // Log the withdrawal. - emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount); + emit ISablierLockup.WithdrawFromLockupStream(streamId, to, asset, amount); } } diff --git a/src/core/interfaces/ISablierV2NFTDescriptor.sol b/src/core/interfaces/ILockupNFTDescriptor.sol similarity index 89% rename from src/core/interfaces/ISablierV2NFTDescriptor.sol rename to src/core/interfaces/ILockupNFTDescriptor.sol index f0d134cb8..d80d7f38f 100644 --- a/src/core/interfaces/ISablierV2NFTDescriptor.sol +++ b/src/core/interfaces/ILockupNFTDescriptor.sol @@ -3,10 +3,10 @@ pragma solidity >=0.8.22; import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; -/// @title ISablierV2NFTDescriptor -/// @notice This contract generates the URI describing the Sablier V2 stream NFTs. +/// @title ILockupNFTDescriptor +/// @notice This contract generates the URI describing the Sablier stream NFTs. /// @dev Inspired by Uniswap V3 Positions NFTs. -interface ISablierV2NFTDescriptor { +interface ILockupNFTDescriptor { /// @notice Produces the URI describing a particular stream NFT. /// @dev This is a data URI with the JSON contents directly inlined. /// @param sablier The address of the Sablier contract the stream was created in. diff --git a/src/core/interfaces/ISablierV2Lockup.sol b/src/core/interfaces/ISablierLockup.sol similarity index 97% rename from src/core/interfaces/ISablierV2Lockup.sol rename to src/core/interfaces/ISablierLockup.sol index 3be3d2309..f3ccd1dfd 100644 --- a/src/core/interfaces/ISablierV2Lockup.sol +++ b/src/core/interfaces/ISablierLockup.sol @@ -8,11 +8,11 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { Lockup } from "../types/DataTypes.sol"; import { IAdminable } from "./IAdminable.sol"; -import { ISablierV2NFTDescriptor } from "./ISablierV2NFTDescriptor.sol"; +import { ILockupNFTDescriptor } from "./ILockupNFTDescriptor.sol"; -/// @title ISablierV2Lockup -/// @notice Common logic between all Sablier V2 Lockup contracts. -interface ISablierV2Lockup is +/// @title ISablierLockup +/// @notice Common logic between all Sablier Lockup contracts. +interface ISablierLockup is IAdminable, // 0 inherited components IERC4906, // 2 inherited components IERC721Metadata // 2 inherited components @@ -53,7 +53,7 @@ interface ISablierV2Lockup is /// @param oldNFTDescriptor The address of the old NFT descriptor contract. /// @param newNFTDescriptor The address of the new NFT descriptor contract. event SetNFTDescriptor( - address indexed admin, ISablierV2NFTDescriptor oldNFTDescriptor, ISablierV2NFTDescriptor newNFTDescriptor + address indexed admin, ILockupNFTDescriptor oldNFTDescriptor, ILockupNFTDescriptor newNFTDescriptor ); /// @notice Emitted when assets are withdrawn from a stream. @@ -153,7 +153,7 @@ interface ISablierV2Lockup is function nextStreamId() external view returns (uint256); /// @notice Contract that generates the non-fungible token URI. - function nftDescriptor() external view returns (ISablierV2NFTDescriptor); + function nftDescriptor() external view returns (ILockupNFTDescriptor); /// @notice Calculates the amount that the sender would be refunded if the stream were canceled, denoted in units /// of the asset's decimals. @@ -279,7 +279,7 @@ interface ISablierV2Lockup is /// - `msg.sender` must be the contract admin. /// /// @param newNFTDescriptor The address of the new NFT descriptor contract. - function setNFTDescriptor(ISablierV2NFTDescriptor newNFTDescriptor) external; + function setNFTDescriptor(ILockupNFTDescriptor newNFTDescriptor) external; /// @notice Withdraws the provided amount of assets from the stream to the `to` address. /// diff --git a/src/core/interfaces/ISablierV2LockupDynamic.sol b/src/core/interfaces/ISablierLockupDynamic.sol similarity index 97% rename from src/core/interfaces/ISablierV2LockupDynamic.sol rename to src/core/interfaces/ISablierLockupDynamic.sol index 292b48d86..d6b4604af 100644 --- a/src/core/interfaces/ISablierV2LockupDynamic.sol +++ b/src/core/interfaces/ISablierLockupDynamic.sol @@ -4,11 +4,11 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupDynamic } from "../types/DataTypes.sol"; -import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; +import { ISablierLockup } from "./ISablierLockup.sol"; -/// @title ISablierV2LockupDynamic +/// @title ISablierLockupDynamic /// @notice Creates and manages Lockup streams with a dynamic distribution function. -interface ISablierV2LockupDynamic is ISablierV2Lockup { +interface ISablierLockupDynamic is ISablierLockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/core/interfaces/ISablierV2LockupLinear.sol b/src/core/interfaces/ISablierLockupLinear.sol similarity index 97% rename from src/core/interfaces/ISablierV2LockupLinear.sol rename to src/core/interfaces/ISablierLockupLinear.sol index 425514c09..213e92f87 100644 --- a/src/core/interfaces/ISablierV2LockupLinear.sol +++ b/src/core/interfaces/ISablierLockupLinear.sol @@ -4,11 +4,11 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupLinear } from "../types/DataTypes.sol"; -import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; +import { ISablierLockup } from "./ISablierLockup.sol"; -/// @title ISablierV2LockupLinear +/// @title ISablierLockupLinear /// @notice Creates and manages Lockup streams with a linear distribution function. -interface ISablierV2LockupLinear is ISablierV2Lockup { +interface ISablierLockupLinear is ISablierLockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/core/interfaces/ISablierV2LockupTranched.sol b/src/core/interfaces/ISablierLockupTranched.sol similarity index 97% rename from src/core/interfaces/ISablierV2LockupTranched.sol rename to src/core/interfaces/ISablierLockupTranched.sol index 261accb9a..a1d147255 100644 --- a/src/core/interfaces/ISablierV2LockupTranched.sol +++ b/src/core/interfaces/ISablierLockupTranched.sol @@ -4,11 +4,11 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupTranched } from "../types/DataTypes.sol"; -import { ISablierV2Lockup } from "./ISablierV2Lockup.sol"; +import { ISablierLockup } from "./ISablierLockup.sol"; -/// @title ISablierV2LockupTranched +/// @title ISablierLockupTranched /// @notice Creates and manages Lockup streams with a tranched distribution function. -interface ISablierV2LockupTranched is ISablierV2Lockup { +interface ISablierLockupTranched is ISablierLockup { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/core/libraries/Errors.sol b/src/core/libraries/Errors.sol index 03e6c8e05..b329ecdbf 100644 --- a/src/core/libraries/Errors.sol +++ b/src/core/libraries/Errors.sol @@ -18,142 +18,140 @@ library Errors { error DelegateCall(); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP + LOCKUP-NFT-DESCRIPTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Thrown when trying to generate the token URI for an unknown ERC-721 NFT contract. + error LockupNFTDescriptor_UnknownNFT(IERC721Metadata nft, string symbol); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-LOCKUP //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to allow to hook a contract that doesn't implement the interface correctly. - error SablierV2Lockup_AllowToHookUnsupportedInterface(address recipient); + error SablierLockup_AllowToHookUnsupportedInterface(address recipient); /// @notice Thrown when trying to allow to hook an address with no code. - error SablierV2Lockup_AllowToHookZeroCodeSize(address recipient); + error SablierLockup_AllowToHookZeroCodeSize(address recipient); /// @notice Thrown when the broker fee exceeds the maximum allowed fee. - error SablierV2Lockup_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxBrokerFee); + error SablierLockup_BrokerFeeTooHigh(UD60x18 brokerFee, UD60x18 maxBrokerFee); /// @notice Thrown when trying to create a stream with a zero deposit amount. - error SablierV2Lockup_DepositAmountZero(); + error SablierLockup_DepositAmountZero(); /// @notice Thrown when trying to create a stream with an end time not in the future. - error SablierV2Lockup_EndTimeNotInTheFuture(uint40 blockTimestamp, uint40 endTime); + error SablierLockup_EndTimeNotInTheFuture(uint40 blockTimestamp, uint40 endTime); /// @notice Thrown when the hook does not return the correct selector. - error SablierV2Lockup_InvalidHookSelector(address recipient); + error SablierLockup_InvalidHookSelector(address recipient); /// @notice Thrown when trying to transfer Stream NFT when transferability is disabled. - error SablierV2Lockup_NotTransferable(uint256 tokenId); + error SablierLockup_NotTransferable(uint256 tokenId); /// @notice Thrown when the ID references a null stream. - error SablierV2Lockup_Null(uint256 streamId); + error SablierLockup_Null(uint256 streamId); /// @notice Thrown when trying to withdraw an amount greater than the withdrawable amount. - error SablierV2Lockup_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); + error SablierLockup_Overdraw(uint256 streamId, uint128 amount, uint128 withdrawableAmount); /// @notice Thrown when trying to create a stream with a zero start time. - error SablierV2Lockup_StartTimeZero(); + error SablierLockup_StartTimeZero(); /// @notice Thrown when trying to cancel or renounce a canceled stream. - error SablierV2Lockup_StreamCanceled(uint256 streamId); + error SablierLockup_StreamCanceled(uint256 streamId); /// @notice Thrown when trying to cancel, renounce, or withdraw from a depleted stream. - error SablierV2Lockup_StreamDepleted(uint256 streamId); + error SablierLockup_StreamDepleted(uint256 streamId); /// @notice Thrown when trying to cancel or renounce a stream that is not cancelable. - error SablierV2Lockup_StreamNotCancelable(uint256 streamId); + error SablierLockup_StreamNotCancelable(uint256 streamId); /// @notice Thrown when trying to burn a stream that is not depleted. - error SablierV2Lockup_StreamNotDepleted(uint256 streamId); + error SablierLockup_StreamNotDepleted(uint256 streamId); /// @notice Thrown when trying to cancel or renounce a settled stream. - error SablierV2Lockup_StreamSettled(uint256 streamId); + error SablierLockup_StreamSettled(uint256 streamId); /// @notice Thrown when `msg.sender` lacks authorization to perform an action. - error SablierV2Lockup_Unauthorized(uint256 streamId, address caller); + error SablierLockup_Unauthorized(uint256 streamId, address caller); /// @notice Thrown when trying to withdraw to an address other than the recipient's. - error SablierV2Lockup_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); + error SablierLockup_WithdrawalAddressNotRecipient(uint256 streamId, address caller, address to); /// @notice Thrown when trying to withdraw zero assets from a stream. - error SablierV2Lockup_WithdrawAmountZero(uint256 streamId); + error SablierLockup_WithdrawAmountZero(uint256 streamId); /// @notice Thrown when trying to withdraw from multiple streams and the number of stream IDs does /// not match the number of withdraw amounts. - error SablierV2Lockup_WithdrawArrayCountsNotEqual(uint256 streamIdsCount, uint256 amountsCount); + error SablierLockup_WithdrawArrayCountsNotEqual(uint256 streamIdsCount, uint256 amountsCount); /// @notice Thrown when trying to withdraw to the zero address. - error SablierV2Lockup_WithdrawToZeroAddress(uint256 streamId); + error SablierLockup_WithdrawToZeroAddress(uint256 streamId); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-DYNAMIC + SABLIER-LOCKUP-DYNAMIC //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to create a stream with a deposit amount not equal to the sum of the /// segment amounts. - error SablierV2LockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( + error SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( uint128 depositAmount, uint128 segmentAmountsSum ); /// @notice Thrown when trying to create a stream with more segments than the maximum allowed. - error SablierV2LockupDynamic_SegmentCountTooHigh(uint256 count); + error SablierLockupDynamic_SegmentCountTooHigh(uint256 count); /// @notice Thrown when trying to create a stream with no segments. - error SablierV2LockupDynamic_SegmentCountZero(); + error SablierLockupDynamic_SegmentCountZero(); /// @notice Thrown when trying to create a stream with unordered segment timestamps. - error SablierV2LockupDynamic_SegmentTimestampsNotOrdered( + error SablierLockupDynamic_SegmentTimestampsNotOrdered( uint256 index, uint40 previousTimestamp, uint40 currentTimestamp ); /// @notice Thrown when trying to create a stream with a start time not strictly less than the first /// segment timestamp. - error SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( - uint40 startTime, uint40 firstSegmentTimestamp - ); + error SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp(uint40 startTime, uint40 firstSegmentTimestamp); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-LINEAR + SABLIER-LOCKUP-LINEAR //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to create a stream with a cliff time not strictly less than the end time. - error SablierV2LockupLinear_CliffTimeNotLessThanEndTime(uint40 cliffTime, uint40 endTime); + error SablierLockupLinear_CliffTimeNotLessThanEndTime(uint40 cliffTime, uint40 endTime); /// @notice Thrown when trying to create a stream with a start time not strictly less than the cliff time, when the /// cliff time does not have a zero value. - error SablierV2LockupLinear_StartTimeNotLessThanCliffTime(uint40 startTime, uint40 cliffTime); + error SablierLockupLinear_StartTimeNotLessThanCliffTime(uint40 startTime, uint40 cliffTime); /// @notice Thrown when trying to create a stream with a start time not strictly less than the end time. - error SablierV2LockupLinear_StartTimeNotLessThanEndTime(uint40 startTime, uint40 endTime); - - /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-NFT-DESCRIPTOR - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Thrown when trying to generate the token URI for an unknown ERC-721 NFT contract. - error SablierV2NFTDescriptor_UnknownNFT(IERC721Metadata nft, string symbol); + error SablierLockupLinear_StartTimeNotLessThanEndTime(uint40 startTime, uint40 endTime); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHE + SABLIER-LOCKUP-TRANCHE //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to create a stream with a deposit amount not equal to the sum of the /// tranche amounts. - error SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum( + error SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum( uint128 depositAmount, uint128 trancheAmountsSum ); /// @notice Thrown when trying to create a stream with a start time not strictly less than the first /// tranche timestamp. - error SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( + error SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( uint40 startTime, uint40 firstTrancheTimestamp ); /// @notice Thrown when trying to create a stream with more tranches than the maximum allowed. - error SablierV2LockupTranched_TrancheCountTooHigh(uint256 count); + error SablierLockupTranched_TrancheCountTooHigh(uint256 count); /// @notice Thrown when trying to create a stream with no tranches. - error SablierV2LockupTranched_TrancheCountZero(); + error SablierLockupTranched_TrancheCountZero(); /// @notice Thrown when trying to create a stream with unordered tranche timestamps. - error SablierV2LockupTranched_TrancheTimestampsNotOrdered( + error SablierLockupTranched_TrancheTimestampsNotOrdered( uint256 index, uint40 previousTimestamp, uint40 currentTimestamp ); } diff --git a/src/core/libraries/Helpers.sol b/src/core/libraries/Helpers.sol index d4bd40b48..e0202c081 100644 --- a/src/core/libraries/Helpers.sol +++ b/src/core/libraries/Helpers.sol @@ -7,7 +7,7 @@ import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../types/Da import { Errors } from "./Errors.sol"; /// @title Helpers -/// @notice Library with helper functions needed across the Sablier V2 contracts. +/// @notice Library with helper functions needed across the Lockup contracts. library Helpers { /*////////////////////////////////////////////////////////////////////////// INTERNAL CONSTANT FUNCTIONS @@ -25,7 +25,7 @@ library Helpers { // Make the block timestamp the stream's start time. uint40 startTime = uint40(block.timestamp); - // It is safe to use unchecked arithmetic because {SablierV2LockupDynamic-_create} will nonetheless check the + // It is safe to use unchecked arithmetic because {SablierLockupDynamic-_create} will nonetheless check the // correctness of the calculated segment timestamps. unchecked { // The first segment is precomputed because it is needed in the for loop below. @@ -58,7 +58,7 @@ library Helpers { // Make the block timestamp the stream's start time. uint40 startTime = uint40(block.timestamp); - // It is safe to use unchecked arithmetic because {SablierV2LockupTranched-_create} will nonetheless check the + // It is safe to use unchecked arithmetic because {SablierLockupTranched-_create} will nonetheless check the // correctness of the calculated tranche timestamps. unchecked { // The first tranche is precomputed because it is needed in the for loop below. @@ -93,7 +93,7 @@ library Helpers { // Check: the broker fee is not greater than `maxBrokerFee`. if (brokerFee.gt(maxBrokerFee)) { - revert Errors.SablierV2Lockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee); + revert Errors.SablierLockup_BrokerFeeTooHigh(brokerFee, maxBrokerFee); } // Calculate the broker fee amount. @@ -107,7 +107,7 @@ library Helpers { amounts.deposit = totalAmount - amounts.brokerFee; } - /// @dev Checks the parameters of the {SablierV2LockupDynamic-_create} function. + /// @dev Checks the parameters of the {SablierLockupDynamic-_create} function. function checkCreateLockupDynamic( uint128 depositAmount, LockupDynamic.Segment[] memory segments, @@ -119,67 +119,67 @@ library Helpers { { // Check: the deposit amount is not zero. if (depositAmount == 0) { - revert Errors.SablierV2Lockup_DepositAmountZero(); + revert Errors.SablierLockup_DepositAmountZero(); } // Check: the start time is not zero. if (startTime == 0) { - revert Errors.SablierV2Lockup_StartTimeZero(); + revert Errors.SablierLockup_StartTimeZero(); } // Check: the segment count is not zero. uint256 segmentCount = segments.length; if (segmentCount == 0) { - revert Errors.SablierV2LockupDynamic_SegmentCountZero(); + revert Errors.SablierLockupDynamic_SegmentCountZero(); } // Check: the segment count is not greater than the maximum allowed. if (segmentCount > maxSegmentCount) { - revert Errors.SablierV2LockupDynamic_SegmentCountTooHigh(segmentCount); + revert Errors.SablierLockupDynamic_SegmentCountTooHigh(segmentCount); } // Check: requirements of segments. _checkSegments(segments, depositAmount, startTime); } - /// @dev Checks the parameters of the {SablierV2LockupLinear-_create} function. + /// @dev Checks the parameters of the {SablierLockupLinear-_create} function. function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Timestamps memory timestamps) internal view { // Check: the deposit amount is not zero. if (depositAmount == 0) { - revert Errors.SablierV2Lockup_DepositAmountZero(); + revert Errors.SablierLockup_DepositAmountZero(); } // Check: the start time is not zero. if (timestamps.start == 0) { - revert Errors.SablierV2Lockup_StartTimeZero(); + revert Errors.SablierLockup_StartTimeZero(); } // Since a cliff time of zero means there is no cliff, the following checks are performed only if it's not zero. if (timestamps.cliff > 0) { // Check: the start time is strictly less than the cliff time. if (timestamps.start >= timestamps.cliff) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime(timestamps.start, timestamps.cliff); + revert Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime(timestamps.start, timestamps.cliff); } // Check: the cliff time is strictly less than the end time. if (timestamps.cliff >= timestamps.end) { - revert Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime(timestamps.cliff, timestamps.end); + revert Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime(timestamps.cliff, timestamps.end); } } // Check: the start time is strictly less than the end time. if (timestamps.start >= timestamps.end) { - revert Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime(timestamps.start, timestamps.end); + revert Errors.SablierLockupLinear_StartTimeNotLessThanEndTime(timestamps.start, timestamps.end); } // Check: the end time is in the future. uint40 blockTimestamp = uint40(block.timestamp); if (blockTimestamp >= timestamps.end) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, timestamps.end); + revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, timestamps.end); } } - /// @dev Checks the parameters of the {SablierV2LockupTranched-_create} function. + /// @dev Checks the parameters of the {SablierLockupTranched-_create} function. function checkCreateLockupTranched( uint128 depositAmount, LockupTranched.Tranche[] memory tranches, @@ -191,23 +191,23 @@ library Helpers { { // Check: the deposit amount is not zero. if (depositAmount == 0) { - revert Errors.SablierV2Lockup_DepositAmountZero(); + revert Errors.SablierLockup_DepositAmountZero(); } // Check: the start time is not zero. if (startTime == 0) { - revert Errors.SablierV2Lockup_StartTimeZero(); + revert Errors.SablierLockup_StartTimeZero(); } // Check: the tranche count is not zero. uint256 trancheCount = tranches.length; if (trancheCount == 0) { - revert Errors.SablierV2LockupTranched_TrancheCountZero(); + revert Errors.SablierLockupTranched_TrancheCountZero(); } // Check: the tranche count is not greater than the maximum allowed. if (trancheCount > maxTrancheCount) { - revert Errors.SablierV2LockupTranched_TrancheCountTooHigh(trancheCount); + revert Errors.SablierLockupTranched_TrancheCountTooHigh(trancheCount); } // Check: requirements of tranches. @@ -234,7 +234,7 @@ library Helpers { { // Check: the start time is strictly less than the first segment timestamp. if (startTime >= segments[0].timestamp) { - revert Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( + revert Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp( startTime, segments[0].timestamp ); } @@ -256,7 +256,7 @@ library Helpers { // Check: the current timestamp is strictly greater than the previous timestamp. currentSegmentTimestamp = segments[index].timestamp; if (currentSegmentTimestamp <= previousSegmentTimestamp) { - revert Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered( + revert Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered( index, previousSegmentTimestamp, currentSegmentTimestamp ); } @@ -270,12 +270,12 @@ library Helpers { // time. The variable is not renamed for gas efficiency purposes. uint40 blockTimestamp = uint40(block.timestamp); if (blockTimestamp >= currentSegmentTimestamp) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, currentSegmentTimestamp); + revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, currentSegmentTimestamp); } // Check: the deposit amount is equal to the segment amounts sum. if (depositAmount != segmentAmountsSum) { - revert Errors.SablierV2LockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( + revert Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( depositAmount, segmentAmountsSum ); } @@ -297,7 +297,7 @@ library Helpers { { // Check: the start time is strictly less than the first tranche timestamp. if (startTime >= tranches[0].timestamp) { - revert Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( + revert Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp( startTime, tranches[0].timestamp ); } @@ -319,7 +319,7 @@ library Helpers { // Check: the current timestamp is strictly greater than the previous timestamp. currentTrancheTimestamp = tranches[index].timestamp; if (currentTrancheTimestamp <= previousTrancheTimestamp) { - revert Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered( + revert Errors.SablierLockupTranched_TrancheTimestampsNotOrdered( index, previousTrancheTimestamp, currentTrancheTimestamp ); } @@ -333,12 +333,12 @@ library Helpers { // time. The variable is not renamed for gas efficiency purposes. uint40 blockTimestamp = uint40(block.timestamp); if (blockTimestamp >= currentTrancheTimestamp) { - revert Errors.SablierV2Lockup_EndTimeNotInTheFuture(blockTimestamp, currentTrancheTimestamp); + revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, currentTrancheTimestamp); } // Check: the deposit amount is equal to the tranche amounts sum. if (depositAmount != trancheAmountsSum) { - revert Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum( + revert Errors.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum( depositAmount, trancheAmountsSum ); } diff --git a/src/core/libraries/NFTSVG.sol b/src/core/libraries/NFTSVG.sol index 0cfa05c0f..ad2b736dc 100644 --- a/src/core/libraries/NFTSVG.sol +++ b/src/core/libraries/NFTSVG.sol @@ -17,10 +17,10 @@ library NFTSVG { string assetAddress; string assetSymbol; string duration; + string lockupAddress; + string lockupModel; string progress; uint256 progressNumerical; - string sablierAddress; - string sablierModel; string status; } @@ -89,7 +89,7 @@ library NFTSVG { '', SVGElements.BACKGROUND, generateDefs(params.accentColor, params.status, vars.cards), - generateFloatingText(params.sablierAddress, params.sablierModel, params.assetAddress, params.assetSymbol), + generateFloatingText(params.lockupAddress, params.lockupModel, params.assetAddress, params.assetSymbol), generateHrefs(vars.progressXPosition, vars.statusXPosition, vars.amountXPosition, vars.durationXPosition), "" ); @@ -118,8 +118,8 @@ library NFTSVG { } function generateFloatingText( - string memory sablierAddress, - string memory sablierModel, + string memory lockupAddress, + string memory lockupModel, string memory assetAddress, string memory assetSymbol ) @@ -131,11 +131,11 @@ library NFTSVG { '', SVGElements.floatingText({ offset: "-100%", - text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", sablierModel) + text: string.concat(lockupAddress, unicode" • ", "Sablier ", lockupModel) }), SVGElements.floatingText({ offset: "0%", - text: string.concat(sablierAddress, unicode" • ", "Sablier V2 ", sablierModel) + text: string.concat(lockupAddress, unicode" • ", "Sablier ", lockupModel) }), SVGElements.floatingText({ offset: "-50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }), SVGElements.floatingText({ offset: "50%", text: string.concat(assetAddress, unicode" • ", assetSymbol) }), diff --git a/src/core/types/DataTypes.sol b/src/core/types/DataTypes.sol index d43c94030..f665bb17b 100644 --- a/src/core/types/DataTypes.sol +++ b/src/core/types/DataTypes.sol @@ -7,7 +7,7 @@ import { UD60x18 } from "@prb/math/src/UD60x18.sol"; // DataTypes.sol // -// This file defines all structs used in V2 Core, most of which are organized under three namespaces: +// This file defines all structs used in Lockup, most of which are organized under three namespaces: // // - Lockup // - LockupDynamic @@ -26,7 +26,7 @@ struct Broker { UD60x18 fee; } -/// @notice Namespace for the structs used in both {SablierV2LockupLinear} and {SablierV2LockupDynamic}. +/// @notice Namespace for the structs used in both {SablierLockupLinear} and {SablierLockupDynamic}. library Lockup { /// @notice Struct encapsulating the deposit, withdrawn, and refunded amounts, both denoted in units of the asset's /// decimals. @@ -71,7 +71,7 @@ library Lockup { DEPLETED } - /// @notice A common data structure to be stored in all {SablierV2Lockup} models. + /// @notice A common data structure to be stored in all {SablierLockup} models. /// @dev The fields are arranged like this to save gas via tight variable packing. /// @param sender The address distributing the assets, with the ability to cancel the stream. /// @param startTime The Unix timestamp indicating the stream's start. @@ -101,9 +101,9 @@ library Lockup { } } -/// @notice Namespace for the structs used in {SablierV2LockupDynamic}. +/// @notice Namespace for the structs used in {SablierLockupDynamic}. library LockupDynamic { - /// @notice Struct encapsulating the parameters of the {SablierV2LockupDynamic.createWithDurations} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupDynamic.createWithDurations} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -127,7 +127,7 @@ library LockupDynamic { Broker broker; } - /// @notice Struct encapsulating the parameters of the {SablierV2LockupDynamic.createWithTimestamps} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupDynamic.createWithTimestamps} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -163,7 +163,7 @@ library LockupDynamic { uint40 timestamp; } - /// @notice Segment struct used at runtime in {SablierV2LockupDynamic.createWithDurations}. + /// @notice Segment struct used at runtime in {SablierLockupDynamic.createWithDurations}. /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. /// @param exponent The exponent of the segment, denoted as a fixed-point number. /// @param duration The time difference in seconds between the segment and the previous one. @@ -199,9 +199,9 @@ library LockupDynamic { } } -/// @notice Namespace for the structs used in {SablierV2LockupLinear}. +/// @notice Namespace for the structs used in {SablierLockupLinear}. library LockupLinear { - /// @notice Struct encapsulating the parameters of the {SablierV2LockupLinear.createWithDurations} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupLinear.createWithDurations} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -224,7 +224,7 @@ library LockupLinear { Broker broker; } - /// @notice Struct encapsulating the parameters of the {SablierV2LockupLinear.createWithTimestamps} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupLinear.createWithTimestamps} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -284,9 +284,9 @@ library LockupLinear { } } -/// @notice Namespace for the structs used in {SablierV2LockupTranched}. +/// @notice Namespace for the structs used in {SablierLockupTranched}. library LockupTranched { - /// @notice Struct encapsulating the parameters of the {SablierV2LockupTranched.createWithDurations} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupTranched.createWithDurations} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -310,7 +310,7 @@ library LockupTranched { Broker broker; } - /// @notice Struct encapsulating the parameters of the {SablierV2LockupTranched.createWithTimestamps} function. + /// @notice Struct encapsulating the parameters of the {SablierLockupTranched.createWithTimestamps} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. /// @param recipient The address receiving the assets. @@ -369,7 +369,7 @@ library LockupTranched { uint40 timestamp; } - /// @notice Tranche struct used at runtime in {SablierV2LockupTranched.createWithDurations}. + /// @notice Tranche struct used at runtime in {SablierLockupTranched.createWithDurations}. /// @param amount The amount of assets to be unlocked in the tranche, denoted in units of the asset's decimals. /// @param duration The time difference in seconds between the tranche and the previous one. struct TrancheWithDuration { diff --git a/src/periphery/SablierV2BatchLockup.sol b/src/periphery/SablierBatchLockup.sol similarity index 79% rename from src/periphery/SablierV2BatchLockup.sol rename to src/periphery/SablierBatchLockup.sol index fb2b8b3b7..73fe519f5 100644 --- a/src/periphery/SablierV2BatchLockup.sol +++ b/src/periphery/SablierBatchLockup.sol @@ -4,27 +4,27 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; -import { ISablierV2LockupDynamic } from "../core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupDynamic } from "../core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; import { LockupDynamic, LockupLinear, LockupTranched } from "../core/types/DataTypes.sol"; -import { ISablierV2BatchLockup } from "./interfaces/ISablierV2BatchLockup.sol"; +import { ISablierBatchLockup } from "./interfaces/ISablierBatchLockup.sol"; import { Errors } from "./libraries/Errors.sol"; import { BatchLockup } from "./types/DataTypes.sol"; -/// @title SablierV2BatchLockup -/// @notice See the documentation in {ISablierV2BatchLockup}. -contract SablierV2BatchLockup is ISablierV2BatchLockup { +/// @title SablierBatchLockup +/// @notice See the documentation in {ISablierBatchLockup}. +contract SablierBatchLockup is ISablierBatchLockup { using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-DYNAMIC + SABLIER-LOCKUP-DYNAMIC //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithDurationsLD( - ISablierV2LockupDynamic lockupDynamic, + ISablierLockupDynamic lockupDynamic, IERC20 asset, BatchLockup.CreateWithDurationsLD[] calldata batch ) @@ -35,7 +35,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch size is not zero. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -48,7 +48,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupDynamic} to spend the amount of assets. _handleTransfer(address(lockupDynamic), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -70,9 +70,9 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithTimestampsLD( - ISablierV2LockupDynamic lockupDynamic, + ISablierLockupDynamic lockupDynamic, IERC20 asset, BatchLockup.CreateWithTimestampsLD[] calldata batch ) @@ -83,7 +83,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch size is not zero. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -96,7 +96,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupDynamic} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupDynamic} to spend the amount of assets. _handleTransfer(address(lockupDynamic), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -120,12 +120,12 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-LINEAR + SABLIER-LOCKUP-LINEAR //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithDurationsLL( - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, IERC20 asset, BatchLockup.CreateWithDurationsLL[] calldata batch ) @@ -136,7 +136,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch size is not zero. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -149,7 +149,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupLinear} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupLinear} to spend the amount of assets. _handleTransfer(address(lockupLinear), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -171,9 +171,9 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithTimestampsLL( - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, IERC20 asset, BatchLockup.CreateWithTimestampsLL[] calldata batch ) @@ -184,7 +184,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch is not empty. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -197,7 +197,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupLinear} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupLinear} to spend the amount of assets. _handleTransfer(address(lockupLinear), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -220,12 +220,12 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHED + SABLIER-LOCKUP-TRANCHED //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithDurationsLT( - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, IERC20 asset, BatchLockup.CreateWithDurationsLT[] calldata batch ) @@ -236,7 +236,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch size is not zero. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -249,7 +249,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupTranched} to spend the amount of assets. _handleTransfer(address(lockupTranched), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -271,9 +271,9 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - /// @inheritdoc ISablierV2BatchLockup + /// @inheritdoc ISablierBatchLockup function createWithTimestampsLT( - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, IERC20 asset, BatchLockup.CreateWithTimestampsLT[] calldata batch ) @@ -284,7 +284,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { // Check that the batch size is not zero. uint256 batchSize = batch.length; if (batchSize == 0) { - revert Errors.SablierV2BatchLockup_BatchSizeZero(); + revert Errors.SablierBatchLockup_BatchSizeZero(); } // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create @@ -297,7 +297,7 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { } } - // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + // Perform the ERC-20 transfer and approve {SablierLockupTranched} to spend the amount of assets. _handleTransfer(address(lockupTranched), asset, transferAmount); // Create a stream for each element in the parameter array. @@ -324,24 +324,24 @@ contract SablierV2BatchLockup is ISablierV2BatchLockup { HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Helper function to approve a Sablier contract to spend funds from the batchLockup. If the current allowance - /// is insufficient, this function approves Sablier to spend the exact `amount`. + /// @dev Helper function to approve a Lockup contract to spend funds from the batchLockup. If the current allowance + /// is insufficient, this function approves Lockup to spend the exact `amount`. /// The {SafeERC20.forceApprove} function is used to handle special ERC-20 assets (e.g. USDT) that require the /// current allowance to be zero before setting it to a non-zero value. - function _approve(address sablierContract, IERC20 asset, uint256 amount) internal { - uint256 allowance = asset.allowance({ owner: address(this), spender: sablierContract }); + function _approve(address lockupContract, IERC20 asset, uint256 amount) internal { + uint256 allowance = asset.allowance({ owner: address(this), spender: lockupContract }); if (allowance < amount) { - asset.forceApprove({ spender: sablierContract, value: amount }); + asset.forceApprove({ spender: lockupContract, value: amount }); } } - /// @dev Helper function to transfer assets from the caller to the batchLockup contract and approve the Sablier + /// @dev Helper function to transfer assets from the caller to the batchLockup contract and approve the Lockup /// contract. - function _handleTransfer(address sablierContract, IERC20 asset, uint256 amount) internal { + function _handleTransfer(address lockupContract, IERC20 asset, uint256 amount) internal { // Transfer the assets to the batchLockup contract. asset.safeTransferFrom({ from: msg.sender, to: address(this), value: amount }); - // Approve the Sablier contract to spend funds. - _approve(sablierContract, asset, amount); + // Approve the Lockup contract to spend funds. + _approve(lockupContract, asset, amount); } } diff --git a/src/periphery/SablierV2MerkleLL.sol b/src/periphery/SablierMerkleLL.sol similarity index 74% rename from src/periphery/SablierV2MerkleLL.sol rename to src/periphery/SablierMerkleLL.sol index 731b3869a..85587d3f6 100644 --- a/src/periphery/SablierV2MerkleLL.sol +++ b/src/periphery/SablierMerkleLL.sol @@ -6,18 +6,18 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.sol"; import { Broker, LockupLinear } from "../core/types/DataTypes.sol"; -import { SablierV2MerkleLockup } from "./abstracts/SablierV2MerkleLockup.sol"; -import { ISablierV2MerkleLL } from "./interfaces/ISablierV2MerkleLL.sol"; +import { SablierMerkleLockup } from "./abstracts/SablierMerkleLockup.sol"; +import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; import { MerkleLockup } from "./types/DataTypes.sol"; -/// @title SablierV2MerkleLL -/// @notice See the documentation in {ISablierV2MerkleLL}. -contract SablierV2MerkleLL is - ISablierV2MerkleLL, // 2 inherited components - SablierV2MerkleLockup // 4 inherited components +/// @title SablierMerkleLL +/// @notice See the documentation in {ISablierMerkleLL}. +contract SablierMerkleLL is + ISablierMerkleLL, // 2 inherited components + SablierMerkleLockup // 4 inherited components { using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; @@ -26,29 +26,29 @@ contract SablierV2MerkleLL is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLL - ISablierV2LockupLinear public immutable override LOCKUP_LINEAR; + /// @inheritdoc ISablierMerkleLL + ISablierLockupLinear public immutable override LOCKUP_LINEAR; - /// @inheritdoc ISablierV2MerkleLL + /// @inheritdoc ISablierMerkleLL LockupLinear.Durations public override streamDurations; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier + /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Lockup /// contract. constructor( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, LockupLinear.Durations memory streamDurations_ ) - SablierV2MerkleLockup(baseParams) + SablierMerkleLockup(baseParams) { LOCKUP_LINEAR = lockupLinear; streamDurations = streamDurations_; - // Max approve the Sablier contract to spend funds from the MerkleLockup contract. + // Max approve the Lockup contract to spend funds from the MerkleLockup contract. ASSET.forceApprove(address(LOCKUP_LINEAR), type(uint256).max); } @@ -56,7 +56,7 @@ contract SablierV2MerkleLL is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLL + /// @inheritdoc ISablierMerkleLL function claim( uint256 index, address recipient, @@ -77,7 +77,7 @@ contract SablierV2MerkleLL is // Effect: mark the index as claimed. _claimedBitMap.set(index); - // Interaction: create the stream via {SablierV2LockupLinear}. + // Interaction: create the stream via {SablierLockupLinear}. streamId = LOCKUP_LINEAR.createWithDurations( LockupLinear.CreateWithDurations({ sender: admin, diff --git a/src/periphery/SablierV2MerkleLT.sol b/src/periphery/SablierMerkleLT.sol similarity index 85% rename from src/periphery/SablierV2MerkleLT.sol rename to src/periphery/SablierMerkleLT.sol index ad9414de6..0b0ecdedd 100644 --- a/src/periphery/SablierV2MerkleLT.sol +++ b/src/periphery/SablierMerkleLT.sol @@ -7,19 +7,19 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { uUNIT } from "@prb/math/src/UD2x18.sol"; import { UD60x18, ud60x18, ZERO } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; import { Broker, LockupTranched } from "../core/types/DataTypes.sol"; -import { SablierV2MerkleLockup } from "./abstracts/SablierV2MerkleLockup.sol"; -import { ISablierV2MerkleLT } from "./interfaces/ISablierV2MerkleLT.sol"; +import { SablierMerkleLockup } from "./abstracts/SablierMerkleLockup.sol"; +import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; import { Errors } from "./libraries/Errors.sol"; import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; -/// @title SablierV2MerkleLT -/// @notice See the documentation in {ISablierV2MerkleLT}. -contract SablierV2MerkleLT is - ISablierV2MerkleLT, // 2 inherited components - SablierV2MerkleLockup // 4 inherited components +/// @title SablierMerkleLT +/// @notice See the documentation in {ISablierMerkleLT}. +contract SablierMerkleLT is + ISablierMerkleLT, // 2 inherited components + SablierMerkleLockup // 4 inherited components { using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; @@ -28,10 +28,10 @@ contract SablierV2MerkleLT is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLT - ISablierV2LockupTranched public immutable override LOCKUP_TRANCHED; + /// @inheritdoc ISablierMerkleLT + ISablierLockupTranched public immutable override LOCKUP_TRANCHED; - /// @inheritdoc ISablierV2MerkleLT + /// @inheritdoc ISablierMerkleLT uint64 public immutable override TOTAL_PERCENTAGE; /// @dev The tranches with their respective unlock percentages and durations. @@ -41,14 +41,14 @@ contract SablierV2MerkleLT is CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Sablier + /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Lockup /// contract. constructor( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages ) - SablierV2MerkleLockup(baseParams) + SablierMerkleLockup(baseParams) { LOCKUP_TRANCHED = lockupTranched; @@ -63,7 +63,7 @@ contract SablierV2MerkleLT is } TOTAL_PERCENTAGE = totalPercentage; - // Max approve the Sablier contract to spend funds from the MerkleLockup contract. + // Max approve the Lockup contract to spend funds from the MerkleLockup contract. ASSET.forceApprove(address(LOCKUP_TRANCHED), type(uint256).max); } @@ -71,7 +71,7 @@ contract SablierV2MerkleLT is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLT + /// @inheritdoc ISablierMerkleLT function getTranchesWithPercentages() external view override returns (MerkleLT.TrancheWithPercentage[] memory) { return _tranchesWithPercentages; } @@ -80,7 +80,7 @@ contract SablierV2MerkleLT is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLT + /// @inheritdoc ISablierMerkleLT function claim( uint256 index, address recipient, @@ -93,7 +93,7 @@ contract SablierV2MerkleLT is { // Check: the sum of percentages equals 100%. if (TOTAL_PERCENTAGE != uUNIT) { - revert Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred(TOTAL_PERCENTAGE); + revert Errors.SablierMerkleLT_TotalPercentageNotOneHundred(TOTAL_PERCENTAGE); } // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second @@ -109,7 +109,7 @@ contract SablierV2MerkleLT is // Effect: mark the index as claimed. _claimedBitMap.set(index); - // Interaction: create the stream via {SablierV2LockupTranched}. + // Interaction: create the stream via {SablierLockupTranched}. streamId = LOCKUP_TRANCHED.createWithDurations( LockupTranched.CreateWithDurations({ sender: admin, diff --git a/src/periphery/SablierV2MerkleLockupFactory.sol b/src/periphery/SablierMerkleLockupFactory.sol similarity index 75% rename from src/periphery/SablierV2MerkleLockupFactory.sol rename to src/periphery/SablierMerkleLockupFactory.sol index a4aede999..196ed64c3 100644 --- a/src/periphery/SablierV2MerkleLockupFactory.sol +++ b/src/periphery/SablierMerkleLockupFactory.sol @@ -3,25 +3,25 @@ pragma solidity >=0.8.22; import { uUNIT } from "@prb/math/src/UD2x18.sol"; -import { ISablierV2LockupLinear } from "../core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; import { LockupLinear } from "../core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "./interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLockupFactory } from "./interfaces/ISablierV2MerkleLockupFactory.sol"; -import { ISablierV2MerkleLT } from "./interfaces/ISablierV2MerkleLT.sol"; -import { SablierV2MerkleLL } from "./SablierV2MerkleLL.sol"; -import { SablierV2MerkleLT } from "./SablierV2MerkleLT.sol"; +import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; +import { ISablierMerkleLockupFactory } from "./interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; +import { SablierMerkleLL } from "./SablierMerkleLL.sol"; +import { SablierMerkleLT } from "./SablierMerkleLT.sol"; import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; -/// @title SablierV2MerkleLockupFactory -/// @notice See the documentation in {ISablierV2MerkleLockupFactory}. -contract SablierV2MerkleLockupFactory is ISablierV2MerkleLockupFactory { +/// @title SablierMerkleLockupFactory +/// @notice See the documentation in {ISablierMerkleLockupFactory}. +contract SablierMerkleLockupFactory is ISablierMerkleLockupFactory { /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLockupFactory + /// @inheritdoc ISablierMerkleLockupFactory function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) external pure @@ -39,16 +39,16 @@ contract SablierV2MerkleLockupFactory is ISablierV2MerkleLockupFactory { USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice inheritdoc ISablierV2MerkleLockupFactory + /// @notice inheritdoc ISablierMerkleLockupFactory function createMerkleLL( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, LockupLinear.Durations memory streamDurations, uint256 aggregateAmount, uint256 recipientCount ) external - returns (ISablierV2MerkleLL merkleLL) + returns (ISablierMerkleLL merkleLL) { // Hash the parameters to generate a salt. bytes32 salt = keccak256( @@ -68,22 +68,22 @@ contract SablierV2MerkleLockupFactory is ISablierV2MerkleLockupFactory { ); // Deploy the MerkleLockup contract with CREATE2. - merkleLL = new SablierV2MerkleLL{ salt: salt }(baseParams, lockupLinear, streamDurations); + merkleLL = new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, streamDurations); // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. emit CreateMerkleLL(merkleLL, baseParams, lockupLinear, streamDurations, aggregateAmount, recipientCount); } - /// @notice inheritdoc ISablierV2MerkleLockupFactory + /// @notice inheritdoc ISablierMerkleLockupFactory function createMerkleLT( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, uint256 aggregateAmount, uint256 recipientCount ) external - returns (ISablierV2MerkleLT merkleLT) + returns (ISablierMerkleLT merkleLT) { uint256 totalDuration; @@ -117,7 +117,7 @@ contract SablierV2MerkleLockupFactory is ISablierV2MerkleLockupFactory { ); // Deploy the MerkleLockup contract with CREATE2. - merkleLT = new SablierV2MerkleLT{ salt: salt }(baseParams, lockupTranched, tranchesWithPercentages); + merkleLT = new SablierMerkleLT{ salt: salt }(baseParams, lockupTranched, tranchesWithPercentages); // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. emit CreateMerkleLT( diff --git a/src/periphery/abstracts/SablierV2MerkleLockup.sol b/src/periphery/abstracts/SablierMerkleLockup.sol similarity index 81% rename from src/periphery/abstracts/SablierV2MerkleLockup.sol rename to src/periphery/abstracts/SablierMerkleLockup.sol index 17f84485a..788b7944d 100644 --- a/src/periphery/abstracts/SablierV2MerkleLockup.sol +++ b/src/periphery/abstracts/SablierMerkleLockup.sol @@ -8,14 +8,14 @@ import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { Adminable } from "../../core/abstracts/Adminable.sol"; -import { ISablierV2MerkleLockup } from "../interfaces/ISablierV2MerkleLockup.sol"; +import { ISablierMerkleLockup } from "../interfaces/ISablierMerkleLockup.sol"; import { MerkleLockup } from "../types/DataTypes.sol"; import { Errors } from "../libraries/Errors.sol"; -/// @title SablierV2MerkleLockup -/// @notice See the documentation in {ISablierV2MerkleLockup}. -abstract contract SablierV2MerkleLockup is - ISablierV2MerkleLockup, // 2 inherited component +/// @title SablierMerkleLockup +/// @notice See the documentation in {ISablierMerkleLockup}. +abstract contract SablierMerkleLockup is + ISablierMerkleLockup, // 2 inherited component Adminable // 1 inherited component { using BitMaps for BitMaps.BitMap; @@ -25,25 +25,25 @@ abstract contract SablierV2MerkleLockup is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup IERC20 public immutable override ASSET; - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup bool public immutable override CANCELABLE; - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup uint40 public immutable override EXPIRATION; - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup bytes32 public immutable override MERKLE_ROOT; /// @dev The name of the campaign stored as bytes32. bytes32 internal immutable NAME; - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup bool public immutable override TRANSFERABLE; - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup string public ipfsCID; /// @dev Packed booleans that record the history of claims. @@ -60,7 +60,7 @@ abstract contract SablierV2MerkleLockup is constructor(MerkleLockup.ConstructorParams memory params) { // Check: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) { - revert Errors.SablierV2MerkleLockup_CampaignNameTooLong({ + revert Errors.SablierMerkleLockup_CampaignNameTooLong({ nameLength: bytes(params.name).length, maxLength: 32 }); @@ -80,22 +80,22 @@ abstract contract SablierV2MerkleLockup is USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup function getFirstClaimTime() external view override returns (uint40) { return _firstClaimTime; } - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup function hasClaimed(uint256 index) public view override returns (bool) { return _claimedBitMap.get(index); } - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup function hasExpired() public view override returns (bool) { return EXPIRATION > 0 && EXPIRATION <= block.timestamp; } - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup function name() external view override returns (string memory) { return string(abi.encodePacked(NAME)); } @@ -104,11 +104,11 @@ abstract contract SablierV2MerkleLockup is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierV2MerkleLockup + /// @inheritdoc ISablierMerkleLockup function clawback(address to, uint128 amount) external override onlyAdmin { // Check: current timestamp is over the grace period and the campaign has not expired. if (_hasGracePeriodPassed() && !hasExpired()) { - revert Errors.SablierV2MerkleLockup_ClawbackNotAllowed({ + revert Errors.SablierMerkleLockup_ClawbackNotAllowed({ blockTimestamp: block.timestamp, expiration: EXPIRATION, firstClaimTime: _firstClaimTime @@ -140,20 +140,17 @@ abstract contract SablierV2MerkleLockup is function _checkClaim(uint256 index, bytes32 leaf, bytes32[] calldata merkleProof) internal { // Check: the campaign has not expired. if (hasExpired()) { - revert Errors.SablierV2MerkleLockup_CampaignExpired({ - blockTimestamp: block.timestamp, - expiration: EXPIRATION - }); + revert Errors.SablierMerkleLockup_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); } // Check: the index has not been claimed. if (_claimedBitMap.get(index)) { - revert Errors.SablierV2MerkleLockup_StreamClaimed(index); + revert Errors.SablierMerkleLockup_StreamClaimed(index); } // Check: the input claim is included in the Merkle tree. if (!MerkleProof.verify(merkleProof, MERKLE_ROOT, leaf)) { - revert Errors.SablierV2MerkleLockup_InvalidProof(); + revert Errors.SablierMerkleLockup_InvalidProof(); } // Effect: set the `_firstClaimTime` if its zero. diff --git a/src/periphery/interfaces/ISablierV2BatchLockup.sol b/src/periphery/interfaces/ISablierBatchLockup.sol similarity index 66% rename from src/periphery/interfaces/ISablierV2BatchLockup.sol rename to src/periphery/interfaces/ISablierBatchLockup.sol index 4e0991113..3ef10202e 100644 --- a/src/periphery/interfaces/ISablierV2BatchLockup.sol +++ b/src/periphery/interfaces/ISablierBatchLockup.sol @@ -3,116 +3,116 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "../../core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupDynamic } from "../../core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; import { BatchLockup } from "../types/DataTypes.sol"; -/// @title ISablierV2BatchLockup -/// @notice Helper to batch create Sablier V2 Lockup streams. -interface ISablierV2BatchLockup { +/// @title ISablierBatchLockup +/// @notice Helper to batch create Lockup streams. +interface ISablierBatchLockup { /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-LINEAR + SABLIER-LOCKUP-DYNAMIC //////////////////////////////////////////////////////////////////////////*/ - /// @notice Creates a batch of LockupLinear streams using `createWithDurations`. + /// @notice Creates a batch of Lockup Dynamic streams using `createWithDurations`. /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupLinear.createWithDurations} must be met for each stream. + /// - All requirements from {ISablierLockupDynamic.createWithDurations} must be met for each stream. /// - /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param lockupDynamic The address of the {SablierLockupDynamic} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupLinear.createWithDurations}. + /// {SablierLockupDynamic.createWithDurations}. /// @return streamIds The ids of the newly created streams. - function createWithDurationsLL( - ISablierV2LockupLinear lockupLinear, + function createWithDurationsLD( + ISablierLockupDynamic lockupDynamic, IERC20 asset, - BatchLockup.CreateWithDurationsLL[] calldata batch + BatchLockup.CreateWithDurationsLD[] calldata batch ) external returns (uint256[] memory streamIds); - /// @notice Creates a batch of LockupLinear streams using `createWithTimestamps`. + /// @notice Creates a batch of Lockup Dynamic streams using `createWithTimestamps`. /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupLinear.createWithTimestamps} must be met for each stream. + /// - All requirements from {ISablierLockupDynamic.createWithTimestamps} must be met for each stream. /// - /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param lockupDynamic The address of the {SablierLockupDynamic} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupLinear.createWithTimestamps}. + /// {SablierLockupDynamic.createWithTimestamps}. /// @return streamIds The ids of the newly created streams. - function createWithTimestampsLL( - ISablierV2LockupLinear lockupLinear, + function createWithTimestampsLD( + ISablierLockupDynamic lockupDynamic, IERC20 asset, - BatchLockup.CreateWithTimestampsLL[] calldata batch + BatchLockup.CreateWithTimestampsLD[] calldata batch ) external returns (uint256[] memory streamIds); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-DYNAMIC + SABLIER-LOCKUP-LINEAR //////////////////////////////////////////////////////////////////////////*/ - /// @notice Creates a batch of Lockup Dynamic streams using `createWithDurations`. + /// @notice Creates a batch of LockupLinear streams using `createWithDurations`. /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupDynamic.createWithDurations} must be met for each stream. + /// - All requirements from {ISablierLockupLinear.createWithDurations} must be met for each stream. /// - /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract. + /// @param lockupLinear The address of the {SablierLockupLinear} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupDynamic.createWithDurations}. + /// {SablierLockupLinear.createWithDurations}. /// @return streamIds The ids of the newly created streams. - function createWithDurationsLD( - ISablierV2LockupDynamic lockupDynamic, + function createWithDurationsLL( + ISablierLockupLinear lockupLinear, IERC20 asset, - BatchLockup.CreateWithDurationsLD[] calldata batch + BatchLockup.CreateWithDurationsLL[] calldata batch ) external returns (uint256[] memory streamIds); - /// @notice Creates a batch of Lockup Dynamic streams using `createWithTimestamps`. + /// @notice Creates a batch of LockupLinear streams using `createWithTimestamps`. /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupDynamic.createWithTimestamps} must be met for each stream. + /// - All requirements from {ISablierLockupLinear.createWithTimestamps} must be met for each stream. /// - /// @param lockupDynamic The address of the {SablierV2LockupDynamic} contract. + /// @param lockupLinear The address of the {SablierLockupLinear} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupDynamic.createWithTimestamps}. + /// {SablierLockupLinear.createWithTimestamps}. /// @return streamIds The ids of the newly created streams. - function createWithTimestampsLD( - ISablierV2LockupDynamic lockupDynamic, + function createWithTimestampsLL( + ISablierLockupLinear lockupLinear, IERC20 asset, - BatchLockup.CreateWithTimestampsLD[] calldata batch + BatchLockup.CreateWithTimestampsLL[] calldata batch ) external returns (uint256[] memory streamIds); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP-TRANCHED + SABLIER-LOCKUP-TRANCHED //////////////////////////////////////////////////////////////////////////*/ /// @notice Creates a batch of LockupTranched streams using `createWithDurations`. /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupTranched.createWithDurations} must be met for each stream. + /// - All requirements from {ISablierLockupTranched.createWithDurations} must be met for each stream. /// - /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param lockupTranched The address of the {SablierLockupTranched} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupTranched.createWithDurations}. + /// {SablierLockupTranched.createWithDurations}. /// @return streamIds The ids of the newly created streams. function createWithDurationsLT( - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, IERC20 asset, BatchLockup.CreateWithDurationsLT[] calldata batch ) @@ -123,15 +123,15 @@ interface ISablierV2BatchLockup { /// /// @dev Requirements: /// - There must be at least one element in `batch`. - /// - All requirements from {ISablierV2LockupTranched.createWithTimestamps} must be met for each stream. + /// - All requirements from {ISablierLockupTranched.createWithTimestamps} must be met for each stream. /// - /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param lockupTranched The address of the {SablierLockupTranched} contract. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param batch An array of structs, each encapsulating a subset of the parameters of - /// {SablierV2LockupTranched.createWithTimestamps}. + /// {SablierLockupTranched.createWithTimestamps}. /// @return streamIds The ids of the newly created streams. function createWithTimestampsLT( - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, IERC20 asset, BatchLockup.CreateWithTimestampsLT[] calldata batch ) diff --git a/src/periphery/interfaces/ISablierV2MerkleLL.sol b/src/periphery/interfaces/ISablierMerkleLL.sol similarity index 80% rename from src/periphery/interfaces/ISablierV2MerkleLL.sol rename to src/periphery/interfaces/ISablierMerkleLL.sol index 89bba74a3..61ef0597a 100644 --- a/src/periphery/interfaces/ISablierV2MerkleLL.sol +++ b/src/periphery/interfaces/ISablierMerkleLL.sol @@ -1,19 +1,19 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear.sol"; -import { ISablierV2MerkleLockup } from "./ISablierV2MerkleLockup.sol"; +import { ISablierMerkleLockup } from "./ISablierMerkleLockup.sol"; -/// @title ISablierV2MerkleLL +/// @title ISablierMerkleLL /// @notice MerkleLockup campaign that creates LockupLinear streams. -interface ISablierV2MerkleLL is ISablierV2MerkleLockup { +interface ISablierMerkleLL is ISablierMerkleLockup { /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice The address of the {SablierV2LockupLinear} contract. - function LOCKUP_LINEAR() external view returns (ISablierV2LockupLinear); + /// @notice The address of the {SablierLockupLinear} contract. + function LOCKUP_LINEAR() external view returns (ISablierLockupLinear); /// @notice The total streaming duration of each stream. function streamDurations() external view returns (uint40 cliff, uint40 duration); diff --git a/src/periphery/interfaces/ISablierV2MerkleLT.sol b/src/periphery/interfaces/ISablierMerkleLT.sol similarity index 82% rename from src/periphery/interfaces/ISablierV2MerkleLT.sol rename to src/periphery/interfaces/ISablierMerkleLT.sol index aad3f0602..136985752 100644 --- a/src/periphery/interfaces/ISablierV2MerkleLT.sol +++ b/src/periphery/interfaces/ISablierMerkleLT.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; -import { ISablierV2MerkleLockup } from "./ISablierV2MerkleLockup.sol"; +import { ISablierMerkleLockup } from "./ISablierMerkleLockup.sol"; import { MerkleLT } from "../types/DataTypes.sol"; -/// @title ISablierV2MerkleLT +/// @title ISablierMerkleLT /// @notice MerkleLockup campaign that creates LockupTranched streams. -interface ISablierV2MerkleLT is ISablierV2MerkleLockup { +interface ISablierMerkleLT is ISablierMerkleLockup { /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ @@ -16,8 +16,8 @@ interface ISablierV2MerkleLT is ISablierV2MerkleLockup { /// @notice Retrieves the tranches with their respective unlock percentages and durations. function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); - /// @notice The address of the {SablierV2LockupTranched} contract. - function LOCKUP_TRANCHED() external view returns (ISablierV2LockupTranched); + /// @notice The address of the {SablierLockupTranched} contract. + function LOCKUP_TRANCHED() external view returns (ISablierLockupTranched); /// @notice The total percentage of the tranches. function TOTAL_PERCENTAGE() external view returns (uint64); diff --git a/src/periphery/interfaces/ISablierV2MerkleLockup.sol b/src/periphery/interfaces/ISablierMerkleLockup.sol similarity index 94% rename from src/periphery/interfaces/ISablierV2MerkleLockup.sol rename to src/periphery/interfaces/ISablierMerkleLockup.sol index 47e3f3c00..750ca3655 100644 --- a/src/periphery/interfaces/ISablierV2MerkleLockup.sol +++ b/src/periphery/interfaces/ISablierMerkleLockup.sol @@ -5,12 +5,12 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IAdminable } from "../../core/interfaces/IAdminable.sol"; -/// @title ISablierV2MerkleLockup -/// @notice A contract that lets user claim Sablier streams using Merkle proofs. A popular use case for MerkleLockup +/// @title ISablierMerkleLockup +/// @notice A contract that lets user claim Lockup streams using Merkle proofs. A popular use case for MerkleLockup /// is airstreams: a portmanteau of "airdrop" and "stream". This is an airdrop model where the tokens are distributed /// over time, as opposed to all at once. /// @dev This is the base interface for MerkleLockup. See the Sablier docs for more guidance: https://docs.sablier.com -interface ISablierV2MerkleLockup is IAdminable { +interface ISablierMerkleLockup is IAdminable { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol b/src/periphery/interfaces/ISablierMerkleLockupFactory.sol similarity index 72% rename from src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol rename to src/periphery/interfaces/ISablierMerkleLockupFactory.sol index 0aa0b83df..eb8b71e03 100644 --- a/src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleLockupFactory.sol @@ -1,36 +1,36 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { ISablierV2LockupLinear } from "../../core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; import { LockupLinear } from "../../core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "./ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "./ISablierV2MerkleLT.sol"; +import { ISablierMerkleLL } from "./ISablierMerkleLL.sol"; +import { ISablierMerkleLT } from "./ISablierMerkleLT.sol"; import { MerkleLockup, MerkleLT } from "../types/DataTypes.sol"; -/// @title ISablierV2MerkleLockupFactory +/// @title ISablierMerkleLockupFactory /// @notice Deploys MerkleLockup campaigns with CREATE2. -interface ISablierV2MerkleLockupFactory { +interface ISablierMerkleLockupFactory { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Emitted when a {SablierV2MerkleLL} campaign is created. + /// @notice Emitted when a {SablierMerkleLL} campaign is created. event CreateMerkleLL( - ISablierV2MerkleLL indexed merkleLL, + ISablierMerkleLL indexed merkleLL, MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, LockupLinear.Durations streamDurations, uint256 aggregateAmount, uint256 recipientCount ); - /// @notice Emitted when a {SablierV2MerkleLT} campaign is created. + /// @notice Emitted when a {SablierMerkleLT} campaign is created. event CreateMerkleLT( - ISablierV2MerkleLT indexed merkleLT, + ISablierMerkleLT indexed merkleLT, MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, @@ -56,40 +56,40 @@ interface ISablierV2MerkleLockupFactory { /// @notice Creates a new MerkleLockup campaign with a LockupLinear distribution. /// @dev Emits a {CreateMerkleLL} event. - /// @param baseParams Struct encapsulating the {SablierV2MerkleLockup} parameters, which are documented in + /// @param baseParams Struct encapsulating the {SablierMerkleLockup} parameters, which are documented in /// {DataTypes}. - /// @param lockupLinear The address of the {SablierV2LockupLinear} contract. + /// @param lockupLinear The address of the {SablierLockupLinear} contract. /// @param streamDurations The durations for each stream. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. /// @param recipientCount The total number of recipients who are eligible to claim. /// @return merkleLL The address of the newly created MerkleLockup contract. function createMerkleLL( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, LockupLinear.Durations memory streamDurations, uint256 aggregateAmount, uint256 recipientCount ) external - returns (ISablierV2MerkleLL merkleLL); + returns (ISablierMerkleLL merkleLL); /// @notice Creates a new MerkleLockup campaign with a LockupTranched distribution. /// @dev Emits a {CreateMerkleLT} event. /// - /// @param baseParams Struct encapsulating the {SablierV2MerkleLockup} parameters, which are documented in + /// @param baseParams Struct encapsulating the {SablierMerkleLockup} parameters, which are documented in /// {DataTypes}. - /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param lockupTranched The address of the {SablierLockupTranched} contract. /// @param tranchesWithPercentages The tranches with their respective unlock percentages. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. /// @param recipientCount The total number of recipients who are eligible to claim. /// @return merkleLT The address of the newly created MerkleLockup contract. function createMerkleLT( MerkleLockup.ConstructorParams memory baseParams, - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, uint256 aggregateAmount, uint256 recipientCount ) external - returns (ISablierV2MerkleLT merkleLT); + returns (ISablierMerkleLT merkleLT); } diff --git a/src/periphery/libraries/Errors.sol b/src/periphery/libraries/Errors.sol index ecd1b2e17..79a7d8806 100644 --- a/src/periphery/libraries/Errors.sol +++ b/src/periphery/libraries/Errors.sol @@ -5,35 +5,35 @@ pragma solidity >=0.8.22; /// @notice Library containing all custom errors the protocol may revert with. library Errors { /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-BATCH-LOCKUP + SABLIER-BATCH-LOCKUP //////////////////////////////////////////////////////////////////////////*/ - error SablierV2BatchLockup_BatchSizeZero(); + error SablierBatchLockup_BatchSizeZero(); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-MERKLE-LOCKUP + SABLIER-MERKLE-LOCKUP //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to claim after the campaign has expired. - error SablierV2MerkleLockup_CampaignExpired(uint256 blockTimestamp, uint40 expiration); + error SablierMerkleLockup_CampaignExpired(uint256 blockTimestamp, uint40 expiration); /// @notice Thrown when trying to create a campaign with a name that is too long. - error SablierV2MerkleLockup_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); + error SablierMerkleLockup_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); /// @notice Thrown when trying to clawback when the current timestamp is over the grace period and the campaign has /// not expired. - error SablierV2MerkleLockup_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); + error SablierMerkleLockup_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); /// @notice Thrown when trying to claim with an invalid Merkle proof. - error SablierV2MerkleLockup_InvalidProof(); + error SablierMerkleLockup_InvalidProof(); /// @notice Thrown when trying to claim the same stream more than once. - error SablierV2MerkleLockup_StreamClaimed(uint256 index); + error SablierMerkleLockup_StreamClaimed(uint256 index); /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-MERKLE-LT + SABLIER-MERKLE-LT //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to claim from an LT campaign with tranches' unlock percentages not adding up to 100%. - error SablierV2MerkleLT_TotalPercentageNotOneHundred(uint64 totalPercentage); + error SablierMerkleLT_TotalPercentageNotOneHundred(uint64 totalPercentage); } diff --git a/src/periphery/types/DataTypes.sol b/src/periphery/types/DataTypes.sol index bd1df1214..2b5b0a055 100644 --- a/src/periphery/types/DataTypes.sol +++ b/src/periphery/types/DataTypes.sol @@ -7,7 +7,7 @@ import { UD2x18 } from "@prb/math/src/UD2x18.sol"; import { Broker, LockupDynamic, LockupLinear, LockupTranched } from "../../core/types/DataTypes.sol"; library BatchLockup { - /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithDurations} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupDynamic.createWithDurations} except for the /// asset. struct CreateWithDurationsLD { address sender; @@ -19,7 +19,7 @@ library BatchLockup { Broker broker; } - /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithDurations} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupLinear.createWithDurations} except for the /// asset. struct CreateWithDurationsLL { address sender; @@ -31,7 +31,7 @@ library BatchLockup { Broker broker; } - /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithDurations} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupTranched.createWithDurations} except for the /// asset. struct CreateWithDurationsLT { address sender; @@ -43,7 +43,7 @@ library BatchLockup { Broker broker; } - /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithTimestamps} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupDynamic.createWithTimestamps} except for the /// asset. struct CreateWithTimestampsLD { address sender; @@ -56,7 +56,7 @@ library BatchLockup { Broker broker; } - /// @notice A struct encapsulating all parameters of {SablierV2LockupLinear.createWithTimestamps} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupLinear.createWithTimestamps} except for the /// asset. struct CreateWithTimestampsLL { address sender; @@ -68,7 +68,7 @@ library BatchLockup { Broker broker; } - /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithTimestamps} except for the + /// @notice A struct encapsulating all parameters of {SablierLockupTranched.createWithTimestamps} except for the /// asset. struct CreateWithTimestampsLT { address sender; diff --git a/test/Base.t.sol b/test/Base.t.sol index 23be527f9..44a195ffb 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -3,21 +3,21 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { SablierV2LockupDynamic } from "src/core/SablierV2LockupDynamic.sol"; -import { SablierV2LockupLinear } from "src/core/SablierV2LockupLinear.sol"; -import { SablierV2LockupTranched } from "src/core/SablierV2LockupTranched.sol"; -import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLockupFactory } from "src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; -import { ISablierV2BatchLockup } from "src/periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; -import { SablierV2BatchLockup } from "src/periphery/SablierV2BatchLockup.sol"; -import { SablierV2MerkleLockupFactory } from "src/periphery/SablierV2MerkleLockupFactory.sol"; +import { ISablierMerkleLockupFactory } from "src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; +import { SablierBatchLockup } from "src/periphery/SablierBatchLockup.sol"; +import { SablierMerkleLockupFactory } from "src/periphery/SablierMerkleLockupFactory.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; @@ -44,16 +44,16 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2BatchLockup internal batchLockup; + ISablierBatchLockup internal batchLockup; ERC20Mock internal dai; Defaults internal defaults; - ISablierV2LockupDynamic internal lockupDynamic; - ISablierV2LockupLinear internal lockupLinear; - ISablierV2LockupTranched internal lockupTranched; - ISablierV2MerkleLockupFactory internal merkleLockupFactory; - ISablierV2MerkleLL internal merkleLL; - ISablierV2MerkleLT internal merkleLT; - ISablierV2NFTDescriptor internal nftDescriptor; + ISablierLockupDynamic internal lockupDynamic; + ISablierLockupLinear internal lockupLinear; + ISablierLockupTranched internal lockupTranched; + ISablierMerkleLockupFactory internal merkleLockupFactory; + ISablierMerkleLL internal merkleLL; + ISablierMerkleLT internal merkleLT; + ILockupNFTDescriptor internal nftDescriptor; Noop internal noop; RecipientGood internal recipientGood; ERC20MissingReturn internal usdt; @@ -148,14 +148,14 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi /// for contracts deployed via `CREATE` are based on the caller-and-nonce-hash). function deployProtocolConditionally() internal { if (!isBenchmarkProfile() && !isTestOptimizedProfile()) { - batchLockup = new SablierV2BatchLockup(); - nftDescriptor = new SablierV2NFTDescriptor(); - lockupDynamic = new SablierV2LockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); - lockupLinear = new SablierV2LockupLinear(users.admin, nftDescriptor); - lockupTranched = new SablierV2LockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); - merkleLockupFactory = new SablierV2MerkleLockupFactory(); + batchLockup = new SablierBatchLockup(); + nftDescriptor = new LockupNFTDescriptor(); + lockupDynamic = new SablierLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); + lockupLinear = new SablierLockupLinear(users.admin, nftDescriptor); + lockupTranched = new SablierLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); + merkleLockupFactory = new SablierMerkleLockupFactory(); } else { - (lockupDynamic, lockupLinear, lockupTranched, nftDescriptor, batchLockup, merkleLockupFactory) = + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = deployOptimizedProtocol(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); } @@ -222,7 +222,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi CALL EXPECTS - LOCKUP //////////////////////////////////////////////////////////////////////////*/ - /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithDurations}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithDurations}, each with the specified /// `params`. function expectMultipleCallsToCreateWithDurationsLD( uint64 count, @@ -233,11 +233,11 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupDynamic), count: count, - data: abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockupDynamic.createWithDurations, (params)) }); } - /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithDurations}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupLinear.createWithDurations}, each with the specified /// `params`. function expectMultipleCallsToCreateWithDurationsLL( uint64 count, @@ -248,11 +248,11 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupLinear), count: count, - data: abi.encodeCall(ISablierV2LockupLinear.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockupLinear.createWithDurations, (params)) }); } - /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithDurations}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupTranched.createWithDurations}, each with the specified /// `params`. function expectMultipleCallsToCreateWithDurationsLT( uint64 count, @@ -263,11 +263,11 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupTranched), count: count, - data: abi.encodeCall(ISablierV2LockupTranched.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockupTranched.createWithDurations, (params)) }); } - /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithTimestamps}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithTimestamps}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLD( uint64 count, @@ -278,11 +278,11 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupDynamic), count: count, - data: abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, (params)) }); } - /// @dev Expects multiple calls to {ISablierV2LockupLinear.createWithTimestamps}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupLinear.createWithTimestamps}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLL( uint64 count, @@ -293,11 +293,11 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupLinear), count: count, - data: abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockupLinear.createWithTimestamps, (params)) }); } - /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithTimestamps}, each with the specified + /// @dev Expects multiple calls to {ISablierLockupTranched.createWithTimestamps}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLT( uint64 count, @@ -308,7 +308,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.expectCall({ callee: address(lockupTranched), count: count, - data: abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockupTranched.createWithTimestamps, (params)) }); } } diff --git a/test/core/fork/Fork.t.sol b/test/core/fork/Fork.t.sol index dd76cd5fc..a343909f3 100644 --- a/test/core/fork/Fork.t.sol +++ b/test/core/fork/Fork.t.sol @@ -31,7 +31,7 @@ abstract contract Fork_Test is Base_Test { function setUp() public virtual override { // Fork Ethereum Mainnet at a specific block number. - vm.createSelectFork({ blockNumber: 19_000_000, urlOrAlias: "mainnet" }); + vm.createSelectFork({ blockNumber: 20_428_723, urlOrAlias: "mainnet" }); // The base is set up after the fork is selected so that the base test contracts are deployed on the fork. Base_Test.setUp(); @@ -51,14 +51,14 @@ abstract contract Fork_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ /// @dev Checks the user assumptions. - function checkUsers(address sender, address recipient, address broker, address sablierContract) internal virtual { + function checkUsers(address sender, address recipient, address broker, address lockupContract) internal virtual { // The protocol does not allow the zero address to interact with it. vm.assume(sender != address(0) && recipient != address(0) && broker != address(0)); // The goal is to not have overlapping users because the forked asset balance tests would fail otherwise. vm.assume(sender != recipient && sender != broker && recipient != broker); vm.assume(sender != FORK_ASSET_HOLDER && recipient != FORK_ASSET_HOLDER && broker != FORK_ASSET_HOLDER); - vm.assume(sender != sablierContract && recipient != sablierContract && broker != sablierContract); + vm.assume(sender != lockupContract && recipient != lockupContract && broker != lockupContract); // Avoid users blacklisted by USDC or USDT. assumeNoBlacklisted(address(FORK_ASSET), sender); diff --git a/test/core/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol index 14b18495b..27a306c61 100644 --- a/test/core/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -22,7 +22,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierV2LockupDynamic} to transfer the holder's assets. + // Approve {SablierLockupDynamic} to transfer the holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupDynamic), MAX_UINT256))); diff --git a/test/core/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol index 18dcd40ac..21d517311 100644 --- a/test/core/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -23,7 +23,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierV2LockupLinear} to transfer the asset holder's assets. + // Approve {SablierLockupLinear} to transfer the asset holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupLinear), MAX_UINT256))); success; diff --git a/test/core/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol index 5ab8bb50c..377a97374 100644 --- a/test/core/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -22,7 +22,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierV2LockupTranched} to transfer the holder's assets. + // Approve {SablierLockupTranched} to transfer the holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupTranched), MAX_UINT256))); diff --git a/test/core/fork/NFTDescriptor.t.sol b/test/core/fork/NFTDescriptor.t.sol index 4a55cb355..1b6ec3df8 100644 --- a/test/core/fork/NFTDescriptor.t.sol +++ b/test/core/fork/NFTDescriptor.t.sol @@ -3,8 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { Fork_Test } from "./Fork.t.sol"; @@ -26,17 +27,25 @@ contract NFTDescriptor_Fork_Test is Fork_Test { MODIFIERS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Loads the Lockup V2.0 contracts pre-deployed on Mainnet. - modifier loadDeployments_V2_0() { - lockupDynamic = ISablierV2LockupDynamic(0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44); - lockupLinear = ISablierV2LockupLinear(0xB10daee1FCF62243aE27776D7a92D39dC8740f95); + /// @dev Loads the Lockup v1.0.0 contracts pre-deployed on Mainnet. + modifier loadDeployments_v1_0_0() { + lockupDynamic = ISablierLockupDynamic(0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44); + lockupLinear = ISablierLockupLinear(0xB10daee1FCF62243aE27776D7a92D39dC8740f95); _; } - /// @dev Loads the Lockup V2.1 contracts pre-deployed on Mainnet. - modifier loadDeployments_V2_1() { - lockupDynamic = ISablierV2LockupDynamic(0x7CC7e125d83A581ff438608490Cc0f7bDff79127); - lockupLinear = ISablierV2LockupLinear(0xAFb979d9afAd1aD27C5eFf4E27226E3AB9e5dCC9); + /// @dev Loads the Lockup v1.1.2 contracts pre-deployed on Mainnet. + modifier loadDeployments_v1_1_2() { + lockupDynamic = ISablierLockupDynamic(0x7CC7e125d83A581ff438608490Cc0f7bDff79127); + lockupLinear = ISablierLockupLinear(0xAFb979d9afAd1aD27C5eFf4E27226E3AB9e5dCC9); + _; + } + + /// @dev Loads the Lockup v1.2.0 contracts pre-deployed on Mainnet. + modifier loadDeployments_v1_2_0() { + lockupDynamic = ISablierLockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); + lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); + lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); _; } @@ -52,15 +61,41 @@ contract NFTDescriptor_Fork_Test is Fork_Test { TEST FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v2.0. + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.0.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. + /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupDynamic_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { + streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); + + // Set the new NFT descriptor for the previous version of Lockup Dynamic. + resetPrank({ msgSender: lockupDynamic.admin() }); + lockupDynamic.setNFTDescriptor(nftDescriptor); + + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupDynamic, streamId)), + count: 1 + }); + + // Generate the token URI using the new NFT Descriptor. + lockupDynamic.tokenURI(streamId); + } + + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.1.2. /// /// Checklist: - /// - It should expect a call to {ISablierV2LockupDynamic.tokenURI}. - /// - The test would fail if the call to {ISablierV2LockupDynamic.tokenURI} reverts. + /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. + /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupDynamic_V2_0(uint256 streamId) external loadDeployments_V2_0 { + function testForkFuzz_TokenURI_LockupDynamic_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Dynamic. @@ -78,15 +113,15 @@ contract NFTDescriptor_Fork_Test is Fork_Test { lockupDynamic.tokenURI(streamId); } - /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v2.1. + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.2.0. /// /// Checklist: - /// - It should expect a call to {ISablierV2LockupDynamic.tokenURI}. - /// - The test would fail if the call to {ISablierV2LockupDynamic.tokenURI} reverts. + /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. + /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupDynamic_V2_1(uint256 streamId) external loadDeployments_V2_1 { + function testForkFuzz_TokenURI_LockupDynamic_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Dynamic. @@ -104,15 +139,15 @@ contract NFTDescriptor_Fork_Test is Fork_Test { lockupDynamic.tokenURI(streamId); } - /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v2.0. + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.0.0. /// /// Checklist: - /// - It should expect a call to {ISablierV2LockupLinear.tokenURI}. - /// - The test would fail if the call to {ISablierV2LockupLinear.tokenURI} reverts. + /// - It should expect a call to {ISablierLockupLinear.tokenURI}. + /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupLinear_V2_0(uint256 streamId) external loadDeployments_V2_0 { + function testForkFuzz_TokenURI_LockupLinear_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Linear. @@ -130,15 +165,15 @@ contract NFTDescriptor_Fork_Test is Fork_Test { lockupLinear.tokenURI(streamId); } - /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v2.1. + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.1.2. /// /// Checklist: - /// - It should expect a call to {ISablierV2LockupLinear.tokenURI}. - /// - The test would fail if the call to {ISablierV2LockupLinear.tokenURI} reverts. + /// - It should expect a call to {ISablierLockupLinear.tokenURI}. + /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupLinear_V2_1(uint256 streamId) external loadDeployments_V2_1 { + function testForkFuzz_TokenURI_LockupLinear_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Linear. @@ -155,4 +190,56 @@ contract NFTDescriptor_Fork_Test is Fork_Test { // Generate the token URI using the new NFT Descriptor. lockupLinear.tokenURI(streamId); } + + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.2.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierLockupLinear.tokenURI}. + /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupLinear_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { + streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); + + // Set the new NFT descriptor for the previous version of Lockup Linear. + resetPrank({ msgSender: lockupLinear.admin() }); + lockupLinear.setNFTDescriptor(nftDescriptor); + + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupLinear, streamId)), + count: 1 + }); + + // Generate the token URI using the new NFT Descriptor. + lockupLinear.tokenURI(streamId); + } + + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Tranched v1.2.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierLockupTranched.tokenURI}. + /// - The test would fail if the call to {ISablierLockupTranched.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_LockupTranched_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { + streamId = _bound(streamId, 1, lockupTranched.nextStreamId() - 1); + + // Set the new NFT descriptor for the previous version of Lockup Tranched. + resetPrank({ msgSender: lockupTranched.admin() }); + lockupTranched.setNFTDescriptor(nftDescriptor); + + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockupTranched, streamId)), + count: 1 + }); + + // Generate the token URI using the new NFT Descriptor. + lockupTranched.tokenURI(streamId); + } } diff --git a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index 5f115da8b..fd1d8eff1 100644 --- a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -41,7 +41,7 @@ import { WithdrawMultiple_Integration_Concrete_Test } from "../lockup/withdraw-m NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupDynamic} integration concrete tests. +/// @notice Common testing logic needed across {SablierLockupDynamic} integration concrete tests. abstract contract LockupDynamic_Integration_Concrete_Test is Integration_Test, LockupDynamic_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, LockupDynamic_Integration_Shared_Test) { // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is @@ -49,8 +49,8 @@ abstract contract LockupDynamic_Integration_Concrete_Test is Integration_Test, L Integration_Test.setUp(); LockupDynamic_Integration_Shared_Test.setUp(); - // Cast the {LockupDynamic} contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupDynamic); + // Cast the {LockupDynamic} contract as {ISablierLockup}. + lockup = ISablierLockup(lockupDynamic); } } diff --git a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol index 8bbfd69f4..8915a68d3 100644 --- a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupDynamic } from "src/core/SablierV2LockupDynamic.sol"; +import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; import { LockupDynamic_Integration_Concrete_Test } from "./LockupDynamic.t.sol"; @@ -13,18 +13,18 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); // Construct the contract. - SablierV2LockupDynamic constructedLockupDynamic = new SablierV2LockupDynamic({ + SablierLockupDynamic constructedLockupDynamic = new SablierLockupDynamic({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor, maxSegmentCount: defaults.MAX_SEGMENT_COUNT() }); - // {SablierV2Lockup.constant} + // {SablierLockup.constant} UD60x18 actualMaxBrokerFee = constructedLockupDynamic.MAX_BROKER_FEE(); UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - // {SablierV2Lockup.constructor} + // {SablierLockup.constructor} address actualAdmin = constructedLockupDynamic.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); @@ -37,10 +37,10 @@ contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_In address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - // {SablierV2Lockup.supportsInterface} + // {SablierLockup.supportsInterface} assertTrue(constructedLockupDynamic.supportsInterface(0x49064906), "ERC-4906 interface ID"); - // {SablierV2LockupDynamic.constructor} + // {SablierLockupDynamic.constructor} uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_SEGMENT_COUNT"); diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol index 79072fc32..a365cb560 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; @@ -27,7 +27,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, defaults.createWithDurationsLD()); + abi.encodeCall(ISablierLockupDynamic.createWithDurations, defaults.createWithDurationsLD()); (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -35,7 +35,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_SegmentCountTooHigh() external whenNotDelegateCalled { LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, 25_000)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupDynamic_SegmentCountTooHigh.selector, 25_000)); createDefaultStreamWithDurations(segments); } @@ -46,7 +46,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, index, startTime + segments[0].duration, startTime + segments[0].duration @@ -67,7 +67,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is segments[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, startTime, startTime + segments[0].duration ) @@ -99,7 +99,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, index, startTime + segments[0].duration, startTime + segments[0].duration + segments[1].duration @@ -132,7 +132,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is segments[0].timestamp = timestamps.start + segmentsWithDurations[0].duration; segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; - // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index f5e00fc95..4382ccc25 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -7,7 +7,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; @@ -29,7 +29,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, defaults.createWithTimestampsLD()); + abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, defaults.createWithTimestampsLD()); (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -43,7 +43,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_BROKER_FEE` // is hard coded to 10%. - vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); + vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); uint128 totalAmount = 0; createDefaultStreamWithTotalAmount(totalAmount); } @@ -54,7 +54,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenRecipientNonZeroAddress whenDepositAmountNotZero { - vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); + vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); createDefaultStreamWithStartTime(0); } @@ -66,7 +66,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenStartTimeNotZero { LockupDynamic.Segment[] memory segments; - vm.expectRevert(Errors.SablierV2LockupDynamic_SegmentCountZero.selector); + vm.expectRevert(Errors.SablierLockupDynamic_SegmentCountZero.selector); createDefaultStreamWithSegments(segments); } @@ -80,9 +80,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is { uint256 segmentCount = defaults.MAX_SEGMENT_COUNT() + 1; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupDynamic_SegmentCountTooHigh.selector, segmentCount)); createDefaultStreamWithSegments(segments); } @@ -119,7 +117,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) @@ -146,7 +144,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) @@ -175,7 +173,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, index, segments[0].timestamp, segments[1].timestamp @@ -200,7 +198,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is { uint40 endTime = defaults.END_TIME(); vm.warp({ newTimestamp: endTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); createDefaultStream(); } @@ -230,7 +228,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) @@ -256,7 +254,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -329,7 +327,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is // Make the Sender the stream's funder. address funder = users.sender; - // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. expectCallToTransferFrom({ asset: IERC20(asset), from: funder, diff --git a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol index 972f9df07..4f2a1fee6 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.t.sol @@ -9,7 +9,7 @@ import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol" contract GetSegments_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupDynamic.getSegments(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol index 75e3505e3..0e625a39b 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol @@ -16,7 +16,7 @@ contract GetStream_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Inte function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupDynamic.getStream(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol index 1d573d2b3..31001df8f 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol @@ -9,7 +9,7 @@ import { LockupDynamic_Integration_Concrete_Test } from "../LockupDynamic.t.sol" contract GetTimestamps_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupDynamic.getTimestamps(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol index 4c4e4ad9a..019ebe177 100644 --- a/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.t.sol @@ -49,7 +49,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = - unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Dynamic contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Dynamic Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Dynamic #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; + unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Dynamic contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Dynamic Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Dynamic #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI"); } diff --git a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol index 7fe2bf7cf..6af6486f7 100644 --- a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -41,7 +41,7 @@ import { WithdrawMultiple_Integration_Concrete_Test } from "../lockup/withdraw-m NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupLinear} integration concrete tests. +/// @notice Common testing logic needed across {SablierLockupLinear} integration concrete tests. abstract contract LockupLinear_Integration_Concrete_Test is Integration_Test, LockupLinear_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, LockupLinear_Integration_Shared_Test) { // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is @@ -49,8 +49,8 @@ abstract contract LockupLinear_Integration_Concrete_Test is Integration_Test, Lo Integration_Test.setUp(); LockupLinear_Integration_Shared_Test.setUp(); - // Cast the {LockupLinear} contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupLinear); + // Cast the {LockupLinear} contract as {ISablierLockup}. + lockup = ISablierLockup(lockupLinear); } } diff --git a/test/core/integration/concrete/lockup-linear/constructor.t.sol b/test/core/integration/concrete/lockup-linear/constructor.t.sol index d51a1e113..90ade2479 100644 --- a/test/core/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/core/integration/concrete/lockup-linear/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupLinear } from "src/core/SablierV2LockupLinear.sol"; +import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; import { LockupLinear_Integration_Concrete_Test } from "./LockupLinear.t.sol"; @@ -13,15 +13,15 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); // Construct the contract. - SablierV2LockupLinear constructedLockupLinear = - new SablierV2LockupLinear({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor }); + SablierLockupLinear constructedLockupLinear = + new SablierLockupLinear({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor }); - // {SablierV2Lockup.constant} + // {SablierLockup.constant} UD60x18 actualMaxBrokerFee = constructedLockupLinear.MAX_BROKER_FEE(); UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - // {SablierV2Lockup.constructor} + // {SablierLockup.constructor} address actualAdmin = constructedLockupLinear.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); @@ -34,7 +34,7 @@ contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Inte address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - // {SablierV2Lockup.supportsInterface} + // {SablierLockup.supportsInterface} assertTrue(constructedLockupLinear.supportsInterface(0x49064906), "ERC-4906 interface ID"); } } diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol index 623d87884..b88f86563 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; @@ -23,7 +23,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupLinear.createWithDurations, defaults.createWithDurationsLL()); + abi.encodeCall(ISablierLockupLinear.createWithDurations, defaults.createWithDurationsLL()); (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -42,7 +42,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime + Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime ) ); @@ -69,9 +69,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime - ) + abi.encodeWithSelector(Errors.SablierLockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime) ); // Create the stream. @@ -95,7 +93,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is end: blockTimestamp + defaults.TOTAL_DURATION() }); - // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockupLinear}. expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index b809172e7..ca6103c7f 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -6,7 +6,7 @@ import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093 import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; @@ -28,7 +28,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, defaults.createWithTimestampsLL()); + abi.encodeCall(ISablierLockupLinear.createWithTimestamps, defaults.createWithTimestampsLL()); (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -42,7 +42,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is /// @dev It is not possible to obtain a zero deposit amount from a non-zero total amount, because the /// `MAX_BROKER_FEE` is hard coded to 10%. function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { - vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); + vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); createDefaultStreamWithTotalAmount(0); } @@ -55,7 +55,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is uint40 cliffTime = defaults.CLIFF_TIME(); uint40 endTime = defaults.END_TIME(); - vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); + vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: 0, cliff: cliffTime, end: endTime })); } @@ -71,9 +71,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is uint40 endTime = defaults.START_TIME(); vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime - ) + abi.encodeWithSelector(Errors.SablierLockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime) ); createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: 0, end: endTime })); } @@ -121,7 +119,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is uint40 endTime = defaults.END_TIME(); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime + Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime ) ); createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); @@ -140,9 +138,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is uint40 cliffTime = defaults.END_TIME(); uint40 endTime = defaults.CLIFF_TIME(); vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime - ) + abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } @@ -160,7 +156,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is { uint40 endTime = defaults.END_TIME(); vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); createDefaultStream(); } @@ -177,7 +173,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -236,7 +232,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is // Make the Sender the stream's funder. address funder = users.sender; - // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockupLinear}. expectCallToTransferFrom({ asset: IERC20(asset), from: funder, diff --git a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol index 4aa27d570..145955eb3 100644 --- a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.t.sol @@ -8,7 +8,7 @@ import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; contract GetCliffTime_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupLinear.getCliffTime(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol index c511f0e4b..0066e8ec3 100644 --- a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol @@ -16,7 +16,7 @@ contract GetStream_LockupLinear_Integration_Concrete_Test is LockupLinear_Integr function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupLinear.getStream(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol index 4fd3a2aa4..92e49c68b 100644 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol @@ -9,7 +9,7 @@ import { LockupLinear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; contract GetTimestamps_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupLinear.getTimestamps(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol index 2ce92568e..2197257ec 100644 --- a/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol +++ b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.t.sol @@ -49,7 +49,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = - unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Linear contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Linear Address: 0x3381cd18e2fb4db236bf0525938ab6e43db0440f\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Linear #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCgxOSwyMiUsNjMlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMTksMjIlLDYzJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woMTksMjIlLDYzJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBMaW5lYXI8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iMCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MzM4MWNkMThlMmZiNGRiMjM2YmYwNTI1OTM4YWI2ZTQzZGIwNDQwZiDigKIgU2FibGllciBWMiBMb2NrdXAgTGluZWFyPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9Ii01MCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYiDigKIgREFJPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjwvdGV4dD48dXNlIGhyZWY9IiNHbG93IiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjR2xvdyIgeD0iMTAwMCIgeT0iMTAwMCIgZmlsbC1vcGFjaXR5PSIuOSIvPjx1c2UgaHJlZj0iI0xvZ28iIHg9IjE3MCIgeT0iMTcwIiB0cmFuc2Zvcm09InNjYWxlKC42KSIvPjx1c2UgaHJlZj0iI0hvdXJnbGFzcyIgeD0iMTUwIiB5PSI5MCIgdHJhbnNmb3JtPSJyb3RhdGUoMTApIiB0cmFuc2Zvcm0tb3JpZ2luPSI1MDAgNTAwIi8+PHVzZSBocmVmPSIjUHJvZ3Jlc3MiIHg9IjE0NCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjU3RhdHVzIiB4PSIzNjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0Ftb3VudCIgeD0iNTY4IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNEdXJhdGlvbiIgeD0iNzA0IiB5PSI3OTAiLz48L3N2Zz4="}'; + unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Linear contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Linear Address: 0x3381cd18e2fb4db236bf0525938ab6e43db0440f\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Linear #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCgxOSwyMiUsNjMlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMTksMjIlLDYzJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDE5LDIyJSw2MyUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woMTksMjIlLDYzJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBMaW5lYXI8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iMCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MzM4MWNkMThlMmZiNGRiMjM2YmYwNTI1OTM4YWI2ZTQzZGIwNDQwZiDigKIgU2FibGllciBWMiBMb2NrdXAgTGluZWFyPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9Ii01MCUiIGhyZWY9IiNGbG9hdGluZ1RleHQiIGZpbGw9IiNmZmYiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZmlsbC1vcGFjaXR5PSIuOCIgZm9udC1zaXplPSIyNnB4Ij48YW5pbWF0ZSBhZGRpdGl2ZT0ic3VtIiBhdHRyaWJ1dGVOYW1lPSJzdGFydE9mZnNldCIgYmVnaW49IjBzIiBkdXI9IjUwcyIgZnJvbT0iMCUiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiB0bz0iMTAwJSIvPjB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYiDigKIgREFJPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjwvdGV4dD48dXNlIGhyZWY9IiNHbG93IiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjR2xvdyIgeD0iMTAwMCIgeT0iMTAwMCIgZmlsbC1vcGFjaXR5PSIuOSIvPjx1c2UgaHJlZj0iI0xvZ28iIHg9IjE3MCIgeT0iMTcwIiB0cmFuc2Zvcm09InNjYWxlKC42KSIvPjx1c2UgaHJlZj0iI0hvdXJnbGFzcyIgeD0iMTUwIiB5PSI5MCIgdHJhbnNmb3JtPSJyb3RhdGUoMTApIiB0cmFuc2Zvcm0tb3JpZ2luPSI1MDAgNTAwIi8+PHVzZSBocmVmPSIjUHJvZ3Jlc3MiIHg9IjE0NCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjU3RhdHVzIiB4PSIzNjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0Ftb3VudCIgeD0iNTY4IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNEdXJhdGlvbiIgeD0iNzA0IiB5PSI3OTAiLz48L3N2Zz4="}'; assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI"); } diff --git a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol index 48c052a22..f90a9e62e 100644 --- a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -41,7 +41,7 @@ import { WithdrawMultiple_Integration_Concrete_Test } from "../lockup/withdraw-m NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupTranched} integration concrete tests. +/// @notice Common testing logic needed across {SablierLockupTranched} integration concrete tests. abstract contract LockupTranched_Integration_Concrete_Test is Integration_Test, LockupTranched_Integration_Shared_Test @@ -52,8 +52,8 @@ abstract contract LockupTranched_Integration_Concrete_Test is Integration_Test.setUp(); LockupTranched_Integration_Shared_Test.setUp(); - // Cast the {LockupTranched} contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupTranched); + // Cast the {LockupTranched} contract as {ISablierLockup}. + lockup = ISablierLockup(lockupTranched); } } diff --git a/test/core/integration/concrete/lockup-tranched/constructor.t.sol b/test/core/integration/concrete/lockup-tranched/constructor.t.sol index ed3549a60..246de6cdd 100644 --- a/test/core/integration/concrete/lockup-tranched/constructor.t.sol +++ b/test/core/integration/concrete/lockup-tranched/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; -import { SablierV2LockupTranched } from "src/core/SablierV2LockupTranched.sol"; +import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; import { LockupTranched_Integration_Concrete_Test } from "./LockupTranched.t.sol"; @@ -13,18 +13,18 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ emit TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); // Construct the contract. - SablierV2LockupTranched constructedLockupTranched = new SablierV2LockupTranched({ + SablierLockupTranched constructedLockupTranched = new SablierLockupTranched({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor, maxTrancheCount: defaults.MAX_TRANCHE_COUNT() }); - // {SablierV2Lockup.constant} + // {SablierLockup.constant} UD60x18 actualMaxBrokerFee = constructedLockupTranched.MAX_BROKER_FEE(); UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - // {SablierV2Lockup.constructor} + // {SablierLockup.constructor} address actualAdmin = constructedLockupTranched.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); @@ -37,10 +37,10 @@ contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_ address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - // {SablierV2Lockup.supportsInterface} + // {SablierLockup.supportsInterface} assertTrue(constructedLockupTranched.supportsInterface(0x49064906), "ERC-4906 interface ID"); - // {SablierV2LockupTranched.constructor} + // {SablierLockupTranched.constructor} uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); uint256 expectedMaxTrancheCount = defaults.MAX_TRANCHE_COUNT(); assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_TRANCHE_COUNT"); diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol index b8e7a2579..3cd78233e 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; @@ -25,7 +25,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupTranched.createWithDurations, defaults.createWithDurationsLT()); + abi.encodeCall(ISablierLockupTranched.createWithDurations, defaults.createWithDurationsLT()); (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -33,7 +33,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is /// @dev it should revert. function test_RevertWhen_TrancheCountTooHigh() external whenNotDelegateCalled { LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, 25_000)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupTranched_TrancheCountTooHigh.selector, 25_000)); createDefaultStreamWithDurations(tranches); } @@ -44,7 +44,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is uint256 index = 2; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration + tranches[1].duration, startTime + tranches[0].duration + tranches[1].duration @@ -65,7 +65,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is tranches[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, startTime, startTime + tranches[0].duration ) @@ -93,7 +93,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration, startTime + tranches[0].duration + tranches[1].duration @@ -126,7 +126,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is tranches[1].timestamp = tranches[0].timestamp + tranchesWithDurations[1].duration; tranches[2].timestamp = tranches[1].timestamp + tranchesWithDurations[2].duration; - // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockupTranched}. expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 4d30b16db..5e0ddddd0 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -7,7 +7,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; @@ -29,7 +29,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is function test_RevertWhen_DelegateCalled() external { bytes memory callData = - abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, defaults.createWithTimestampsLT()); + abi.encodeCall(ISablierLockupTranched.createWithTimestamps, defaults.createWithTimestampsLT()); (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -43,7 +43,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is function test_RevertWhen_DepositAmountZero() external whenNotDelegateCalled whenRecipientNonZeroAddress { // It is not possible to obtain a zero deposit amount from a non-zero total amount, because the `MAX_BROKER_FEE` // is hard coded to 10%. - vm.expectRevert(Errors.SablierV2Lockup_DepositAmountZero.selector); + vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); uint128 totalAmount = 0; createDefaultStreamWithTotalAmount(totalAmount); } @@ -54,7 +54,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenRecipientNonZeroAddress whenDepositAmountNotZero { - vm.expectRevert(Errors.SablierV2Lockup_StartTimeZero.selector); + vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); createDefaultStreamWithStartTime(0); } @@ -66,7 +66,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenStartTimeNotZero { LockupTranched.Tranche[] memory tranches; - vm.expectRevert(Errors.SablierV2LockupTranched_TrancheCountZero.selector); + vm.expectRevert(Errors.SablierLockupTranched_TrancheCountZero.selector); createDefaultStreamWithTranches(tranches); } @@ -80,9 +80,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is { uint256 trancheCount = defaults.MAX_TRANCHE_COUNT() + 1; LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupTranched_TrancheCountTooHigh.selector, trancheCount)); createDefaultStreamWithTranches(tranches); } @@ -119,7 +117,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) @@ -146,7 +144,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) @@ -175,7 +173,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, index, tranches[0].timestamp, tranches[1].timestamp @@ -200,7 +198,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is { uint40 endTime = defaults.END_TIME(); vm.warp({ newTimestamp: endTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_EndTimeNotInTheFuture.selector, endTime, endTime)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); createDefaultStream(); } @@ -230,7 +228,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + Errors.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, depositAmount, defaultDepositAmount ) @@ -256,7 +254,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); } @@ -329,7 +327,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is // Make the Sender the stream's funder. address funder = users.sender; - // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockupTranched}. expectCallToTransferFrom({ asset: IERC20(asset), from: funder, diff --git a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol index 0a422bbd3..185fbedce 100644 --- a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol @@ -16,7 +16,7 @@ contract GetStream_LockupTranched_Integration_Concrete_Test is LockupTranched_In function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupTranched.getStream(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol index 70c53323c..1e759dacf 100644 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol @@ -9,7 +9,7 @@ import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.so contract GetTimestamps_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupTranched.getTimestamps(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol index 0b3a8dc05..e54fbaa0b 100644 --- a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.t.sol @@ -9,7 +9,7 @@ import { LockupTranched_Integration_Concrete_Test } from "../LockupTranched.t.so contract GetTranches_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Concrete_Test { function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockupTranched.getTranches(nullStreamId); } diff --git a/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol index 04b8aeb06..a32053887 100644 --- a/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol +++ b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.t.sol @@ -49,7 +49,7 @@ contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Int tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = - unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier V2 Lockup Tranched contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier V2 Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; + unicode'{"attributes":[{"trait_type":"Asset","value":"DAI"},{"trait_type":"Sender","value":"0x6332e7b1deb1f1a0b77b2bb18b144330c7291bca"},{"trait_type":"Status","value":"Streaming"}],"description":"This NFT represents a payment stream in a Sablier Lockup Tranched contract. The owner of this NFT can withdraw the streamed assets, which are denominated in DAI.\\n\\n- Stream ID: 1\\n- Lockup Tranched Address: 0xdb25a7b768311de128bbda7b8426c3f9c74f3240\\n- DAI Address: 0x03a6a84cd762d9707a21605b548aaab891562aab\\n\\n⚠️ WARNING: Transferring the NFT makes the new owner the recipient of the stream. The funds are not automatically withdrawn for the previous recipient.","external_url":"https://sablier.com","name":"Sablier Lockup Tranched #1","image":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAwIiBoZWlnaHQ9IjEwMDAiIHZpZXdCb3g9IjAgMCAxMDAwIDEwMDAiPjxyZWN0IHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbHRlcj0idXJsKCNOb2lzZSkiLz48cmVjdCB4PSI3MCIgeT0iNzAiIHdpZHRoPSI4NjAiIGhlaWdodD0iODYwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjQ1IiByeT0iNDUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48ZGVmcz48Y2lyY2xlIGlkPSJHbG93IiByPSI1MDAiIGZpbGw9InVybCgjUmFkaWFsR2xvdykiLz48ZmlsdGVyIGlkPSJOb2lzZSI+PGZlRmxvb2QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmxvb2QtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiIGZsb29kLW9wYWNpdHk9IjEiIHJlc3VsdD0iZmxvb2RGaWxsIi8+PGZlVHVyYnVsZW5jZSBiYXNlRnJlcXVlbmN5PSIuNCIgbnVtT2N0YXZlcz0iMyIgcmVzdWx0PSJOb2lzZSIgdHlwZT0iZnJhY3RhbE5vaXNlIi8+PGZlQmxlbmQgaW49Ik5vaXNlIiBpbjI9ImZsb29kRmlsbCIgbW9kZT0ic29mdC1saWdodCIvPjwvZmlsdGVyPjxwYXRoIGlkPSJMb2dvIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4xIiBkPSJtMTMzLjU1OSwxMjQuMDM0Yy0uMDEzLDIuNDEyLTEuMDU5LDQuODQ4LTIuOTIzLDYuNDAyLTIuNTU4LDEuODE5LTUuMTY4LDMuNDM5LTcuODg4LDQuOTk2LTE0LjQ0LDguMjYyLTMxLjA0NywxMi41NjUtNDcuNjc0LDEyLjU2OS04Ljg1OC4wMzYtMTcuODM4LTEuMjcyLTI2LjMyOC0zLjY2My05LjgwNi0yLjc2Ni0xOS4wODctNy4xMTMtMjcuNTYyLTEyLjc3OC0xMy44NDItOC4wMjUsOS40NjgtMjguNjA2LDE2LjE1My0zNS4yNjVoMGMyLjAzNS0xLjgzOCw0LjI1Mi0zLjU0Niw2LjQ2My01LjIyNGgwYzYuNDI5LTUuNjU1LDE2LjIxOC0yLjgzNSwyMC4zNTgsNC4xNyw0LjE0Myw1LjA1Nyw4LjgxNiw5LjY0OSwxMy45MiwxMy43MzRoLjAzN2M1LjczNiw2LjQ2MSwxNS4zNTctMi4yNTMsOS4zOC04LjQ4LDAsMC0zLjUxNS0zLjUxNS0zLjUxNS0zLjUxNS0xMS40OS0xMS40NzgtNTIuNjU2LTUyLjY2NC02NC44MzctNjQuODM3bC4wNDktLjAzN2MtMS43MjUtMS42MDYtMi43MTktMy44NDctMi43NTEtNi4yMDRoMGMtLjA0Ni0yLjM3NSwxLjA2Mi00LjU4MiwyLjcyNi02LjIyOWgwbC4xODUtLjE0OGgwYy4wOTktLjA2MiwuMjIyLS4xNDgsLjM3LS4yNTloMGMyLjA2LTEuMzYyLDMuOTUxLTIuNjIxLDYuMDQ0LTMuODQyQzU3Ljc2My0zLjQ3Myw5Ny43Ni0yLjM0MSwxMjguNjM3LDE4LjMzMmMxNi42NzEsOS45NDYtMjYuMzQ0LDU0LjgxMy0zOC42NTEsNDAuMTk5LTYuMjk5LTYuMDk2LTE4LjA2My0xNy43NDMtMTkuNjY4LTE4LjgxMS02LjAxNi00LjA0Ny0xMy4wNjEsNC43NzYtNy43NTIsOS43NTFsNjguMjU0LDY4LjM3MWMxLjcyNCwxLjYwMSwyLjcxNCwzLjg0LDIuNzM4LDYuMTkyWiIvPjxwYXRoIGlkPSJGbG9hdGluZ1RleHQiIGZpbGw9Im5vbmUiIGQ9Ik0xMjUgNDVoNzUwczgwIDAgODAgODB2NzUwczAgODAgLTgwIDgwaC03NTBzLTgwIDAgLTgwIC04MHYtNzUwczAgLTgwIDgwIC04MCIvPjxyYWRpYWxHcmFkaWVudCBpZD0iUmFkaWFsR2xvdyI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIiBzdG9wLW9wYWNpdHk9Ii42Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIiBzdG9wLW9wYWNpdHk9IjAiLz48L3JhZGlhbEdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iU2FuZFRvcCIgeDE9IjAlIiB5MT0iMCUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3AtY29sb3I9ImhzbCg2MSw4OCUsNDAlKSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iaHNsKDIzMCwyMSUsMTElKSIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJTYW5kQm90dG9tIiB4MT0iMTAwJSIgeTE9IjEwMCUiPjxzdG9wIG9mZnNldD0iMTAlIiBzdG9wLWNvbG9yPSJoc2woMjMwLDIxJSwxMSUpIi8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSJoc2woNjEsODglLDQwJSkiLz48YW5pbWF0ZSBhdHRyaWJ1dGVOYW1lPSJ4MSIgZHVyPSI2cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHZhbHVlcz0iMzAlOzYwJTsxMjAlOzYwJTszMCU7Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkhvdXJnbGFzc1N0cm9rZSIgZ3JhZGllbnRUcmFuc2Zvcm09InJvdGF0ZSg5MCkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjUwJSIgc3RvcC1jb2xvcj0iaHNsKDYxLDg4JSw0MCUpIi8+PHN0b3Agb2Zmc2V0PSI4MCUiIHN0b3AtY29sb3I9ImhzbCgyMzAsMjElLDExJSkiLz48L2xpbmVhckdyYWRpZW50PjxnIGlkPSJIb3VyZ2xhc3MiPjxwYXRoIGQ9Ik0gNTAsMzYwIGEgMzAwLDMwMCAwIDEsMSA2MDAsMCBhIDMwMCwzMDAgMCAxLDEgLTYwMCwwIiBmaWxsPSIjZmZmIiBmaWxsLW9wYWNpdHk9Ii4wMiIgc3Ryb2tlPSJ1cmwoI0hvdXJnbGFzc1N0cm9rZSkiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Im01NjYsMTYxLjIwMXYtNTMuOTI0YzAtMTkuMzgyLTIyLjUxMy0zNy41NjMtNjMuMzk4LTUxLjE5OC00MC43NTYtMTMuNTkyLTk0Ljk0Ni0yMS4wNzktMTUyLjU4Ny0yMS4wNzlzLTExMS44MzgsNy40ODctMTUyLjYwMiwyMS4wNzljLTQwLjg5MywxMy42MzYtNjMuNDEzLDMxLjgxNi02My40MTMsNTEuMTk4djUzLjkyNGMwLDE3LjE4MSwxNy43MDQsMzMuNDI3LDUwLjIyMyw0Ni4zOTR2Mjg0LjgwOWMtMzIuNTE5LDEyLjk2LTUwLjIyMywyOS4yMDYtNTAuMjIzLDQ2LjM5NHY1My45MjRjMCwxOS4zODIsMjIuNTIsMzcuNTYzLDYzLjQxMyw1MS4xOTgsNDAuNzYzLDEzLjU5Miw5NC45NTQsMjEuMDc5LDE1Mi42MDIsMjEuMDc5czExMS44MzEtNy40ODcsMTUyLjU4Ny0yMS4wNzljNDAuODg2LTEzLjYzNiw2My4zOTgtMzEuODE2LDYzLjM5OC01MS4xOTh2LTUzLjkyNGMwLTE3LjE5Ni0xNy43MDQtMzMuNDM1LTUwLjIyMy00Ni40MDFWMjA3LjYwM2MzMi41MTktMTIuOTY3LDUwLjIyMy0yOS4yMDYsNTAuMjIzLTQ2LjQwMVptLTM0Ny40NjIsNTcuNzkzbDEzMC45NTksMTMxLjAyNy0xMzAuOTU5LDEzMS4wMTNWMjE4Ljk5NFptMjYyLjkyNC4wMjJ2MjYyLjAxOGwtMTMwLjkzNy0xMzEuMDA2LDEzMC45MzctMTMxLjAxM1oiIGZpbGw9IiMxNjE4MjIiPjwvcGF0aD48cG9seWdvbiBwb2ludHM9IjM1MCAzNTAuMDI2IDQxNS4wMyAyODQuOTc4IDI4NSAyODQuOTc4IDM1MCAzNTAuMDI2IiBmaWxsPSJ1cmwoI1NhbmRCb3R0b20pIi8+PHBhdGggZD0ibTQxNi4zNDEsMjgxLjk3NWMwLC45MTQtLjM1NCwxLjgwOS0xLjAzNSwyLjY4LTUuNTQyLDcuMDc2LTMyLjY2MSwxMi40NS02NS4yOCwxMi40NS0zMi42MjQsMC01OS43MzgtNS4zNzQtNjUuMjgtMTIuNDUtLjY4MS0uODcyLTEuMDM1LTEuNzY3LTEuMDM1LTIuNjgsMC0uOTE0LjM1NC0xLjgwOCwxLjAzNS0yLjY3Niw1LjU0Mi03LjA3NiwzMi42NTYtMTIuNDUsNjUuMjgtMTIuNDUsMzIuNjE5LDAsNTkuNzM4LDUuMzc0LDY1LjI4LDEyLjQ1LjY4MS44NjcsMS4wMzUsMS43NjIsMS4wMzUsMi42NzZaIiBmaWxsPSJ1cmwoI1NhbmRUb3ApIi8+PHBhdGggZD0ibTQ4MS40Niw1MDQuMTAxdjU4LjQ0OWMtMi4zNS43Ny00LjgyLDEuNTEtNy4zOSwyLjIzLTMwLjMsOC41NC03NC42NSwxMy45Mi0xMjQuMDYsMTMuOTItNTMuNiwwLTEwMS4yNC02LjMzLTEzMS40Ny0xNi4xNnYtNTguNDM5aDI2Mi45MloiIGZpbGw9InVybCgjU2FuZEJvdHRvbSkiLz48ZWxsaXBzZSBjeD0iMzUwIiBjeT0iNTA0LjEwMSIgcng9IjEzMS40NjIiIHJ5PSIyOC4xMDgiIGZpbGw9InVybCgjU2FuZFRvcCkiLz48ZyBmaWxsPSJub25lIiBzdHJva2U9InVybCgjSG91cmdsYXNzU3Ryb2tlKSIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS13aWR0aD0iNCI+PHBhdGggZD0ibTU2NS42NDEsMTA3LjI4YzAsOS41MzctNS41NiwxOC42MjktMTUuNjc2LDI2Ljk3M2gtLjAyM2MtOS4yMDQsNy41OTYtMjIuMTk0LDE0LjU2Mi0zOC4xOTcsMjAuNTkyLTM5LjUwNCwxNC45MzYtOTcuMzI1LDI0LjM1NS0xNjEuNzMzLDI0LjM1NS05MC40OCwwLTE2Ny45NDgtMTguNTgyLTE5OS45NTMtNDQuOTQ4aC0uMDIzYy0xMC4xMTUtOC4zNDQtMTUuNjc2LTE3LjQzNy0xNS42NzYtMjYuOTczLDAtMzkuNzM1LDk2LjU1NC03MS45MjEsMjE1LjY1Mi03MS45MjFzMjE1LjYyOSwzMi4xODUsMjE1LjYyOSw3MS45MjFaIi8+PHBhdGggZD0ibTEzNC4zNiwxNjEuMjAzYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iMTYxLjIwMyIgeDI9IjEzNC4zNiIgeTI9IjEwNy4yOCIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSIxNjEuMjAzIiB4Mj0iNTY1LjY0IiB5Mj0iMTA3LjI4Ii8+PGxpbmUgeDE9IjE4NC41ODQiIHkxPSIyMDYuODIzIiB4Mj0iMTg0LjU4NSIgeTI9IjUzNy41NzkiLz48bGluZSB4MT0iMjE4LjE4MSIgeTE9IjIxOC4xMTgiIHgyPSIyMTguMTgxIiB5Mj0iNTYyLjUzNyIvPjxsaW5lIHgxPSI0ODEuODE4IiB5MT0iMjE4LjE0MiIgeDI9IjQ4MS44MTkiIHkyPSI1NjIuNDI4Ii8+PGxpbmUgeDE9IjUxNS40MTUiIHkxPSIyMDcuMzUyIiB4Mj0iNTE1LjQxNiIgeTI9IjUzNy41NzkiLz48cGF0aCBkPSJtMTg0LjU4LDUzNy41OGMwLDUuNDUsNC4yNywxMC42NSwxMi4wMywxNS40MmguMDJjNS41MSwzLjM5LDEyLjc5LDYuNTUsMjEuNTUsOS40MiwzMC4yMSw5LjksNzguMDIsMTYuMjgsMTMxLjgzLDE2LjI4LDQ5LjQxLDAsOTMuNzYtNS4zOCwxMjQuMDYtMTMuOTIsMi43LS43Niw1LjI5LTEuNTQsNy43NS0yLjM1LDguNzctMi44NywxNi4wNS02LjA0LDIxLjU2LTkuNDNoMGM3Ljc2LTQuNzcsMTIuMDQtOS45NywxMi4wNC0xNS40MiIvPjxwYXRoIGQ9Im0xODQuNTgyLDQ5Mi42NTZjLTMxLjM1NCwxMi40ODUtNTAuMjIzLDI4LjU4LTUwLjIyMyw0Ni4xNDIsMCw5LjUzNiw1LjU2NCwxOC42MjcsMTUuNjc3LDI2Ljk2OWguMDIyYzguNTAzLDcuMDA1LDIwLjIxMywxMy40NjMsMzQuNTI0LDE5LjE1OSw5Ljk5OSwzLjk5MSwyMS4yNjksNy42MDksMzMuNTk3LDEwLjc4OCwzNi40NSw5LjQwNyw4Mi4xODEsMTUuMDAyLDEzMS44MzUsMTUuMDAyczk1LjM2My01LjU5NSwxMzEuODA3LTE1LjAwMmMxMC44NDctMi43OSwyMC44NjctNS45MjYsMjkuOTI0LTkuMzQ5LDEuMjQ0LS40NjcsMi40NzMtLjk0MiwzLjY3My0xLjQyNCwxNC4zMjYtNS42OTYsMjYuMDM1LTEyLjE2MSwzNC41MjQtMTkuMTczaC4wMjJjMTAuMTE0LTguMzQyLDE1LjY3Ny0xNy40MzMsMTUuNjc3LTI2Ljk2OSwwLTE3LjU2Mi0xOC44NjktMzMuNjY1LTUwLjIyMy00Ni4xNSIvPjxwYXRoIGQ9Im0xMzQuMzYsNTkyLjcyYzAsMzkuNzM1LDk2LjU1NCw3MS45MjEsMjE1LjY1Miw3MS45MjFzMjE1LjYyOS0zMi4xODYsMjE1LjYyOS03MS45MjEiLz48bGluZSB4MT0iMTM0LjM2IiB5MT0iNTkyLjcyIiB4Mj0iMTM0LjM2IiB5Mj0iNTM4Ljc5NyIvPjxsaW5lIHgxPSI1NjUuNjQiIHkxPSI1OTIuNzIiIHgyPSI1NjUuNjQiIHkyPSI1MzguNzk3Ii8+PHBvbHlsaW5lIHBvaW50cz0iNDgxLjgyMiA0ODEuOTAxIDQ4MS43OTggNDgxLjg3NyA0ODEuNzc1IDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDIxOC4xODUgMjE4LjEyOSIvPjxwb2x5bGluZSBwb2ludHM9IjIxOC4xODUgNDgxLjkwMSAyMTguMjMxIDQ4MS44NTQgMzUwLjAxNSAzNTAuMDI2IDQ4MS44MjIgMjE4LjE1MiIvPjwvZz48L2c+PGcgaWQ9IlByb2dyZXNzIiBmaWxsPSIjZmZmIj48cmVjdCB3aWR0aD0iMjA4IiBoZWlnaHQ9IjEwMCIgZmlsbC1vcGFjaXR5PSIuMDMiIHJ4PSIxNSIgcnk9IjE1IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1vcGFjaXR5PSIuMSIgc3Ryb2tlLXdpZHRoPSI0Ii8+PHRleHQgeD0iMjAiIHk9IjM0IiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjJweCI+UHJvZ3Jlc3M8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+MjUlPC90ZXh0PjxnIGZpbGw9Im5vbmUiPjxjaXJjbGUgY3g9IjE2NiIgY3k9IjUwIiByPSIyMiIgc3Ryb2tlPSJoc2woMjMwLDIxJSwxMSUpIiBzdHJva2Utd2lkdGg9IjEwIi8+PGNpcmNsZSBjeD0iMTY2IiBjeT0iNTAiIHBhdGhMZW5ndGg9IjEwMDAwIiByPSIyMiIgc3Ryb2tlPSJoc2woNjEsODglLDQwJSkiIHN0cm9rZS1kYXNoYXJyYXk9IjEwMDAwIiBzdHJva2UtZGFzaG9mZnNldD0iNzUwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2Utd2lkdGg9IjUiIHRyYW5zZm9ybT0icm90YXRlKC05MCkiIHRyYW5zZm9ybS1vcmlnaW49IjE2NiA1MCIvPjwvZz48L2c+PGcgaWQ9IlN0YXR1cyIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE4NCIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPlN0YXR1czwvdGV4dD48dGV4dCB4PSIyMCIgeT0iNzIiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyNnB4Ij5TdHJlYW1pbmc8L3RleHQ+PC9nPjxnIGlkPSJBbW91bnQiIGZpbGw9IiNmZmYiPjxyZWN0IHdpZHRoPSIxMjAiIGhlaWdodD0iMTAwIiBmaWxsLW9wYWNpdHk9Ii4wMyIgcng9IjE1IiByeT0iMTUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLW9wYWNpdHk9Ii4xIiBzdHJva2Utd2lkdGg9IjQiLz48dGV4dCB4PSIyMCIgeT0iMzQiIGZvbnQtZmFtaWx5PSInQ291cmllciBOZXcnLEFyaWFsLG1vbm9zcGFjZSIgZm9udC1zaXplPSIyMnB4Ij5BbW91bnQ8L3RleHQ+PHRleHQgeD0iMjAiIHk9IjcyIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZvbnQtc2l6ZT0iMjZweCI+JiM4ODA1OyAxMEs8L3RleHQ+PC9nPjxnIGlkPSJEdXJhdGlvbiIgZmlsbD0iI2ZmZiI+PHJlY3Qgd2lkdGg9IjE1MiIgaGVpZ2h0PSIxMDAiIGZpbGwtb3BhY2l0eT0iLjAzIiByeD0iMTUiIHJ5PSIxNSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utb3BhY2l0eT0iLjEiIHN0cm9rZS13aWR0aD0iNCIvPjx0ZXh0IHg9IjIwIiB5PSIzNCIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjIycHgiPkR1cmF0aW9uPC90ZXh0Pjx0ZXh0IHg9IjIwIiB5PSI3MiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmb250LXNpemU9IjI2cHgiPiZsdDsgMSBEYXk8L3RleHQ+PC9nPjwvZGVmcz48dGV4dCB0ZXh0LXJlbmRlcmluZz0ib3B0aW1pemVTcGVlZCI+PHRleHRQYXRoIHN0YXJ0T2Zmc2V0PSItMTAwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHhkYjI1YTdiNzY4MzExZGUxMjhiYmRhN2I4NDI2YzNmOWM3NGYzMjQwIOKAoiBTYWJsaWVyIFYyIExvY2t1cCBEeW5hbWljPC90ZXh0UGF0aD48dGV4dFBhdGggc3RhcnRPZmZzZXQ9IjAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDAg4oCiIFNhYmxpZXIgVjIgTG9ja3VwIER5bmFtaWM8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iLTUwJSIgaHJlZj0iI0Zsb2F0aW5nVGV4dCIgZmlsbD0iI2ZmZiIgZm9udC1mYW1pbHk9IidDb3VyaWVyIE5ldycsQXJpYWwsbW9ub3NwYWNlIiBmaWxsLW9wYWNpdHk9Ii44IiBmb250LXNpemU9IjI2cHgiPjxhbmltYXRlIGFkZGl0aXZlPSJzdW0iIGF0dHJpYnV0ZU5hbWU9InN0YXJ0T2Zmc2V0IiBiZWdpbj0iMHMiIGR1cj0iNTBzIiBmcm9tPSIwJSIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiIHRvPSIxMDAlIi8+MHgwM2E2YTg0Y2Q3NjJkOTcwN2EyMTYwNWI1NDhhYWFiODkxNTYyYWFiIOKAoiBEQUk8L3RleHRQYXRoPjx0ZXh0UGF0aCBzdGFydE9mZnNldD0iNTAlIiBocmVmPSIjRmxvYXRpbmdUZXh0IiBmaWxsPSIjZmZmIiBmb250LWZhbWlseT0iJ0NvdXJpZXIgTmV3JyxBcmlhbCxtb25vc3BhY2UiIGZpbGwtb3BhY2l0eT0iLjgiIGZvbnQtc2l6ZT0iMjZweCI+PGFuaW1hdGUgYWRkaXRpdmU9InN1bSIgYXR0cmlidXRlTmFtZT0ic3RhcnRPZmZzZXQiIGJlZ2luPSIwcyIgZHVyPSI1MHMiIGZyb209IjAlIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgdG89IjEwMCUiLz4weDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWIg4oCiIERBSTwvdGV4dFBhdGg+PC90ZXh0Pjx1c2UgaHJlZj0iI0dsb3ciIGZpbGwtb3BhY2l0eT0iLjkiLz48dXNlIGhyZWY9IiNHbG93IiB4PSIxMDAwIiB5PSIxMDAwIiBmaWxsLW9wYWNpdHk9Ii45Ii8+PHVzZSBocmVmPSIjTG9nbyIgeD0iMTcwIiB5PSIxNzAiIHRyYW5zZm9ybT0ic2NhbGUoLjYpIi8+PHVzZSBocmVmPSIjSG91cmdsYXNzIiB4PSIxNTAiIHk9IjkwIiB0cmFuc2Zvcm09InJvdGF0ZSgxMCkiIHRyYW5zZm9ybS1vcmlnaW49IjUwMCA1MDAiLz48dXNlIGhyZWY9IiNQcm9ncmVzcyIgeD0iMTQ0IiB5PSI3OTAiLz48dXNlIGhyZWY9IiNTdGF0dXMiIHg9IjM2OCIgeT0iNzkwIi8+PHVzZSBocmVmPSIjQW1vdW50IiB4PSI1NjgiIHk9Ijc5MCIvPjx1c2UgaHJlZj0iI0R1cmF0aW9uIiB4PSI3MDQiIHk9Ijc5MCIvPjwvc3ZnPg=="}'; assertEq(actualDecodedTokenURI, expectedDecodedTokenURI, "decoded token URI"); } diff --git a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol index 3de46aedc..7e98fd725 100644 --- a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol +++ b/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol @@ -30,7 +30,7 @@ abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test, Loc function test_RevertWhen_ProvidedAddressNoCode() external whenCallerAdmin { address eoa = vm.addr({ privateKey: 1 }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_AllowToHookZeroCodeSize.selector, eoa)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_AllowToHookZeroCodeSize.selector, eoa)); lockup.allowToHook(eoa); } @@ -46,7 +46,7 @@ abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test, Loc // Incorrect interface ID. address recipient = address(recipientInterfaceIDIncorrect); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_AllowToHookUnsupportedInterface.selector, recipient) + abi.encodeWithSelector(Errors.SablierLockup_AllowToHookUnsupportedInterface.selector, recipient) ); lockup.allowToHook(recipient); diff --git a/test/core/integration/concrete/lockup/burn/burn.t.sol b/test/core/integration/concrete/lockup/burn/burn.t.sol index 57a12ba57..2a644f1d9 100644 --- a/test/core/integration/concrete/lockup/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup/burn/burn.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; @@ -22,7 +22,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.burn, streamId); + bytes memory callData = abi.encodeCall(ISablierLockup.burn, streamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -33,7 +33,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.burn(nullStreamId); } @@ -52,7 +52,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenStreamHasNotBeenDepleted { vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -63,7 +63,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenStreamHasNotBeenDepleted { vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -74,7 +74,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenStreamHasNotBeenDepleted { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -88,7 +88,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int resetPrank({ msgSender: users.sender }); lockup.cancel(streamId); resetPrank({ msgSender: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotDepleted.selector, streamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, streamId)); lockup.burn(streamId); } @@ -105,7 +105,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test, Lockup_Int givenStreamHasBeenDepleted(streamId) { resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, streamId, users.eve)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, streamId, users.eve)); lockup.burn(streamId); } diff --git a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol index a1fe88a41..52be17fdf 100644 --- a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -19,7 +19,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is } function test_RevertWhen_DelegateCalled() external whenNotDelegateCalled { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.cancelMultiple, (testStreamIds)); + bytes memory callData = abi.encodeCall(ISablierLockup.cancelMultiple, (testStreamIds)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -31,26 +31,26 @@ abstract contract CancelMultiple_Integration_Concrete_Test is function test_RevertGiven_OnlyNull() external whenNotDelegateCalled whenArrayCountNotZero { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.cancelMultiple({ streamIds: Solarray.uint256s(nullStreamId) }); } function test_RevertGiven_SomeNull() external whenNotDelegateCalled whenArrayCountNotZero { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], nullStreamId) }); } function test_RevertGiven_AllStreamsCold() external whenNotDelegateCalled whenArrayCountNotZero givenNoNull { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, testStreamIds[0])); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, testStreamIds[0])); lockup.cancelMultiple({ streamIds: testStreamIds }); } function test_RevertGiven_SomeStreamsCold() external whenNotDelegateCalled whenArrayCountNotZero givenNoNull { uint256 earlyStreamId = createDefaultStreamWithEndTime({ endTime: defaults.CLIFF_TIME() + 1 seconds }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 1 seconds }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, earlyStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, earlyStreamId)); lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], earlyStreamId) }); } @@ -66,9 +66,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.eve) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, testStreamIds[0], users.eve)); lockup.cancelMultiple(testStreamIds); } @@ -85,7 +83,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) + abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, testStreamIds[0], users.recipient) ); lockup.cancelMultiple(testStreamIds); } @@ -105,9 +103,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is // Run the test. uint256[] memory streamIds = Solarray.uint256s(eveStreamId, testStreamIds[0]); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.eve) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, testStreamIds[0], users.eve)); lockup.cancelMultiple(streamIds); } @@ -124,7 +120,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, testStreamIds[0], users.recipient) + abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, testStreamIds[0], users.recipient) ); lockup.cancelMultiple(testStreamIds); } @@ -139,7 +135,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is { uint256 notCancelableStreamId = createDefaultStreamNotCancelable(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotCancelable.selector, notCancelableStreamId) + abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, notCancelableStreamId) ); lockup.cancelMultiple({ streamIds: Solarray.uint256s(notCancelableStreamId) }); } @@ -154,7 +150,7 @@ abstract contract CancelMultiple_Integration_Concrete_Test is { uint256 notCancelableStreamId = createDefaultStreamNotCancelable(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotCancelable.selector, notCancelableStreamId) + abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, notCancelableStreamId) ); lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], notCancelableStreamId) }); } diff --git a/test/core/integration/concrete/lockup/cancel/cancel.t.sol b/test/core/integration/concrete/lockup/cancel/cancel.t.sol index 4f6ba46ec..3f0c208c3 100644 --- a/test/core/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup/cancel/cancel.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -16,34 +16,34 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.cancel, defaultStreamId); + bytes memory callData = abi.encodeCall(ISablierLockup.cancel, defaultStreamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.cancel(nullStreamId); } function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenNotNull givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } function test_RevertGiven_StatusCanceled() external whenNotDelegateCalled givenNotNull givenStreamCold { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamCanceled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamCanceled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } function test_RevertGiven_StatusSettled() external whenNotDelegateCalled givenNotNull givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } @@ -58,9 +58,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.eve) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); lockup.cancel(defaultStreamId); } @@ -76,7 +74,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.recipient) ); lockup.cancel(defaultStreamId); } @@ -89,7 +87,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I whenCallerAuthorized { uint256 streamId = createDefaultStreamNotCancelable(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotCancelable.selector, streamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, streamId)); lockup.cancel(streamId); } @@ -188,9 +186,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I // Expect a revert. vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2Lockup_InvalidHookSelector.selector, address(recipientInvalidSelector) - ) + abi.encodeWithSelector(Errors.SablierLockup_InvalidHookSelector.selector, address(recipientInvalidSelector)) ); // Cancel the stream. @@ -230,7 +226,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test, Cancel_I // Expect a reentrant call to the Lockup contract. vm.expectCall( address(lockup), - abi.encodeCall(ISablierV2Lockup.withdraw, (streamId, address(recipientReentrant), recipientAmount)) + abi.encodeCall(ISablierLockup.withdraw, (streamId, address(recipientReentrant), recipientAmount)) ); // Cancel the stream. diff --git a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol index ac0dc7346..0408616fb 100644 --- a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol +++ b/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol @@ -13,7 +13,7 @@ abstract contract GetAsset_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getAsset(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol index 053daa048..f7a7c9b7f 100644 --- a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol @@ -11,7 +11,7 @@ abstract contract GetDepositedAmount_Integration_Concrete_Test is Integration_Te function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getDepositedAmount(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol index ccfe7d643..9b11af5b6 100644 --- a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol +++ b/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol @@ -11,7 +11,7 @@ abstract contract GetEndTime_Integration_Concrete_Test is Integration_Test, Lock function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getEndTime(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol index bf8632a74..101eb4a33 100644 --- a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol @@ -13,7 +13,7 @@ abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Tes function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getRefundedAmount(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol index d8cf16469..7e61d92af 100644 --- a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol +++ b/test/core/integration/concrete/lockup/get-sender/getSender.t.sol @@ -11,7 +11,7 @@ abstract contract GetSender_Integration_Concrete_Test is Integration_Test, Locku function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getSender(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol index 21eabfdfb..e6bea1101 100644 --- a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol +++ b/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol @@ -11,7 +11,7 @@ abstract contract GetStartTime_Integration_Concrete_Test is Integration_Test, Lo function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getStartTime(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol index 61614c844..290adf734 100644 --- a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -16,7 +16,7 @@ abstract contract GetWithdrawnAmount_Integration_Concrete_Test is function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.getWithdrawnAmount(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol index 5cb73a2db..0470a3c03 100644 --- a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol @@ -13,7 +13,7 @@ abstract contract IsCancelable_Integration_Concrete_Test is Integration_Test, Lo function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.isCancelable(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol index 0af6bd4bc..56fa323de 100644 --- a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/core/integration/concrete/lockup/is-cold/isCold.t.sol @@ -13,7 +13,7 @@ abstract contract IsCold_Integration_Concrete_Test is Integration_Test, Lockup_I function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.isCold(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol index 7ea200621..3d4f5d3f2 100644 --- a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol @@ -13,7 +13,7 @@ abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test, Lock function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.isDepleted(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol index 8686ff1c5..5f2903785 100644 --- a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol +++ b/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol @@ -13,7 +13,7 @@ abstract contract IsTransferable_Integration_Concrete_Test is Integration_Test, function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.isTransferable(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol index 3ba90957f..b93d19322 100644 --- a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol @@ -13,7 +13,7 @@ abstract contract IsWarm_Integration_Concrete_Test is Integration_Test, Lockup_I function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.isWarm(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol index 48fbb8057..4f793be49 100644 --- a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol @@ -13,7 +13,7 @@ abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Te function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.refundableAmountOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/renounce/renounce.t.sol b/test/core/integration/concrete/lockup/renounce/renounce.t.sol index ce319d185..07455e437 100644 --- a/test/core/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup/renounce/renounce.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; @@ -15,7 +15,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup } function test_RevertWhen_DelegateCalled() external givenStreamWarm { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.renounce, defaultStreamId); + bytes memory callData = abi.encodeCall(ISablierLockup.renounce, defaultStreamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -26,7 +26,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.renounce(nullStreamId); } @@ -41,20 +41,20 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_StatusDepleted() external whenNotDelegateCalled givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } function test_RevertGiven_StatusCanceled() external whenNotDelegateCalled givenStreamCold { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); lockup.cancel(defaultStreamId); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamCanceled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamCanceled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } function test_RevertGiven_StatusSettled() external whenNotDelegateCalled givenStreamCold { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamSettled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } @@ -72,9 +72,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.eve) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); lockup.renounce(defaultStreamId); } @@ -88,7 +86,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test, Lockup // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_StreamNotCancelable.selector, notCancelableStreamId) + abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, notCancelableStreamId) ); lockup.renounce(notCancelableStreamId); } diff --git a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol index 0b7a57f7a..6dfc95d22 100644 --- a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; import { Errors } from "src/core/libraries/Errors.sol"; -import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; import { Lockup_Integration_Shared_Test } from "../../../shared/lockup/Lockup.t.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -21,7 +21,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test // Run the test. vm.expectRevert(abi.encodeWithSelector(Errors.CallerNotAdmin.selector, users.admin, users.eve)); - lockup.setNFTDescriptor(ISablierV2NFTDescriptor(users.eve)); + lockup.setNFTDescriptor(ILockupNFTDescriptor(users.eve)); } modifier whenCallerAdmin() { @@ -41,13 +41,13 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test lockup.setNFTDescriptor(nftDescriptor); // Assert that the new NFT descriptor has been set. - vm.expectCall(address(nftDescriptor), abi.encodeCall(ISablierV2NFTDescriptor.tokenURI, (lockup, 1))); + vm.expectCall(address(nftDescriptor), abi.encodeCall(ILockupNFTDescriptor.tokenURI, (lockup, 1))); lockup.tokenURI({ tokenId: defaultStreamId }); } function test_SetNFTDescriptor_NewNFTDescriptor() external whenCallerAdmin { // Deploy another NFT descriptor. - ISablierV2NFTDescriptor newNFTDescriptor = new SablierV2NFTDescriptor(); + ILockupNFTDescriptor newNFTDescriptor = new LockupNFTDescriptor(); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -59,7 +59,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test lockup.setNFTDescriptor(newNFTDescriptor); // Assert that the new NFT descriptor has been set. - vm.expectCall(address(newNFTDescriptor), abi.encodeCall(ISablierV2NFTDescriptor.tokenURI, (lockup, 1))); + vm.expectCall(address(newNFTDescriptor), abi.encodeCall(ILockupNFTDescriptor.tokenURI, (lockup, 1))); lockup.tokenURI({ tokenId: defaultStreamId }); } } diff --git a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol index c426e86fa..5adeff749 100644 --- a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup/status-of/statusOf.t.sol @@ -14,7 +14,7 @@ abstract contract StatusOf_Integration_Concrete_Test is Integration_Test, Lockup function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.statusOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol index 3fc0557ec..54453db08 100644 --- a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol @@ -16,7 +16,7 @@ abstract contract StreamedAmountOf_Integration_Concrete_Test is function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.streamedAmountOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol index 3a48922a6..1b7b83156 100644 --- a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol @@ -13,9 +13,7 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test, Lo function test_RevertGiven_StreamNotTransferable() external { uint256 notTransferableStreamId = createDefaultStreamNotTransferable(); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_NotTransferable.selector, notTransferableStreamId)); lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: notTransferableStreamId }); } diff --git a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol index 9875a113d..ff110959d 100644 --- a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol +++ b/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol @@ -13,7 +13,7 @@ abstract contract WasCanceled_Integration_Concrete_Test is Integration_Test, Loc function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.wasCanceled(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 1430c679b..969039f9a 100644 --- a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { WithdrawMaxAndTransfer_Integration_Shared_Test } from "../../../shared/lockup/withdrawMaxAndTransfer.t.sol"; @@ -16,14 +16,14 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.withdrawMaxAndTransfer, (defaultStreamId, users.alice)); + bytes memory callData = abi.encodeCall(ISablierLockup.withdrawMaxAndTransfer, (defaultStreamId, users.alice)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient }); } @@ -32,9 +32,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.eve) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.eve }); } @@ -48,7 +46,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.recipient) ); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.alice }); } @@ -74,9 +72,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is givenWithdrawableAmountNotZero { uint256 notTransferableStreamId = createDefaultStreamNotTransferable(); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_NotTransferable.selector, notTransferableStreamId) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_NotTransferable.selector, notTransferableStreamId)); lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient }); } diff --git a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol index f49c86a23..31dd039a8 100644 --- a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -19,7 +19,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is } function test_RevertWhen_DelegateCalled() external { - bytes memory callData = abi.encodeCall(ISablierV2Lockup.withdrawMultiple, (testStreamIds, testAmounts)); + bytes memory callData = abi.encodeCall(ISablierLockup.withdrawMultiple, (testStreamIds, testAmounts)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -29,7 +29,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is uint128[] memory amounts = new uint128[](1); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_WithdrawArrayCountsNotEqual.selector, streamIds.length, amounts.length + Errors.SablierLockup_WithdrawArrayCountsNotEqual.selector, streamIds.length, amounts.length ) ); lockup.withdrawMultiple(streamIds, amounts); @@ -57,7 +57,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is { uint256 nullStreamId = 1729; uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.withdrawMultiple({ streamIds: Solarray.uint256s(nullStreamId), amounts: Solarray.uint128s(withdrawAmount) @@ -77,7 +77,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Expect the relevant error to be thrown. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); // Withdraw from multiple streams. lockup.withdrawMultiple({ streamIds: streamIds, amounts: testAmounts }); @@ -100,7 +100,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); // Expect the relevant error to be thrown. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, testStreamIds[0])); // Withdraw from multiple streams. lockup.withdrawMultiple(streamIds, amounts); @@ -120,7 +120,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); // Expect the relevant error to be thrown. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, testStreamIds[0])); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, testStreamIds[0])); // Withdraw from multiple streams. lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: testAmounts }); @@ -140,7 +140,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is // Run the test. uint128[] memory amounts = Solarray.uint128s(defaults.WITHDRAW_AMOUNT(), 0, 0); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, testStreamIds[1])); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawAmountZero.selector, testStreamIds[1])); lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); } @@ -162,7 +162,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is uint128[] memory amounts = Solarray.uint128s(testAmounts[0], testAmounts[1], MAX_UINT128); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_Overdraw.selector, testStreamIds[2], MAX_UINT128, withdrawableAmount + Errors.SablierLockup_Overdraw.selector, testStreamIds[2], MAX_UINT128, withdrawableAmount ) ); lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); diff --git a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol index 4d4247b37..baa108f0a 100644 --- a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -22,7 +22,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_RevertWhen_DelegateCalled() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = - abi.encodeCall(ISablierV2Lockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); + abi.encodeCall(ISablierLockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -30,7 +30,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr function test_RevertGiven_Null() external whenNotDelegateCalled { uint256 nullStreamId = 1729; uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.withdraw({ streamId: nullStreamId, to: users.recipient, amount: withdrawAmount }); } @@ -39,13 +39,13 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } function test_RevertWhen_ToZeroAddress() external whenNotDelegateCalled givenNotNull givenStreamNotDepleted { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawToZeroAddress.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawToZeroAddress.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: address(0), amount: withdrawAmount }); } @@ -56,7 +56,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr givenStreamNotDepleted whenToNonZeroAddress { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_WithdrawAmountZero.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawAmountZero.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); } @@ -71,7 +71,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawableAmount = 0; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount + Errors.SablierLockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount ) ); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); @@ -95,7 +95,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, + Errors.SablierLockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, unknownCaller, unknownCaller @@ -120,10 +120,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, - defaultStreamId, - users.sender, - users.sender + Errors.SablierLockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, users.sender, users.sender ) ); lockup.withdraw({ streamId: defaultStreamId, to: users.sender, amount: withdrawAmount }); @@ -145,7 +142,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2Lockup_WithdrawalAddressNotRecipient.selector, + Errors.SablierLockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, users.recipient, users.recipient @@ -424,9 +421,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test, Withdr // Expect a revert. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2Lockup_InvalidHookSelector.selector, address(recipientInvalidSelector) - ) + abi.encodeWithSelector(Errors.SablierLockup_InvalidHookSelector.selector, address(recipientInvalidSelector)) ); // Cancel the stream. diff --git a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol index bdccef21b..529ff8be9 100644 --- a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -16,7 +16,7 @@ abstract contract WithdrawableAmountOf_Integration_Concrete_Test is function test_RevertGiven_Null() external { uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2Lockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); lockup.withdrawableAmountOf(nullStreamId); } diff --git a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol index 6e2e65231..e9b801222 100644 --- a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -5,7 +5,7 @@ import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descript contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { function test_GenerateAccentColor() external view { - // Passing a dummy contract instead of a real Sablier contract to make this test easy to maintain. + // Passing a dummy contract instead of a real Lockup contract to make this test easy to maintain. // Note: the address of `noop` depends on the order of the state variables in {Base_Test}. string memory actualColor = nftDescriptorMock.generateAccentColor_({ sablier: address(noop), streamId: 1337 }); string memory expectedColor = "hsl(182,56%,46%)"; diff --git a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol index 7f201dc66..5256a1892 100644 --- a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol +++ b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.t.sol @@ -12,7 +12,7 @@ contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared function test_RevertGiven_UnknownNFT() external { MockERC721 nft = new MockERC721(); nft.initialize("Foo", "FOO"); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2NFTDescriptor_UnknownNFT.selector, nft, "FOO")); + vm.expectRevert(abi.encodeWithSelector(Errors.LockupNFTDescriptor_UnknownNFT.selector, nft, "FOO")); nftDescriptorMock.mapSymbol_(IERC721Metadata(address(nft))); } @@ -21,20 +21,20 @@ contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared } function test_MapSymbol_LockupDynamic() external view givenKnownNFT { - string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupDynamic); - string memory expectedSablierModel = "Lockup Dynamic"; - assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); + string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupDynamic); + string memory expectedLockupModel = "Sablier Lockup Dynamic"; + assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); } function test_MapSymbol_LockupLinear() external view givenKnownNFT { - string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupLinear); - string memory expectedSablierModel = "Lockup Linear"; - assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); + string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupLinear); + string memory expectedLockupModel = "Sablier Lockup Linear"; + assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); } function test_MapSymbol_LockupTranched() external view givenKnownNFT { - string memory actualSablierModel = nftDescriptorMock.mapSymbol_(lockupTranched); - string memory expectedSablierModel = "Lockup Tranched"; - assertEq(actualSablierModel, expectedSablierModel, "sablierModel"); + string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupTranched); + string memory expectedLockupModel = "Sablier Lockup Tranched"; + assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index 1d21f46be..12aac9929 100644 --- a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupDynamic_Integration_Shared_Test } from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -17,7 +17,7 @@ import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultip NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupDynamic} integration fuzz tests. +/// @notice Common testing logic needed across {SablierLockupDynamic} integration fuzz tests. abstract contract LockupDynamic_Integration_Fuzz_Test is Integration_Test, LockupDynamic_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, LockupDynamic_Integration_Shared_Test) { // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is @@ -25,8 +25,8 @@ abstract contract LockupDynamic_Integration_Fuzz_Test is Integration_Test, Locku Integration_Test.setUp(); LockupDynamic_Integration_Shared_Test.setUp(); - // Cast the LockupDynamic contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupDynamic); + // Cast the LockupDynamic contract as {ISablierLockup}. + lockup = ISablierLockup(lockupDynamic); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index 4dc092c94..d0c784587 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -56,7 +56,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); - // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. expectCallToTransferFrom({ from: vars.funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index c715db7bd..a02b469d4 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -33,9 +33,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is uint256 defaultMax = defaults.MAX_SEGMENT_COUNT(); segmentCount = _bound(segmentCount, defaultMax + 1, defaultMax * 2); LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2LockupDynamic_SegmentCountTooHigh.selector, segmentCount) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupDynamic_SegmentCountTooHigh.selector, segmentCount)); createDefaultStreamWithSegments(segments); } @@ -77,7 +75,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) @@ -114,7 +112,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) @@ -140,7 +138,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(broker); } @@ -211,10 +209,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierV2LockupDynamic} to transfer the assets from the fuzzed funder. + // Approve {SablierLockupDynamic} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierV2LockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. diff --git a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol index 2ad974487..9590d9f2a 100644 --- a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupLinear_Integration_Shared_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -18,7 +18,7 @@ import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultip NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupLinear} integration fuzz tests. +/// @notice Common testing logic needed across {SablierLockupLinear} integration fuzz tests. abstract contract LockupLinear_Integration_Fuzz_Test is Integration_Test, LockupLinear_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, LockupLinear_Integration_Shared_Test) { // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is @@ -26,8 +26,8 @@ abstract contract LockupLinear_Integration_Fuzz_Test is Integration_Test, Lockup Integration_Test.setUp(); LockupLinear_Integration_Shared_Test.setUp(); - // Cast the lockupLinear contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupLinear); + // Cast the lockupLinear contract as {ISablierLockup}. + lockup = ISablierLockup(lockupLinear); } } diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol index 8a0900bb4..e0235e110 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -39,9 +39,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime - ) + abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); // Create the stream. @@ -60,7 +58,7 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is // Make the Sender the stream's funder (recall that the Sender is the default caller). address funder = users.sender; - // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockupLinear}. expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 8f46bdebb..1e9aa108b 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -31,7 +31,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(broker); } @@ -45,7 +45,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is startTime = boundUint40(startTime, defaults.CLIFF_TIME() + 1 seconds, defaults.END_TIME() - 1 seconds); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() + Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() ) ); createDefaultStreamWithStartTime(startTime); @@ -65,9 +65,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is cliffTime = boundUint40(cliffTime, endTime, MAX_UNIX_TIMESTAMP); vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierV2LockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime - ) + abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } @@ -139,10 +137,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is // Mint enough assets to the funder. deal({ token: address(dai), to: funder, give: params.totalAmount }); - // Approve {SablierV2LockupLinear} to transfer the assets from the fuzzed funder. + // Approve {SablierLockupLinear} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierV2LockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockupLinear}. expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. diff --git a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol index 3b9d4565b..d1a7e7205 100644 --- a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupTranched_Integration_Shared_Test } from "../../shared/lockup-tranched/LockupTranched.t.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -17,7 +17,7 @@ import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultip NON-SHARED ABSTRACT TEST //////////////////////////////////////////////////////////////////////////*/ -/// @notice Common testing logic needed across {SablierV2LockupTranched} integration fuzz tests. +/// @notice Common testing logic needed across {SablierLockupTranched} integration fuzz tests. abstract contract LockupTranched_Integration_Fuzz_Test is Integration_Test, LockupTranched_Integration_Shared_Test { function setUp() public virtual override(Integration_Test, LockupTranched_Integration_Shared_Test) { // Both of these contracts inherit from {Base_Test}, which is fine because multiple inheritance is @@ -25,8 +25,8 @@ abstract contract LockupTranched_Integration_Fuzz_Test is Integration_Test, Lock Integration_Test.setUp(); LockupTranched_Integration_Shared_Test.setUp(); - // Cast the LockupTranched contract as {ISablierV2Lockup}. - lockup = ISablierV2Lockup(lockupTranched); + // Cast the LockupTranched contract as {ISablierLockup}. + lockup = ISablierLockup(lockupTranched); } } diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol index 1c4396ea5..a94710783 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -56,7 +56,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); - // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockupTranched}. expectCallToTransferFrom({ from: vars.funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 308768340..c4c8162c7 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -33,9 +33,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is uint256 defaultMax = defaults.MAX_TRANCHE_COUNT(); trancheCount = _bound(trancheCount, defaultMax + 1, defaultMax * 10); LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2LockupTranched_TrancheCountTooHigh.selector, trancheCount) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupTranched_TrancheCountTooHigh.selector, trancheCount)); createDefaultStreamWithTranches(tranches); } @@ -77,7 +75,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) @@ -114,7 +112,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2LockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + Errors.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, depositAmount, defaultDepositAmount ) @@ -140,7 +138,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2Lockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); createDefaultStreamWithBroker(broker); } @@ -212,10 +210,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierV2LockupTranched} to transfer the assets from the fuzzed funder. + // Approve {SablierLockupTranched} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierV2LockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockupTranched}. expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. diff --git a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol index a74578e03..7df0dd617 100644 --- a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -7,7 +7,7 @@ import { Broker, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; -/// @notice Common testing logic needed across {SablierV2LockupDynamic} integration tests. +/// @notice Common testing logic needed across {SablierLockupDynamic} integration tests. abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Shared_Test { struct CreateParams { LockupDynamic.CreateWithDurations createWithDurations; diff --git a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol index 2e5451cc8..8daeccb39 100644 --- a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol @@ -7,7 +7,7 @@ import { Broker, LockupLinear } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; -/// @notice Common testing logic needed by all {SablierV2LockupLinear} integration tests. +/// @notice Common testing logic needed by all {SablierLockupLinear} integration tests. abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Shared_Test { struct Params { LockupLinear.CreateWithDurations createWithDurations; diff --git a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol index 81213515a..5f18265c7 100644 --- a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -7,7 +7,7 @@ import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; import { Lockup_Integration_Shared_Test } from "../lockup/Lockup.t.sol"; -/// @notice Common testing logic needed across {SablierV2LockupTranched} integration tests. +/// @notice Common testing logic needed across {SablierLockupTranched} integration tests. abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_Shared_Test { struct CreateParams { LockupTranched.CreateWithDurations createWithDurations; diff --git a/test/core/integration/shared/lockup/Lockup.t.sol b/test/core/integration/shared/lockup/Lockup.t.sol index 1600c47cc..700c7f9a3 100644 --- a/test/core/integration/shared/lockup/Lockup.t.sol +++ b/test/core/integration/shared/lockup/Lockup.t.sol @@ -3,21 +3,21 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Broker } from "src/core/types/DataTypes.sol"; import { Base_Test } from "test/Base.t.sol"; -/// @dev This contracts avoids duplicating test logic for {SablierV2LockupLinear} and {SablierV2LockupDynamic}; -/// both of these contracts inherit from {SablierV2Lockup}. +/// @dev This contracts avoids duplicating test logic for {SablierLockupLinear} and {SablierLockupDynamic}; +/// both of these contracts inherit from {SablierLockup}. abstract contract Lockup_Integration_Shared_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ /// @dev A test contract that is meant to be overridden by the implementing contract, which will be - /// either {SablierV2LockupLinear} or {SablierV2LockupDynamic}. - ISablierV2Lockup internal lockup; + /// either {SablierLockupLinear} or {SablierLockupDynamic}. + ISablierLockup internal lockup; /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION diff --git a/test/core/invariant/Lockup.t.sol b/test/core/invariant/Lockup.t.sol index f4df1aad5..54ae5801f 100644 --- a/test/core/invariant/Lockup.t.sol +++ b/test/core/invariant/Lockup.t.sol @@ -1,20 +1,20 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Invariant_Test } from "./Invariant.t.sol"; import { LockupHandler } from "./handlers/LockupHandler.sol"; import { LockupStore } from "./stores/LockupStore.sol"; -/// @notice Common invariant test logic needed across contracts that inherit from {SablierV2Lockup}. +/// @notice Common invariant test logic needed across contracts that inherit from {SablierLockup}. abstract contract Lockup_Invariant_Test is Invariant_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2Lockup internal lockup; + ISablierLockup internal lockup; LockupHandler internal lockupHandler; LockupStore internal lockupStore; diff --git a/test/core/invariant/LockupDynamic.t.sol b/test/core/invariant/LockupDynamic.t.sol index 6a3550a35..fdfe4445e 100644 --- a/test/core/invariant/LockupDynamic.t.sol +++ b/test/core/invariant/LockupDynamic.t.sol @@ -7,7 +7,7 @@ import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupDynamicCreateHandler } from "./handlers/LockupDynamicCreateHandler.sol"; import { LockupDynamicHandler } from "./handlers/LockupDynamicHandler.sol"; -/// @dev Invariant tests for {SablierV2LockupDynamic}. +/// @dev Invariant tests for {SablierLockupDynamic}. contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS @@ -64,7 +64,7 @@ contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { } } - /// @dev Settled streams must not appear as cancelable in {SablierV2LockupDynamic.getStream}. + /// @dev Settled streams must not appear as cancelable in {SablierLockupDynamic.getStream}. function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { diff --git a/test/core/invariant/LockupLinear.t.sol b/test/core/invariant/LockupLinear.t.sol index cf96445ae..37fbc3374 100644 --- a/test/core/invariant/LockupLinear.t.sol +++ b/test/core/invariant/LockupLinear.t.sol @@ -7,7 +7,7 @@ import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupLinearHandler } from "./handlers/LockupLinearHandler.sol"; import { LockupLinearCreateHandler } from "./handlers/LockupLinearCreateHandler.sol"; -/// @dev Invariant tests for {SablierV2LockupLinear}. +/// @dev Invariant tests for {SablierLockupLinear}. contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS @@ -33,7 +33,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { vm.label({ account: address(lockupLinearHandler), newLabel: "LockupLinearHandler" }); vm.label({ account: address(lockupLinearCreateHandler), newLabel: "LockupLinearCreateHandler" }); - // Cast the lockupLinear contract as {ISablierV2Lockup} and the lockupLinear handler as {LockupHandler}. + // Cast the lockupLinear contract as {ISablierLockup} and the lockupLinear handler as {LockupHandler}. lockup = lockupLinear; lockupHandler = lockupLinearHandler; @@ -78,7 +78,7 @@ contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { } } - /// @dev Settled streams must not appear as cancelable in {SablierV2LockupLinear.getStream}. + /// @dev Settled streams must not appear as cancelable in {SablierLockupLinear.getStream}. function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { diff --git a/test/core/invariant/LockupTranched.t.sol b/test/core/invariant/LockupTranched.t.sol index 586516132..1e5d2e207 100644 --- a/test/core/invariant/LockupTranched.t.sol +++ b/test/core/invariant/LockupTranched.t.sol @@ -7,7 +7,7 @@ import { Lockup_Invariant_Test } from "./Lockup.t.sol"; import { LockupTranchedCreateHandler } from "./handlers/LockupTranchedCreateHandler.sol"; import { LockupTranchedHandler } from "./handlers/LockupTranchedHandler.sol"; -/// @dev Invariant tests for {SablierV2LockupTranched}. +/// @dev Invariant tests for {SablierLockupTranched}. contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS @@ -50,7 +50,7 @@ contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { INVARIANTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Settled streams must not appear as cancelable in {SablierV2LockupTranched.getStream}. + /// @dev Settled streams must not appear as cancelable in {SablierLockupTranched.getStream}. function invariant_StatusSettled_GetStream() external view { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { diff --git a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol index 5206a7a85..6a762123d 100644 --- a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol @@ -3,28 +3,27 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; import { LockupDynamic } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; -/// @dev This contract is a complement of {LockupDynamicHandler}. The goal is to bias the invariant calls -/// toward the lockup functions (especially the create stream functions) by creating multiple handlers for -/// the lockup contracts. +/// @dev This contract is a complement of {LockupDynamicHandler}. The goal is to bias the invariant calls toward the +/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. contract LockupDynamicCreateHandler is BaseHandler { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2LockupDynamic public lockupDynamic; + ISablierLockupDynamic public lockupDynamic; LockupStore public lockupStore; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2LockupDynamic lockupDynamic_) BaseHandler(asset_) { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupDynamic lockupDynamic_) BaseHandler(asset_) { lockupStore = lockupStore_; lockupDynamic = lockupDynamic_; } @@ -69,7 +68,7 @@ contract LockupDynamicCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupDynamic} to spend the assets. + // Approve {SablierLockupDynamic} to spend the assets. asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); // Create the stream. @@ -116,7 +115,7 @@ contract LockupDynamicCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupDynamic} to spend the assets. + // Approve {SablierLockupDynamic} to spend the assets. asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); // Create the stream. diff --git a/test/core/invariant/handlers/LockupDynamicHandler.sol b/test/core/invariant/handlers/LockupDynamicHandler.sol index 5d60b6528..0e9a2b9fc 100644 --- a/test/core/invariant/handlers/LockupDynamicHandler.sol +++ b/test/core/invariant/handlers/LockupDynamicHandler.sol @@ -3,18 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupDynamic} is exposed to Foundry for invariant testing. The goal is +/// @dev This contract and not {SablierLockupDynamic} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupDynamicHandler is LockupHandler { constructor( IERC20 asset_, LockupStore lockupStore_, - ISablierV2LockupDynamic lockupDynamic_ + ISablierLockupDynamic lockupDynamic_ ) LockupHandler(asset_, lockupStore_, lockupDynamic_) { } diff --git a/test/core/invariant/handlers/LockupHandler.sol b/test/core/invariant/handlers/LockupHandler.sol index 1f46c404e..1bff8fd4f 100644 --- a/test/core/invariant/handlers/LockupHandler.sol +++ b/test/core/invariant/handlers/LockupHandler.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; @@ -15,7 +15,7 @@ abstract contract LockupHandler is BaseHandler { TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2Lockup public lockup; + ISablierLockup public lockup; LockupStore public lockupStore; /*////////////////////////////////////////////////////////////////////////// @@ -30,7 +30,7 @@ abstract contract LockupHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2Lockup lockup_) BaseHandler(asset_) { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_) { lockupStore = lockupStore_; lockup = lockup_; } @@ -72,7 +72,7 @@ abstract contract LockupHandler is BaseHandler { } /*////////////////////////////////////////////////////////////////////////// - SABLIER-V2-LOCKUP + SABLIER-LOCKUP //////////////////////////////////////////////////////////////////////////*/ function burn( diff --git a/test/core/invariant/handlers/LockupLinearCreateHandler.sol b/test/core/invariant/handlers/LockupLinearCreateHandler.sol index 1086cd5e2..09c383814 100644 --- a/test/core/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/core/invariant/handlers/LockupLinearCreateHandler.sol @@ -3,28 +3,27 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; import { LockupLinear } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; -/// @dev This contract is a complement of {LockupLinearHandler}. The goal is to bias the invariant calls -/// toward the lockup functions (especially the create stream functions) by creating multiple handlers for -/// the lockup contracts. +/// @dev This contract is a complement of {LockupLinearHandler}. The goal is to bias the invariant calls toward the +/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. contract LockupLinearCreateHandler is BaseHandler { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierV2LockupLinear public lockupLinear; + ISablierLockupLinear public lockupLinear; LockupStore public lockupStore; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierV2LockupLinear lockupLinear_) BaseHandler(asset_) { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupLinear lockupLinear_) BaseHandler(asset_) { lockupStore = lockupStore_; lockupLinear = lockupLinear_; } @@ -58,7 +57,7 @@ contract LockupLinearCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupLinear} to spend the assets. + // Approve {SablierLockupLinear} to spend the assets. asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); // Create the stream. @@ -103,7 +102,7 @@ contract LockupLinearCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupLinear} to spend the assets. + // Approve {SablierLockupLinear} to spend the assets. asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); // Create the stream. diff --git a/test/core/invariant/handlers/LockupLinearHandler.sol b/test/core/invariant/handlers/LockupLinearHandler.sol index 4e54aea47..075effb8c 100644 --- a/test/core/invariant/handlers/LockupLinearHandler.sol +++ b/test/core/invariant/handlers/LockupLinearHandler.sol @@ -3,18 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupLinear} is exposed to Foundry for invariant testing. The goal is +/// @dev This contract and not {SablierLockupLinear} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupLinearHandler is LockupHandler { constructor( IERC20 asset_, LockupStore lockupStore_, - ISablierV2LockupLinear lockupLinear_ + ISablierLockupLinear lockupLinear_ ) LockupHandler(asset_, lockupStore_, lockupLinear_) { } diff --git a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol index 618f86473..b6c40ba46 100644 --- a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol @@ -3,34 +3,27 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { LockupTranched } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; -/// @dev This contract is a complement of {LockupTranchedHandler}. The goal is to bias the invariant calls -/// toward the lockup functions (especially the create stream functions) by creating multiple handlers for -/// the lockup contracts. +/// @dev This contract is a complement of {LockupTranchedHandler}. The goal is to bias the invariant calls toward the +/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. contract LockupTranchedCreateHandler is BaseHandler { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ LockupStore public lockupStore; - ISablierV2LockupTranched public lockupTranched; + ISablierLockupTranched public lockupTranched; /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor( - IERC20 asset_, - LockupStore lockupStore_, - ISablierV2LockupTranched lockupTranched_ - ) - BaseHandler(asset_) - { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupTranched lockupTranched_) BaseHandler(asset_) { lockupStore = lockupStore_; lockupTranched = lockupTranched_; } @@ -75,7 +68,7 @@ contract LockupTranchedCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupTranched} to spend the assets. + // Approve {SablierLockupTranched} to spend the assets. asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); // Create the stream. @@ -122,7 +115,7 @@ contract LockupTranchedCreateHandler is BaseHandler { // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - // Approve {SablierV2LockupTranched} to spend the assets. + // Approve {SablierLockupTranched} to spend the assets. asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); // Create the stream. diff --git a/test/core/invariant/handlers/LockupTranchedHandler.sol b/test/core/invariant/handlers/LockupTranchedHandler.sol index 59887c84c..bb0c9f26b 100644 --- a/test/core/invariant/handlers/LockupTranchedHandler.sol +++ b/test/core/invariant/handlers/LockupTranchedHandler.sol @@ -3,18 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { LockupHandler } from "./LockupHandler.sol"; -/// @dev This contract and not {SablierV2LockupTranched} is exposed to Foundry for invariant testing. The goal is +/// @dev This contract and not {SablierLockupTranched} is exposed to Foundry for invariant testing. The goal is /// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. contract LockupTranchedHandler is LockupHandler { constructor( IERC20 asset_, LockupStore lockupStore_, - ISablierV2LockupTranched lockupTranched_ + ISablierLockupTranched lockupTranched_ ) LockupHandler(asset_, lockupStore_, lockupTranched_) { } diff --git a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol index bddd59d4b..4d08e0e35 100644 --- a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol +++ b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; import { NFTDescriptorMock } from "test/mocks/NFTDescriptorMock.sol"; import { Base_Test } from "test/Base.t.sol"; -contract NFTDescriptor_Unit_Concrete_Test is Base_Test, SablierV2NFTDescriptor { +contract NFTDescriptor_Unit_Concrete_Test is Base_Test, LockupNFTDescriptor { NFTDescriptorMock internal nftDescriptorMock; function setUp() public virtual override { diff --git a/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol index cb5f6ecbf..aed691410 100644 --- a/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -13,7 +13,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T function test_GenerateDescription_Empty() external view { string memory actualDescription = nftDescriptorMock.generateDescription_("", "", "", "", "", true); string memory expectedDescription = string.concat( - "This NFT represents a payment stream in a Sablier V2 ", + "This NFT represents a payment stream in a Sablier Lockup ", " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", ".\\n\\n", "- Stream ID: ", @@ -37,7 +37,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T false ); string memory expectedDescription = string.concat( - "This NFT represents a payment stream in a Sablier V2 ", + "This NFT represents a payment stream in a Sablier Lockup ", "Lockup Linear", " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", dai.symbol(), @@ -68,7 +68,7 @@ contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_T true ); string memory expectedDescription = string.concat( - "This NFT represents a payment stream in a Sablier V2 ", + "This NFT represents a payment stream in a Sablier Lockup ", "Lockup Linear", " contract. The owner of this NFT can withdraw the streamed assets, which are denominated in ", dai.symbol(), diff --git a/test/core/unit/concrete/nft-descriptor/generateName.t.sol b/test/core/unit/concrete/nft-descriptor/generateName.t.sol index 3efedc0e5..c5b5b0742 100644 --- a/test/core/unit/concrete/nft-descriptor/generateName.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateName.t.sol @@ -4,22 +4,22 @@ pragma solidity >=0.8.22 <0.9.0; import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; contract GenerateName_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { - function gn(string memory sablierModel, string memory streamId) internal view returns (string memory) { - return nftDescriptorMock.generateName_(sablierModel, streamId); + function gn(string memory lockupModel, string memory streamId) internal view returns (string memory) { + return nftDescriptorMock.generateName_(lockupModel, streamId); } function dyn(string memory streamId) internal pure returns (string memory) { - return string.concat("Sablier V2 Lockup Dynamic #", streamId); + return string.concat("Sablier Lockup Dynamic #", streamId); } function lin(string memory streamId) internal pure returns (string memory) { - return string.concat("Sablier V2 Lockup Linear #", streamId); + return string.concat("Sablier Lockup Linear #", streamId); } function test_GenerateName_Empty() external view { - assertEq(gn("", ""), "Sablier V2 #", "metadata name"); - assertEq(gn("A", ""), "Sablier V2 A #", "metadata name"); - assertEq(gn("", "1"), "Sablier V2 #1", "metadata name"); + assertEq(gn("", ""), "Sablier #", "metadata name"); + assertEq(gn("A", ""), "Sablier A #", "metadata name"); + assertEq(gn("", "1"), "Sablier #1", "metadata name"); } function test_GenerateName() external view { diff --git a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol index 74158df39..af141f3ed 100644 --- a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -21,13 +21,13 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { duration: "5 Days", progress: "0%", progressNumerical: 0, - sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - sablierModel: "Lockup Linear", + lockupAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", + lockupModel: "Lockup Linear", status: "Pending" }) ); string memory expectedSVG = - unicode'Progress0%StatusPendingAmount100Duration5 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; + unicode'Progress0%StatusPendingAmount100Duration5 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; assertEq(actualSVG, expectedSVG, "SVG mismatch"); } @@ -41,13 +41,13 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { duration: "91 Days", progress: "42.35%", progressNumerical: 4235, - sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - sablierModel: "Lockup Linear", + lockupAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", + lockupModel: "Lockup Linear", status: "Streaming" }) ); string memory expectedSVG = - unicode'Progress42.35%StatusStreamingAmount≥ 1.23MDuration91 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; + unicode'Progress42.35%StatusStreamingAmount≥ 1.23MDuration91 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; assertEq(actualSVG, expectedSVG, "SVG mismatch"); } @@ -61,13 +61,13 @@ contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { duration: "5 Days", progress: "100%", progressNumerical: 100, - sablierAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", - sablierModel: "Lockup Linear", + lockupAddress: "0xf3a045dc986015be9ae43bb3462ae5981b0816e0", + lockupModel: "Lockup Linear", status: "Depleted" }) ); string memory expectedSVG = - unicode'Progress100%StatusDepletedAmount100Duration5 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier V2 Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; + unicode'Progress100%StatusDepletedAmount100Duration5 Days0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0xf3a045dc986015be9ae43bb3462ae5981b0816e0 • Sablier Lockup Linear0x03a6a84cd762d9707a21605b548aaab891562aab • DAI0x03a6a84cd762d9707a21605b548aaab891562aab • DAI'; assertEq(actualSVG, expectedSVG, "SVG mismatch"); } } diff --git a/test/mocks/Hooks.sol b/test/mocks/Hooks.sol index 9e8235b16..6b7e1981a 100644 --- a/test/mocks/Hooks.sol +++ b/test/mocks/Hooks.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22; import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; -import { ISablierV2Lockup } from "src/core/interfaces/ISablierV2Lockup.sol"; contract RecipientGood is ISablierLockupRecipient, ERC165 { function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { @@ -138,7 +138,7 @@ contract RecipientReentrant is ISablierLockupRecipient, ERC165 { senderAmount; recipientAmount; - ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), recipientAmount); + ISablierLockup(msg.sender).withdraw(streamId, address(this), recipientAmount); return ISablierLockupRecipient.onSablierLockupCancel.selector; } @@ -158,7 +158,7 @@ contract RecipientReentrant is ISablierLockupRecipient, ERC165 { to; amount; - ISablierV2Lockup(msg.sender).withdraw(streamId, address(this), amount); + ISablierLockup(msg.sender).withdraw(streamId, address(this), amount); return ISablierLockupRecipient.onSablierLockupWithdraw.selector; } diff --git a/test/mocks/NFTDescriptorMock.sol b/test/mocks/NFTDescriptorMock.sol index 9192c29b5..3a1ab79c3 100644 --- a/test/mocks/NFTDescriptorMock.sol +++ b/test/mocks/NFTDescriptorMock.sol @@ -6,12 +6,12 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions import { NFTSVG } from "src/core/libraries/NFTSVG.sol"; import { SVGElements } from "src/core/libraries/SVGElements.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { SablierV2NFTDescriptor } from "src/core/SablierV2NFTDescriptor.sol"; +import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; /// @dev This mock is needed for: /// - Running the tests against the `--via-ir` precompiles /// - Testing reverts: https://github.com/foundry-rs/foundry/issues/864 -contract NFTDescriptorMock is SablierV2NFTDescriptor { +contract NFTDescriptorMock is LockupNFTDescriptor { function abbreviateAmount_(uint256 amount, uint256 decimals) external pure returns (string memory) { return abbreviateAmount(amount, decimals); } @@ -52,9 +52,9 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { } function generateDescription_( - string memory sablierModel, + string memory lockupModel, string memory assetSymbol, - string memory sablierAddress, + string memory lockupAddress, string memory assetAddress, string memory streamId, bool isTransferable @@ -63,11 +63,11 @@ contract NFTDescriptorMock is SablierV2NFTDescriptor { pure returns (string memory) { - return generateDescription(sablierModel, assetSymbol, sablierAddress, assetAddress, streamId, isTransferable); + return generateDescription(lockupModel, assetSymbol, lockupAddress, assetAddress, streamId, isTransferable); } - function generateName_(string memory sablierModel, string memory streamId) external pure returns (string memory) { - return generateName(sablierModel, streamId); + function generateName_(string memory lockupModel, string memory streamId) external pure returns (string memory) { + return generateName(lockupModel, streamId); } function generateSVG_(NFTSVG.SVGParams memory params) external pure returns (string memory) { diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 8c6bc43d7..0e2726bdb 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -3,8 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { SablierV2MerkleLL } from "src/periphery/SablierV2MerkleLL.sol"; -import { SablierV2MerkleLT } from "src/periphery/SablierV2MerkleLT.sol"; +import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; +import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { Base_Test } from "../Base.t.sol"; @@ -101,10 +101,9 @@ contract Periphery_Test is Base_Test { bytes memory constructorArgs = abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot), lockupLinear, defaults.durations()); if (!isTestOptimizedProfile()) { - return bytes.concat(type(SablierV2MerkleLL).creationCode, constructorArgs); + return bytes.concat(type(SablierMerkleLL).creationCode, constructorArgs); } else { - return - bytes.concat(vm.getCode("out-optimized/SablierV2MerkleLL.sol/SablierV2MerkleLL.json"), constructorArgs); + return bytes.concat(vm.getCode("out-optimized/SablierMerkleLL.sol/SablierMerkleLL.json"), constructorArgs); } } @@ -124,10 +123,9 @@ contract Periphery_Test is Base_Test { defaults.tranchesWithPercentages() ); if (!isTestOptimizedProfile()) { - return bytes.concat(type(SablierV2MerkleLT).creationCode, constructorArgs); + return bytes.concat(type(SablierMerkleLT).creationCode, constructorArgs); } else { - return - bytes.concat(vm.getCode("out-optimized/SablierV2MerkleLT.sol/SablierV2MerkleLT.json"), constructorArgs); + return bytes.concat(vm.getCode("out-optimized/SablierMerkleLT.sol/SablierMerkleLT.json"), constructorArgs); } } } diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index 4f97e0ebd..c4592c91d 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { Periphery_Test } from "../Periphery.t.sol"; import { Merkle } from "../../utils/Murky.sol"; @@ -62,9 +62,10 @@ abstract contract Fork_Test is Periphery_Test, Merkle { } /// @dev Loads all dependencies pre-deployed on Mainnet. + // TODO: Update address once deployed. function loadDependencies() private { - lockupDynamic = ISablierV2LockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); - lockupLinear = ISablierV2LockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); - lockupTranched = ISablierV2LockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + lockupDynamic = ISablierLockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); + lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); + lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); } } diff --git a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol index 6fd0aac55..9f470a51d 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLL.t.sol @@ -5,7 +5,7 @@ import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; @@ -47,7 +47,8 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { uint256[] indexes; uint256 leafPos; uint256 leafToClaim; - ISablierV2MerkleLL merkleLL; + ISablierMerkleLL merkleLL; + bytes32[] merkleProof; bytes32 merkleRoot; address[] recipients; uint256 recipientCount; @@ -93,7 +94,14 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { // Sort the leaves in ascending order to match the production environment. MerkleBuilder.sortLeaves(leaves); - vars.merkleRoot = getRoot(leaves.toBytes32()); + + // Compute the Merkle root. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle root is the hash of the leaf itself. + vars.merkleRoot = bytes32(leaves[0]); + } else { + vars.merkleRoot = getRoot(leaves.toBytes32()); + } // Make the caller the admin. resetPrank({ msgSender: params.admin }); @@ -110,7 +118,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vm.expectEmit({ emitter: address(merkleLockupFactory) }); emit CreateMerkleLL({ - merkleLL: ISablierV2MerkleLL(vars.expectedLL), + merkleLL: ISablierMerkleLL(vars.expectedLL), baseParams: vars.baseParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), @@ -152,11 +160,20 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.amounts[params.posBeforeSort], vars.expectedStreamId ); + + // Compute the Merkle proof. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the + // leaf is the root. + } else { + vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); + } + vars.actualStreamId = vars.merkleLL.claim({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], - merkleProof: getProof(leaves.toBytes32(), vars.leafPos) + merkleProof: vars.merkleProof }); vars.actualStream = lockupLinear.getStream(vars.actualStreamId); diff --git a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol index 027d4f5e5..1fa90b38d 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-lockup/MerkleLT.t.sol @@ -5,7 +5,7 @@ import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; @@ -48,7 +48,8 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { uint256[] indexes; uint256 leafPos; uint256 leafToClaim; - ISablierV2MerkleLT merkleLT; + ISablierMerkleLT merkleLT; + bytes32[] merkleProof; bytes32 merkleRoot; address[] recipients; uint256 recipientCount; @@ -94,7 +95,14 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { // Sort the leaves in ascending order to match the production environment. MerkleBuilder.sortLeaves(leaves); - vars.merkleRoot = getRoot(leaves.toBytes32()); + + // Compute the Merkle root. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle root is the hash of the leaf itself. + vars.merkleRoot = bytes32(leaves[0]); + } else { + vars.merkleRoot = getRoot(leaves.toBytes32()); + } // Make the caller the admin. resetPrank({ msgSender: params.admin }); @@ -111,7 +119,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vm.expectEmit({ emitter: address(merkleLockupFactory) }); emit CreateMerkleLT({ - merkleLT: ISablierV2MerkleLT(vars.expectedLT), + merkleLT: ISablierMerkleLT(vars.expectedLT), baseParams: vars.baseParams, lockupTranched: lockupTranched, tranchesWithPercentages: defaults.tranchesWithPercentages(), @@ -154,11 +162,20 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.amounts[params.posBeforeSort], vars.expectedStreamId ); + + // Compute the Merkle proof. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the + // leaf is the root. + } else { + vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); + } + vars.actualStreamId = vars.merkleLT.claim({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], - merkleProof: getProof(leaves.toBytes32(), vars.leafPos) + merkleProof: vars.merkleProof }); vars.actualStream = lockupTranched.getStream(vars.actualStreamId); diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 57c38e914..19472c0ce 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -14,7 +14,7 @@ contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLD[] memory batchParams = new BatchLockup.CreateWithDurationsLD[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithDurationsLD(lockupDynamic, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithDurationsLD_Integration_Test is Periphery_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index 1938152c6..40748e402 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -14,7 +14,7 @@ contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLL[] memory batchParams = new BatchLockup.CreateWithDurationsLL[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithDurationsLL(lockupLinear, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithDurationsLL_Integration_Test is Periphery_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index b84c5ff0f..5939ad99d 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -14,7 +14,7 @@ contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLT[] memory batchParams = new BatchLockup.CreateWithDurationsLT[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithDurationsLT(lockupTranched, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithDurationsLT_Integration_Test is Periphery_Test { } function test_BatchCreateWithDurations() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index e9b6a8be2..9af9272e5 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -14,7 +14,7 @@ contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLD[] memory batchParams = new BatchLockup.CreateWithTimestampsLD[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithTimestampsLD(lockupDynamic, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index f03d63159..3c56008a6 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -14,7 +14,7 @@ contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLL[] memory batchParams = new BatchLockup.CreateWithTimestampsLL[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithTimestampsLL(lockupLinear, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index fdb4331be..2de773919 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -14,7 +14,7 @@ contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLT[] memory batchParams = new BatchLockup.CreateWithTimestampsLT[](0); - vm.expectRevert(Errors.SablierV2BatchLockup_BatchSizeZero.selector); + vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); batchLockup.createWithTimestampsLT(lockupTranched, dai, batchParams); } @@ -23,8 +23,8 @@ contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { } function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { - // Asset flow: Sender → batchLockup → Sablier - // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Sablier contract. + // Asset flow: Sender → batchLockup → SablierLockup + // Expect transfers from Alice to the batchLockup, and then from the batchLockup to the Lockup contract. expectCallToTransferFrom({ from: users.sender, to: address(batchLockup), diff --git a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol index 0dd426bd1..1110f26e9 100644 --- a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol +++ b/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Periphery_Test } from "../../Periphery.t.sol"; @@ -63,19 +63,19 @@ abstract contract MerkleLockup_Integration_Test is Periphery_Test { return computeMerkleLLAddress(users.alice, admin, dai, merkleRoot, expiration); } - function createMerkleLL() internal returns (ISablierV2MerkleLL) { + function createMerkleLL() internal returns (ISablierMerkleLL) { return createMerkleLL(users.admin, defaults.EXPIRATION()); } - function createMerkleLL(address admin) internal returns (ISablierV2MerkleLL) { + function createMerkleLL(address admin) internal returns (ISablierMerkleLL) { return createMerkleLL(admin, defaults.EXPIRATION()); } - function createMerkleLL(uint40 expiration) internal returns (ISablierV2MerkleLL) { + function createMerkleLL(uint40 expiration) internal returns (ISablierMerkleLL) { return createMerkleLL(users.admin, expiration); } - function createMerkleLL(address admin, uint40 expiration) internal returns (ISablierV2MerkleLL) { + function createMerkleLL(address admin, uint40 expiration) internal returns (ISablierMerkleLL) { return merkleLockupFactory.createMerkleLL({ baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), lockupLinear: lockupLinear, @@ -126,19 +126,19 @@ abstract contract MerkleLockup_Integration_Test is Periphery_Test { return computeMerkleLTAddress(users.alice, admin, dai, merkleRoot, expiration); } - function createMerkleLT() internal returns (ISablierV2MerkleLT) { + function createMerkleLT() internal returns (ISablierMerkleLT) { return createMerkleLT(users.admin, defaults.EXPIRATION()); } - function createMerkleLT(address admin) internal returns (ISablierV2MerkleLT) { + function createMerkleLT(address admin) internal returns (ISablierMerkleLT) { return createMerkleLT(admin, defaults.EXPIRATION()); } - function createMerkleLT(uint40 expiration) internal returns (ISablierV2MerkleLT) { + function createMerkleLT(uint40 expiration) internal returns (ISablierMerkleLT) { return createMerkleLT(users.admin, expiration); } - function createMerkleLT(address admin, uint40 expiration) internal returns (ISablierV2MerkleLT) { + function createMerkleLT(address admin, uint40 expiration) internal returns (ISablierMerkleLT) { return merkleLockupFactory.createMerkleLT({ baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), lockupTranched: lockupTranched, diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol index 381adc135..5cab524aa 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -19,7 +19,7 @@ contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + Errors.SablierMerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 ) ); @@ -78,7 +78,7 @@ contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { vm.expectEmit({ emitter: address(merkleLockupFactory) }); emit CreateMerkleLL({ - merkleLL: ISablierV2MerkleLL(expectedLL), + merkleLL: ISablierMerkleLL(expectedLL), baseParams: baseParams, lockupLinear: lockupLinear, streamDurations: defaults.durations(), diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol index 596f9c64e..fa03eb990 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -18,7 +18,7 @@ contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + Errors.SablierMerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 ) ); @@ -69,7 +69,7 @@ contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { vm.expectEmit({ emitter: address(merkleLockupFactory) }); emit CreateMerkleLT({ - merkleLT: ISablierV2MerkleLT(expectedLT), + merkleLT: ISablierMerkleLT(expectedLT), baseParams: baseParams, lockupTranched: lockupTranched, tranchesWithPercentages: defaults.tranchesWithPercentages(), diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol index 3889ddbee..44b234cd4 100644 --- a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol @@ -17,7 +17,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2MerkleLockup_CampaignExpired.selector, warpTime, expiration) + abi.encodeWithSelector(Errors.SablierMerkleLockup_CampaignExpired.selector, warpTime, expiration) ); merkleLL.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); } @@ -31,7 +31,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_StreamClaimed.selector, index1)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_StreamClaimed.selector, index1)); merkleLL.claim(index1, users.recipient1, amount, merkleProof); } @@ -52,7 +52,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLL.claim(invalidIndex, users.recipient1, amount, merkleProof); } @@ -66,7 +66,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLL.claim(index1, invalidRecipient, amount, merkleProof); } @@ -79,7 +79,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLL.claim(index1, users.recipient1, invalidAmount, merkleProof); } @@ -92,7 +92,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLL.claim(index1, users.recipient1, amount, invalidMerkleProof); } diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol index 586f5d6b9..0256e4d6b 100644 --- a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors as V2CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -13,7 +13,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(V2CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); merkleLL.clawback({ to: users.eve, amount: 1 }); } @@ -45,7 +45,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, + Errors.SablierMerkleLockup_ClawbackNotAllowed.selector, getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() diff --git a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol index 62ab53417..612adfadf 100644 --- a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol @@ -2,7 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; -import { SablierV2MerkleLL } from "src/periphery/SablierV2MerkleLL.sol"; +import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -34,8 +34,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleLockup_Integration_Test } function test_Constructor() external { - SablierV2MerkleLL constructedLL = - new SablierV2MerkleLL(defaults.baseParams(), lockupLinear, defaults.durations()); + SablierMerkleLL constructedLL = new SablierMerkleLL(defaults.baseParams(), lockupLinear, defaults.durations()); Vars memory vars; diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol index 7e32d35c8..943cc0a39 100644 --- a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2MerkleLL } from "src/periphery/interfaces/ISablierV2MerkleLL.sol"; +import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -11,7 +11,7 @@ contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { } function test_HasExpired_ExpirationZero() external { - ISablierV2MerkleLL testLockup = createMerkleLL({ expiration: 0 }); + ISablierMerkleLL testLockup = createMerkleLL({ expiration: 0 }); assertFalse(testLockup.hasExpired(), "campaign expired"); } diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol index 1d35b1a1d..81aea9d28 100644 --- a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol @@ -5,7 +5,7 @@ import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; @@ -46,7 +46,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) + abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); @@ -73,7 +73,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { bytes32[] memory merkleProof = defaults.index1Proof(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2MerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) + abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); @@ -89,7 +89,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierV2MerkleLockup_CampaignExpired.selector, warpTime, expiration) + abi.encodeWithSelector(Errors.SablierMerkleLockup_CampaignExpired.selector, warpTime, expiration) ); merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); } @@ -103,7 +103,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_StreamClaimed.selector, index1)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_StreamClaimed.selector, index1)); merkleLT.claim(index1, users.recipient1, amount, merkleProof); } @@ -125,7 +125,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLT.claim(invalidIndex, users.recipient1, amount, merkleProof); } @@ -140,7 +140,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLT.claim(index1, invalidRecipient, amount, merkleProof); } @@ -154,7 +154,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLT.claim(index1, users.recipient1, invalidAmount, merkleProof); } @@ -168,7 +168,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierV2MerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); merkleLT.claim(index1, users.recipient1, amount, invalidMerkleProof); } @@ -204,7 +204,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { baseParams.merkleRoot = getRoot(leaves.toBytes32()); // Deploy a test MerkleLT contract. - ISablierV2MerkleLT testMerkleLT = merkleLockupFactory.createMerkleLT( + ISablierMerkleLT testMerkleLT = merkleLockupFactory.createMerkleLT( baseParams, lockupTranched, defaults.tranchesWithPercentages(), diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol index 77502d4ed..23ee08233 100644 --- a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors as V2CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -13,7 +13,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(V2CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); merkleLT.clawback({ to: users.eve, amount: 1 }); } @@ -44,7 +44,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierV2MerkleLockup_ClawbackNotAllowed.selector, + Errors.SablierMerkleLockup_ClawbackNotAllowed.selector, getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() diff --git a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol index 3fef28fa0..5d7ca85cb 100644 --- a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { SablierV2MerkleLT } from "src/periphery/SablierV2MerkleLT.sol"; +import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -36,8 +36,8 @@ contract Constructor_MerkleLT_Integration_Test is MerkleLockup_Integration_Test } function test_Constructor() external { - SablierV2MerkleLT constructedLT = - new SablierV2MerkleLT(defaults.baseParams(), lockupTranched, defaults.tranchesWithPercentages()); + SablierMerkleLT constructedLT = + new SablierMerkleLT(defaults.baseParams(), lockupTranched, defaults.tranchesWithPercentages()); Vars memory vars; diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol index 64c7c0760..16368ac7f 100644 --- a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierV2MerkleLT } from "src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; @@ -11,7 +11,7 @@ contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { } function test_HasExpired_ExpirationZero() external { - ISablierV2MerkleLT testLockup = createMerkleLT({ expiration: 0 }); + ISablierMerkleLT testLockup = createMerkleLT({ expiration: 0 }); assertFalse(testLockup.hasExpired(), "campaign expired"); } diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index 320faf1f6..58a84b61c 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -18,7 +18,7 @@ abstract contract Calculations { return totalAmount - brokerFeeAmount; } - /// @dev Helper function that replicates the logic of {SablierV2LockupLinear.streamedAmountOf}. + /// @dev Helper function that replicates the logic of {SablierLockupLinear.streamedAmountOf}. function calculateStreamedAmount( uint40 startTime, uint40 endTime, @@ -40,7 +40,7 @@ abstract contract Calculations { } } - /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForMultipleSegments}. + /// @dev Replicates the logic of {SablierLockupDynamic._calculateStreamedAmountForMultipleSegments}. function calculateStreamedAmountForMultipleSegments( LockupDynamic.Segment[] memory segments, uint40 startTime, @@ -86,7 +86,7 @@ abstract contract Calculations { } } - /// @dev Replicates the logic of {SablierV2LockupDynamic._calculateStreamedAmountForOneSegment}. + /// @dev Replicates the logic of {SablierLockupDynamic._calculateStreamedAmountForOneSegment}. function calculateStreamedAmountForOneSegment( LockupDynamic.Segment memory segment, uint40 startTime @@ -111,7 +111,7 @@ abstract contract Calculations { } } - /// @dev Helper function that replicates the logic of {SablierV2LockupTranched._calculateStreamedAmount}. + /// @dev Helper function that replicates the logic of {SablierLockupTranched._calculateStreamedAmount}. function calculateStreamedAmountForTranches( LockupTranched.Tranche[] memory tranches, uint128 depositAmount diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index c2c03f571..5d569d589 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -503,7 +503,7 @@ contract Defaults is Constants, Merkle { tranches_[1] = LockupTranched.Tranche({ amount: 7500e18, timestamp: uint40(block.timestamp) + TOTAL_DURATION }); } - /// @dev Mirros the logic from {SablierV2MerkleLT._calculateTranches}. + /// @dev Mirros the logic from {SablierMerkleLT._calculateTranches}. function tranchesMerkleLockup(uint128 totalAmount) public view diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index ed3b27415..d430d8c0b 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -3,80 +3,79 @@ pragma solidity >=0.8.22 <0.9.0; import { StdCheats } from "forge-std/src/StdCheats.sol"; -import { ISablierV2LockupDynamic } from "../../src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { ISablierV2BatchLockup } from "../../src/periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLockupFactory } from "../../src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupDynamic } from "../../src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierBatchLockup } from "../../src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; abstract contract DeployOptimized is StdCheats { /*////////////////////////////////////////////////////////////////////////// CORE //////////////////////////////////////////////////////////////////////////*/ - /// @dev Deploys {SablierV2LockupDynamic} from an optimized source compiled with `--via-ir`. + /// @dev Deploys {SablierLockupDynamic} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupDynamic( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_, + ILockupNFTDescriptor nftDescriptor_, uint256 maxSegmentCount ) internal - returns (ISablierV2LockupDynamic) + returns (ISablierLockupDynamic) { - return ISablierV2LockupDynamic( + return ISablierLockupDynamic( deployCode( - "out-optimized/SablierV2LockupDynamic.sol/SablierV2LockupDynamic.json", + "out-optimized/SablierLockupDynamic.sol/SablierLockupDynamic.json", abi.encode(initialAdmin, address(nftDescriptor_), maxSegmentCount) ) ); } - /// @dev Deploys {SablierV2LockupLinear} from an optimized source compiled with `--via-ir`. + /// @dev Deploys {SablierLockupLinear} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupLinear( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_ + ILockupNFTDescriptor nftDescriptor_ ) internal - returns (ISablierV2LockupLinear) + returns (ISablierLockupLinear) { - return ISablierV2LockupLinear( + return ISablierLockupLinear( deployCode( - "out-optimized/SablierV2LockupLinear.sol/SablierV2LockupLinear.json", + "out-optimized/SablierLockupLinear.sol/SablierLockupLinear.json", abi.encode(initialAdmin, address(nftDescriptor_)) ) ); } - /// @dev Deploys {SablierV2LockupTranched} from an optimized source compiled with `--via-ir`. + /// @dev Deploys {SablierLockupTranched} from an optimized source compiled with `--via-ir`. function deployOptimizedLockupTranched( address initialAdmin, - ISablierV2NFTDescriptor nftDescriptor_, + ILockupNFTDescriptor nftDescriptor_, uint256 maxTrancheCount ) internal - returns (ISablierV2LockupTranched) + returns (ISablierLockupTranched) { - return ISablierV2LockupTranched( + return ISablierLockupTranched( deployCode( - "out-optimized/SablierV2LockupTranched.sol/SablierV2LockupTranched.json", + "out-optimized/SablierLockupTranched.sol/SablierLockupTranched.json", abi.encode(initialAdmin, address(nftDescriptor_), maxTrancheCount) ) ); } - /// @dev Deploys {SablierV2NFTDescriptor} from an optimized source compiled with `--via-ir`. - function deployOptimizedNFTDescriptor() internal returns (ISablierV2NFTDescriptor) { - return - ISablierV2NFTDescriptor(deployCode("out-optimized/SablierV2NFTDescriptor.sol/SablierV2NFTDescriptor.json")); + /// @dev Deploys {LockupNFTDescriptor} from an optimized source compiled with `--via-ir`. + function deployOptimizedNFTDescriptor() internal returns (ILockupNFTDescriptor) { + return ILockupNFTDescriptor(deployCode("out-optimized/LockupNFTDescriptor.sol/LockupNFTDescriptor.json")); } - /// @notice Deploys all V2 Core contracts from an optimized source compiled with `--via-ir` in the following order: + /// @notice Deploys all Lockup contracts from an optimized source compiled with `--via-ir` in the following order: /// - /// 1. {SablierV2NFTDescriptor} - /// 2. {SablierV2LockupDynamic} - /// 3. {SablierV2LockupLinear} - /// 4. {SablierV2LockupTranched} + /// 1. {LockupNFTDescriptor} + /// 2. {SablierLockupDynamic} + /// 3. {SablierLockupLinear} + /// 4. {SablierLockupTranched} function deployOptimizedCore( address initialAdmin, uint256 maxSegmentCount, @@ -84,10 +83,10 @@ abstract contract DeployOptimized is StdCheats { ) internal returns ( - ISablierV2LockupDynamic lockupDynamic_, - ISablierV2LockupLinear lockupLinear_, - ISablierV2LockupTranched lockupTranched_, - ISablierV2NFTDescriptor nftDescriptor_ + ILockupNFTDescriptor nftDescriptor_, + ISablierLockupDynamic lockupDynamic_, + ISablierLockupLinear lockupLinear_, + ISablierLockupTranched lockupTranched_ ) { nftDescriptor_ = deployOptimizedNFTDescriptor(); @@ -100,23 +99,23 @@ abstract contract DeployOptimized is StdCheats { PERIPHERY //////////////////////////////////////////////////////////////////////////*/ - /// @dev Deploys {SablierV2BatchLockup} from an optimized source compiled with `--via-ir`. - function deployOptimizedBatchLockup() internal returns (ISablierV2BatchLockup) { - return ISablierV2BatchLockup(deployCode("out-optimized/SablierV2BatchLockup.sol/SablierV2BatchLockup.json")); + /// @dev Deploys {SablierBatchLockup} from an optimized source compiled with `--via-ir`. + function deployOptimizedBatchLockup() internal returns (ISablierBatchLockup) { + return ISablierBatchLockup(deployCode("out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json")); } - /// @dev Deploys {SablierV2MerkleLockupFactory} from an optimized source compiled with `--via-ir`. - function deployOptimizedMerkleLockupFactory() internal returns (ISablierV2MerkleLockupFactory) { - return ISablierV2MerkleLockupFactory( - deployCode("out-optimized/SablierV2MerkleLockupFactory.sol/SablierV2MerkleLockupFactory.json") + /// @dev Deploys {SablierMerkleLockupFactory} from an optimized source compiled with `--via-ir`. + function deployOptimizedMerkleLockupFactory() internal returns (ISablierMerkleLockupFactory) { + return ISablierMerkleLockupFactory( + deployCode("out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json") ); } - /// @notice Deploys all V2 Periphery contracts from an optimized source in the following order: + /// @notice Deploys all Periphery contracts from an optimized source in the following order: /// - /// 1. {SablierV2BatchLockup} - /// 2. {SablierV2MerkleLockupFactory} - function deployOptimizedPeriphery() internal returns (ISablierV2BatchLockup, ISablierV2MerkleLockupFactory) { + /// 1. {SablierBatchLockup} + /// 2. {SablierMerkleLockupFactory} + function deployOptimizedPeriphery() internal returns (ISablierBatchLockup, ISablierMerkleLockupFactory) { return (deployOptimizedBatchLockup(), deployOptimizedMerkleLockupFactory()); } @@ -124,14 +123,14 @@ abstract contract DeployOptimized is StdCheats { PROTOCOL //////////////////////////////////////////////////////////////////////////*/ - /// @notice Deploys all V2 Core and Periphery contracts from an optimized source in the following order: + /// @notice Deploys all Lockup and Periphery contracts from an optimized source in the following order: /// - /// 1. {SablierV2NFTDescriptor} - /// 2. {SablierV2LockupDynamic} - /// 3. {SablierV2LockupLinear} - /// 4. {SablierV2LockupTranched} - /// 5. {SablierV2BatchLockup} - /// 6. {SablierV2MerkleLockupFactory} + /// 1. {LockupNFTDescriptor} + /// 2. {SablierLockupDynamic} + /// 3. {SablierLockupLinear} + /// 4. {SablierLockupTranched} + /// 5. {SablierBatchLockup} + /// 6. {SablierMerkleLockupFactory} function deployOptimizedProtocol( address initialAdmin, uint256 maxSegmentCount, @@ -139,15 +138,15 @@ abstract contract DeployOptimized is StdCheats { ) internal returns ( - ISablierV2LockupDynamic lockupDynamic_, - ISablierV2LockupLinear lockupLinear_, - ISablierV2LockupTranched lockupTranched_, - ISablierV2NFTDescriptor nftDescriptor_, - ISablierV2BatchLockup batchLockup_, - ISablierV2MerkleLockupFactory merkleLockupFactory_ + ILockupNFTDescriptor nftDescriptor_, + ISablierLockupDynamic lockupDynamic_, + ISablierLockupLinear lockupLinear_, + ISablierLockupTranched lockupTranched_, + ISablierBatchLockup batchLockup_, + ISablierMerkleLockupFactory merkleLockupFactory_ ) { - (lockupDynamic_, lockupLinear_, lockupTranched_, nftDescriptor_) = + (nftDescriptor_, lockupDynamic_, lockupLinear_, lockupTranched_) = deployOptimizedCore(initialAdmin, maxSegmentCount, maxTrancheCount); (batchLockup_, merkleLockupFactory_) = deployOptimizedPeriphery(); } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index fc4ff77f7..31ff07d3e 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -3,12 +3,12 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierV2LockupLinear } from "../../src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "../../src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "../../src/core/interfaces/ISablierV2NFTDescriptor.sol"; +import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; -import { ISablierV2MerkleLL } from "../../src/periphery/interfaces/ISablierV2MerkleLL.sol"; -import { ISablierV2MerkleLT } from "../../src/periphery/interfaces/ISablierV2MerkleLT.sol"; +import { ISablierMerkleLL } from "../../src/periphery/interfaces/ISablierMerkleLL.sol"; +import { ISablierMerkleLT } from "../../src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. @@ -50,7 +50,7 @@ abstract contract Events { event RenounceLockupStream(uint256 indexed streamId); event SetNFTDescriptor( - address indexed admin, ISablierV2NFTDescriptor oldNFTDescriptor, ISablierV2NFTDescriptor newNFTDescriptor + address indexed admin, ILockupNFTDescriptor oldNFTDescriptor, ILockupNFTDescriptor newNFTDescriptor ); event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount); @@ -105,18 +105,18 @@ abstract contract Events { event Clawback(address indexed admin, address indexed to, uint128 amount); event CreateMerkleLL( - ISablierV2MerkleLL indexed merkleLL, + ISablierMerkleLL indexed merkleLL, MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupLinear lockupLinear, + ISablierLockupLinear lockupLinear, LockupLinear.Durations streamDurations, uint256 aggregateAmount, uint256 recipientCount ); event CreateMerkleLT( - ISablierV2MerkleLT indexed merkleLT, + ISablierMerkleLT indexed merkleLT, MerkleLockup.ConstructorParams baseParams, - ISablierV2LockupTranched lockupTranched, + ISablierLockupTranched lockupTranched, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 65577624e..29a424058 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -4,12 +4,12 @@ pragma solidity >=0.8.22 <0.9.0; import { LibString } from "solady/src/utils/LibString.sol"; import { Precompiles } from "precompiles/Precompiles.sol"; -import { ISablierV2LockupDynamic } from "src/core/interfaces/ISablierV2LockupDynamic.sol"; -import { ISablierV2LockupLinear } from "src/core/interfaces/ISablierV2LockupLinear.sol"; -import { ISablierV2LockupTranched } from "src/core/interfaces/ISablierV2LockupTranched.sol"; -import { ISablierV2NFTDescriptor } from "src/core/interfaces/ISablierV2NFTDescriptor.sol"; -import { ISablierV2BatchLockup } from "src/periphery/interfaces/ISablierV2BatchLockup.sol"; -import { ISablierV2MerkleLockupFactory } from "src/periphery/interfaces/ISablierV2MerkleLockupFactory.sol"; +import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; +import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleLockupFactory } from "src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; import { Base_Test } from "../Base.t.sol"; @@ -62,17 +62,17 @@ contract Precompiles_Test is Base_Test { function test_DeployCore() external onlyTestOptimizedProfile { ( - ISablierV2LockupDynamic actualLockupDynamic, - ISablierV2LockupLinear actualLockupLinear, - ISablierV2LockupTranched actualLockupTranched, - ISablierV2NFTDescriptor actualNFTDescriptor + ILockupNFTDescriptor actualNFTDescriptor, + ISablierLockupDynamic actualLockupDynamic, + ISablierLockupLinear actualLockupLinear, + ISablierLockupTranched actualLockupTranched ) = precompiles.deployCore(users.admin); ( - ISablierV2LockupDynamic expectedLockupDynamic, - ISablierV2LockupLinear expectedLockupLinear, - ISablierV2LockupTranched expectedLockupTranched, - ISablierV2NFTDescriptor expectedNFTDescriptor + ILockupNFTDescriptor expectedNFTDescriptor, + ISablierLockupDynamic expectedLockupDynamic, + ISablierLockupLinear expectedLockupLinear, + ISablierLockupTranched expectedLockupTranched ) = deployOptimizedCore(users.admin, precompiles.MAX_SEGMENT_COUNT(), precompiles.MAX_TRANCHE_COUNT()); bytes memory expectedLockupDynamicCode = adjustBytecode( @@ -110,10 +110,10 @@ contract Precompiles_Test is Base_Test { } function test_DeployPeriphery() external onlyTestOptimizedProfile { - (ISablierV2BatchLockup actualBatchLockup, ISablierV2MerkleLockupFactory actualMerkleLockupFactory) = + (ISablierBatchLockup actualBatchLockup, ISablierMerkleLockupFactory actualMerkleLockupFactory) = precompiles.deployPeriphery(); - (ISablierV2BatchLockup expectedBatchLockup, ISablierV2MerkleLockupFactory expectedMerkleLockupFactory) = + (ISablierBatchLockup expectedBatchLockup, ISablierMerkleLockupFactory expectedMerkleLockupFactory) = deployOptimizedPeriphery(); assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); @@ -126,7 +126,7 @@ contract Precompiles_Test is Base_Test { HELPERS //////////////////////////////////////////////////////////////////////////*/ - /// @dev The expected bytecode has to be adjusted because {SablierV2Lockup} inherits from {NoDelegateCall}, which + /// @dev The expected bytecode has to be adjusted because {SablierLockup} inherits from {NoDelegateCall}, which /// saves the contract's own address in storage. function adjustBytecode( bytes memory bytecode, From 96295a86e48fdb6d63ee606aae3d7eb59c523cb3 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Fri, 2 Aug 2024 02:32:42 +0300 Subject: [PATCH 12/34] build: remove gas reports field in foundry.toml (#1005) --- foundry.toml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/foundry.toml b/foundry.toml index 7b82c742a..ef38078a8 100644 --- a/foundry.toml +++ b/foundry.toml @@ -8,16 +8,6 @@ { access = "read-write", path = "./benchmark/results" }, ] gas_limit = 9223372036854775807 - gas_reports = [ - "LockupNFTDescriptor", - "SablierBatchLockup", - "SablierLockupDynamic", - "SablierLockupLinear", - "SablierLockupTranched", - "SablierMerkleLL", - "SablierMerkleLockupFactory", - "SablierMerkleLT", - ] optimizer = true optimizer_runs = 1000 out = "out" From ce5b2dff5129a4693ce3f7e5776593957aa7bb23 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Fri, 2 Aug 2024 12:50:19 +0100 Subject: [PATCH 13/34] ci: fix path in smt profile --- foundry.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/foundry.toml b/foundry.toml index ef38078a8..153219257 100644 --- a/foundry.toml +++ b/foundry.toml @@ -68,10 +68,10 @@ ] [profile.smt.model_checker.contracts] - "src/LockupNFTDescriptor.sol" = ["LockupNFTDescriptor"] - "src/SablierLockupDynamic.sol" = ["SablierLockupDynamic"] - "src/SablierLockupLinear.sol" = ["SablierLockupLinear"] - "src/SablierLockupTranched.sol" = ["SablierLockupTranched"] + "src/core/LockupNFTDescriptor.sol" = ["LockupNFTDescriptor"] + "src/core/SablierLockupDynamic.sol" = ["SablierLockupDynamic"] + "src/core/SablierLockupLinear.sol" = ["SablierLockupLinear"] + "src/core/SablierLockupTranched.sol" = ["SablierLockupTranched"] # Test the optimized contracts without re-compiling them [profile.test-optimized] From 14b48a663e6ce2349801ca59575f8d7d87d91e3b Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 12 Aug 2024 15:08:40 +0530 Subject: [PATCH 14/34] feat: add `SablierMerkleInstant` (#999) * feat: add SablierMerkleInstant refactor: abstract contract SablierMerkleLockup to SablierMerkleBase refactor: library MerkleLockup to MerkleBase refactor: contract MerkleLockupFactory to MerkleFactory test: add test for MerkleInstant contract chore: add CreateMerkleInstant script test: use super.setUp() where setUp() is redundant test: rename merkle-lockup folder to merkle test: rename MerkleLockup_Integration_Test contract to Merkle_Shared_Integration_Test test: fix event assersion in merkleLL and merkleLT refactor: rename MerkleLockup to Merkle Lockup in NatSpecs Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> * test: include asset transfer log in merkle instant claims * test(refactor): rename Merkle_Shared_Integration_Test back to Merkle_Integration_Test * test: refactor merkle-lockup folder to merkle-campaign Signed-off-by: smol-ninja * refactor: polish code for createMerkleLL and createMerkleLT scripts refactor: rename DeployMerkleLockupFactory to DeployMerkleFactory Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> * test(fork): remove unneeded vars --------- Signed-off-by: smol-ninja Co-authored-by: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Co-authored-by: andreivladbrg --- precompiles/Precompiles.sol | 29 ++- script/DeployDeterministicProtocol.s.sol | 6 +- script/DeployProtocol.s.sol | 6 +- script/periphery/CreateMerkleInstant.s.sol | 33 +++ script/periphery/CreateMerkleLL.s.sol | 33 ++- script/periphery/CreateMerkleLT.s.sol | 29 +-- .../DeployDeterministicPeriphery.s.sol | 8 +- script/periphery/DeployMerkleFactory.s.sol | 13 ++ .../periphery/DeployMerkleLockupFactory.s.sol | 13 -- script/periphery/DeployPeriphery.s.sol | 8 +- shell/deploy-multi-chain.sh | 4 +- shell/prepare-artifacts.sh | 6 +- shell/update-precompiles.sh | 4 +- ...upFactory.sol => SablierMerkleFactory.sol} | 91 +++++++-- src/periphery/SablierMerkleInstant.sol | 58 ++++++ src/periphery/SablierMerkleLL.sol | 22 +- src/periphery/SablierMerkleLT.sol | 22 +- ...MerkleLockup.sol => SablierMerkleBase.sol} | 53 ++--- ...erkleLockup.sol => ISablierMerkleBase.sol} | 28 +-- ...pFactory.sol => ISablierMerkleFactory.sol} | 69 +++++-- .../interfaces/ISablierMerkleInstant.sol | 34 ++++ src/periphery/interfaces/ISablierMerkleLL.sol | 21 +- src/periphery/interfaces/ISablierMerkleLT.sol | 25 ++- src/periphery/libraries/Errors.sol | 12 +- src/periphery/types/DataTypes.sol | 10 +- test/Base.t.sol | 18 +- test/periphery/Periphery.t.sol | 81 ++++++-- test/periphery/fork/Fork.t.sol | 4 +- test/periphery/fork/assets/USDC.t.sol | 7 +- test/periphery/fork/assets/USDT.t.sol | 7 +- .../batch-lockup/createWithTimestampsLD.t.sol | 4 - .../batch-lockup/createWithTimestampsLL.t.sol | 4 - .../batch-lockup/createWithTimestampsLT.t.sol | 4 - .../fork/merkle-campaign/MerkleInstant.t.sol | 191 ++++++++++++++++++ .../MerkleLL.t.sol | 20 +- .../MerkleLT.t.sol | 21 +- .../createWithDurationsLD.t.sol | 2 +- .../createWithDurationsLL.t.sol | 2 +- .../createWithDurationsLT.t.sol | 2 +- .../createWithTimestampsLD.t.sol | 2 +- .../createWithTimestamps.t.sol | 2 +- .../createWithTimestampsLT.t.sol | 2 +- .../MerkleCampaign.t.sol} | 80 +++++++- .../createMerkleInstant.t.sol | 84 ++++++++ .../createMerkleInstant.tree | 9 + .../create-merkle-ll/createMerkleLL.t.sol | 34 ++-- .../create-merkle-ll/createMerkleLL.tree | 0 .../create-merkle-lt/createMerkleLT.t.sol | 46 +++-- .../create-merkle-lt/createMerkleLT.tree | 0 .../isPercentagesSum100.t.sol | 12 +- .../isPercentagesSum100.tree | 0 .../merkle-campaign/instant/claim/claim.t.sol | 106 ++++++++++ .../merkle-campaign/instant/claim/claim.tree | 20 ++ .../instant/clawback/clawback.t.sol | 80 ++++++++ .../instant}/clawback/clawback.tree | 0 .../instant/constructor/constructor.t.sol | 54 +++++ .../getFirstClaimTime.t.sol | 22 ++ .../getFirstClaimTime.tree | 0 .../instant/has-claimed/hasClaimed.t.sol | 28 +++ .../instant}/has-claimed/hasClaimed.tree | 0 .../instant/has-expired/hasExpired.t.sol | 31 +++ .../instant}/has-expired/hasExpired.tree | 0 .../ll/claim/claim.t.sol | 22 +- .../ll/claim/claim.tree | 0 .../ll/clawback/clawback.t.sol | 10 +- .../ll}/clawback/clawback.tree | 0 .../ll/constructor/constructor.t.sol | 8 +- .../getFirstClaimTime.t.sol | 8 +- .../getFirstClaimTime.tree | 0 .../ll/has-claimed/hasClaimed.t.sol | 8 +- .../ll}/has-claimed/hasClaimed.tree | 0 .../ll/has-expired/hasExpired.t.sol | 8 +- .../ll/has-expired/hasExpired.tree | 10 + .../lt/claim/claim.t.sol | 62 +++--- .../lt/claim/claim.tree | 0 .../lt/clawback/clawback.t.sol | 10 +- .../merkle-campaign/lt/clawback/clawback.tree | 17 ++ .../lt/constructor/constructor.t.sol | 13 +- .../getFirstClaimTime.t.sol | 8 +- .../getFirstClaimTime.tree | 5 + .../lt/has-claimed/hasClaimed.t.sol | 8 +- .../lt/has-claimed/hasClaimed.tree | 8 + .../lt/has-expired/hasExpired.t.sol | 8 +- .../lt/has-expired/hasExpired.tree | 0 test/utils/Defaults.sol | 22 +- test/utils/DeployOptimized.sol | 22 +- test/utils/Events.sol | 20 +- test/utils/Precompiles.t.sol | 16 +- 88 files changed, 1468 insertions(+), 441 deletions(-) create mode 100644 script/periphery/CreateMerkleInstant.s.sol create mode 100644 script/periphery/DeployMerkleFactory.s.sol delete mode 100644 script/periphery/DeployMerkleLockupFactory.s.sol rename src/periphery/{SablierMerkleLockupFactory.sol => SablierMerkleFactory.sol} (56%) create mode 100644 src/periphery/SablierMerkleInstant.sol rename src/periphery/abstracts/{SablierMerkleLockup.sol => SablierMerkleBase.sol} (76%) rename src/periphery/interfaces/{ISablierMerkleLockup.sol => ISablierMerkleBase.sol} (74%) rename src/periphery/interfaces/{ISablierMerkleLockupFactory.sol => ISablierMerkleFactory.sol} (56%) create mode 100644 src/periphery/interfaces/ISablierMerkleInstant.sol create mode 100644 test/periphery/fork/merkle-campaign/MerkleInstant.t.sol rename test/periphery/fork/{merkle-lockup => merkle-campaign}/MerkleLL.t.sol (94%) rename test/periphery/fork/{merkle-lockup => merkle-campaign}/MerkleLT.t.sol (93%) rename test/periphery/integration/{merkle-lockup/MerkleLockup.t.sol => merkle-campaign/MerkleCampaign.t.sol} (63%) create mode 100644 test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol create mode 100644 test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/create-merkle-ll/createMerkleLL.t.sol (67%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/create-merkle-ll/createMerkleLL.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/create-merkle-lt/createMerkleLT.t.sol (60%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/create-merkle-lt/createMerkleLT.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/is-percentages-sum-100/isPercentagesSum100.t.sol (74%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/factory/is-percentages-sum-100/isPercentagesSum100.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol create mode 100644 test/periphery/integration/merkle-campaign/instant/claim/claim.tree create mode 100644 test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol rename test/periphery/integration/{merkle-lockup/ll => merkle-campaign/instant}/clawback/clawback.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol create mode 100644 test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol rename test/periphery/integration/{merkle-lockup/ll => merkle-campaign/instant}/get-first-claim-time/getFirstClaimTime.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol rename test/periphery/integration/{merkle-lockup/ll => merkle-campaign/instant}/has-claimed/hasClaimed.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol rename test/periphery/integration/{merkle-lockup/ll => merkle-campaign/instant}/has-expired/hasExpired.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/claim/claim.t.sol (88%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/claim/claim.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/clawback/clawback.t.sol (88%) rename test/periphery/integration/{merkle-lockup/lt => merkle-campaign/ll}/clawback/clawback.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/constructor/constructor.t.sol (90%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/get-first-claim-time/getFirstClaimTime.t.sol (69%) rename test/periphery/integration/{merkle-lockup/lt => merkle-campaign/ll}/get-first-claim-time/getFirstClaimTime.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/has-claimed/hasClaimed.t.sol (73%) rename test/periphery/integration/{merkle-lockup/lt => merkle-campaign/ll}/has-claimed/hasClaimed.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/ll/has-expired/hasExpired.t.sol (81%) create mode 100644 test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/claim/claim.t.sol (85%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/claim/claim.tree (100%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/clawback/clawback.t.sol (88%) create mode 100644 test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/constructor/constructor.t.sol (89%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/get-first-claim-time/getFirstClaimTime.t.sol (69%) create mode 100644 test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/has-claimed/hasClaimed.t.sol (73%) create mode 100644 test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/has-expired/hasExpired.t.sol (81%) rename test/periphery/integration/{merkle-lockup => merkle-campaign}/lt/has-expired/hasExpired.tree (100%) diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 0dcf85b33..466f61595 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -8,7 +8,7 @@ import { ISablierLockupDynamic } from "../src/core/interfaces/ISablierLockupDyna import { ISablierLockupLinear } from "../src/core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../src/core/interfaces/ISablierLockupTranched.sol"; import { ISablierBatchLockup } from "../src/periphery/interfaces/ISablierBatchLockup.sol"; -import { ISablierMerkleLockupFactory } from "../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleFactory } from "../src/periphery/interfaces/ISablierMerkleFactory.sol"; /// @notice This is useful for external integrations seeking to test against the exact deployed bytecode, as recompiling /// with via IR enabled would be time-consuming. @@ -28,7 +28,7 @@ contract Precompiles { hex"60a0604052346103bc57614b716040813803918261001c816103c0565b9384928339810103126103bc5780516001600160a01b03811691908290036103bc57602001516001600160a01b038116908190036103bc5761005e60406103c0565b91601983527f5361626c696572204c6f636b7570204c696e656172204e465400000000000000602084015261009360406103c0565b600e81526d29a0a116a627a1a5aaa816a624a760911b60208201523060805283519092906001600160401b0381116102cd57600154600181811c911680156103b2575b60208210146102af57601f811161034f575b50602094601f82116001146102ec579481929394955f926102e1575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102cd57600254600181811c911680156102c3575b60208210146102af57601f811161024c575b506020601f82116001146101e957819293945f926101de575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811684178255600880549091169290921790915560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3600160075561478b90816103e6823960805181613adf0152f35b015190505f80610165565b601f1982169060025f52805f20915f5b8181106102345750958360019596971061021c575b505050811b0160025561017a565b01515f1960f88460031b161c191690555f808061020e565b9192602060018192868b0151815501940192016101f9565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102a5575b601f0160051c01905b81811061029a575061014c565b5f815560010161028d565b9091508190610284565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013a565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610104565b601f1982169560015f52805f20915f5b8881106103375750836001959697981061031f575b505050811b01600155610119565b01515f1960f88460031b161c191690555f8080610311565b919260206001819286850151815501940192016102fc565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103a8575b601f0160051c01905b81811061039d57506100e8565b5f8155600101610390565b9091508190610387565b90607f16906100d6565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102cd5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461313b57508063027b67441461311957806306fdde031461305e578063081812fc14613040578063095ea7b314612f3b5780631400ecec14612e8a5780631c1cdd4c14612e265780631e99d56914612e0957806323b872dd14612df2578063303acc8514612db5578063406887cb14612c4657806340e58ee51461296f578063425d30dd1461291f57806342842e0e146128f657806342966c6814612732578063442675701461270c5780634857501f1461269b5780634869e12d146126615780634cc55e11146122ba57806353b157271461218f57806357404b12146120c95780636352211e1461209a5780636d0cee751461209a57806370a082311461203057806375829def14611fc2578063780a82c814611f765780637cad6cd114611e995780637de6b1db14611d4c5780638659c27014611994578063894e9a0d146116ac5780638f69b9931461162c5780639067b677146115dd57806395d89b41146114d5578063a22cb46514611421578063a80fc071146113d0578063ab167ccc1461125f578063ad35efd414611200578063b2564569146111b0578063b88d4fde14611126578063b8a3be66146110f1578063b971302a146110a3578063bc2be1be14611054578063c156a11d14610c3e578063c87b56dd14610b33578063d4dbd20b14610ae2578063d511609f14610a97578063d975dfed14610a4c578063e985e9c5146109f3578063ea5ead19146106ae578063eac8f5b81461065d578063f590c17614610601578063f851a440146105dc5763fdd46d6014610263575f80fd5b346105d85760603660031901126105d85760043561027f613268565b906102886133ca565b610290613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b2576001600160a01b03831690811561059f576001600160801b031690811561058c57825f5260036020526001600160a01b0360405f20541693848214158061057c575b610561576001600160801b0361031c8561431f565b168084116105475750835f52600a60205282600260405f20015460801c016001600160801b0381116105335761037b90855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a602052610392600260405f20016136ae565b6001600160801b036103b68160208401511692826040818351169201511690613402565b161115610501575b835f52600a6020526103e2836001600160a01b03600160405f200154169283614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104eb575b61044857005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f916104b1575b50160361049f57005b636ade251160e01b5f5260045260245ffd5b6104d3915060203d6020116104d9575b6104cb818361338c565b8101906137e4565b5f610496565b503d6104c1565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610442565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103be565b634e487b7160e01b5f52601160045260245ffd5b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061058684613b2f565b15610307565b8263b2ae763360e01b5f5260045260245ffd5b82632da33e5b60e01b5f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b5063699d2de960e01b5f5260045260245ffd5b5f80fd5b346105d8575f3660031901126105d85760206001600160a01b035f5416604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105d85760403660031901126105d8576004356106ca613268565b906106d48161431f565b906106dd613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c166109e1576001600160a01b0383169182156109ce576001600160801b03169182156109bb57815f5260036020526001600160a01b0360405f2054169384821415806109ab575b610990576001600160801b036107698461431f565b168085116109765750825f52600a60205283600260405f20015460801c016001600160801b038111610533576107c890845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526107df600260405f20016136ae565b6001600160801b036108038160208401511692826040818351169201511690613402565b161115610944575b825f52600a60205261082f846001600160a01b03600160405f200154169283614345565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061092e575b61089f575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104e0576392b9102b60e01b916001600160e01b0319915f9161090f575b5016036108fc578180610894565b50636ade251160e01b5f5260045260245ffd5b610928915060203d6020116104d9576104cb818361338c565b856108ee565b50835f52600960205260ff60405f20541661088f565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561080b565b848463066920d760e01b5f5260045260245260445260645ffd5b509063350b320360e11b5f526004523360245260445260645ffd5b506109b583613b2f565b15610754565b5063b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105d85760403660031901126105d857610a0c613252565b6001600160a01b03610a1c613268565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a8660209161431f565b6001600160801b0360405191168152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a6020526020600260405f20015460801c604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105d85760203660031901126105d857600435610b5081613804565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104e0575f90610bc1575b610bbd9060405191829160208352602083019061322d565b0390f35b503d805f833e610bd1818361338c565b8101906020818303126105d85780519067ffffffffffffffff82116105d857019080601f830112156105d857815191610c09836133ae565b91610c17604051938461338c565b838352602084830101116105d857610bbd92610c39916020808501910161320c565b610ba5565b346105d85760403660031901126105d857600435610c5a613268565b610c62613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f5260036020526001600160a01b0360405f2054169081330361103d576001600160801b03610cac8461431f565b169081158015610d35575b506001600160a01b03811615610d2257610cd9846001600160a01b039261399b565b169182610cf35783637e27328960e01b5f5260045260245ffd5b8084918403610d0757602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d3d613ad5565b845f52600a60205260ff600160405f20015460a81c161561102a57845f52600a60205260ff600160405f20015460a01c1661101757831561100457610ff157835f5260036020526001600160a01b0360405f2054168084141580610fe1575b610fc6576001600160801b03610db18661431f565b16808411610fac5750845f52600a60205282600260405f20015460801c016001600160801b03811161053357610e1090865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610e27600260405f20016136ae565b6001600160801b03610e4b8160208401511692826040818351169201511690613402565b161115610f7a575b845f52600a6020526001600160a01b03600160405f20015416610e77848683614345565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f64575b15610cb7576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91610f45575b501614610cb757636ade251160e01b5f5260045260245ffd5b610f5e915060203d6020116104d9576104cb818361338c565b88610f2c565b50805f52600960205260ff60405f205416610ed7565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e53565b838663066920d760e01b5f5260045260245260445260645ffd5b838563350b320360e11b5f526004523360245260445260645ffd5b50610feb85613b2f565b15610d9c565b8363b2ae763360e01b5f5260045260245ffd5b84632da33e5b60e01b5f5260045260245ffd5b846315efa0f360e11b5f5260045260245ffd5b8463699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105d85760203660031901126105d8576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105d85760803660031901126105d85761113f613252565b611147613268565b6064359167ffffffffffffffff83116105d857366023840112156105d857826004013591611174836133ae565b92611182604051948561338c565b80845236602482870101116105d8576020815f9260246111ae98018388013785010152604435916136f4565b005b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761123890613907565b604051600582101561124b576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105d8576101403660031901126105d857611279613ad5565b611281613690565b64ffffffffff421680825264ffffffffff61129a6136e0565b166113b5575b60e43564ffffffffff811681036105d85764ffffffffff9101166040820152600435906001600160a01b038216918281036105d857506024356001600160a01b038116908181036105d857506044356001600160801b038116908181036105d857506064356001600160a01b0381168091036105d85760843591821515928381036105d8575060a43593841515948581036105d8575060405196611343886132e9565b8752602087015260408601526060850152608084015260a083015260c08201526040610103193601126105d8576040519061137d82613370565b61010435906001600160a01b03821682036105d857826113ad9260209452610124358482015260e0820152613c25565b604051908152f35b64ffffffffff6113c36136e0565b82011660208301526112a0565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105d85760403660031901126105d85761143a613252565b602435908115158092036105d8576001600160a01b03169081156114a957335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8575f3660031901126105d8576040515f6002548060011c906001811680156115d3575b6020831081146115bf5782855290811561159b575060011461153d575b610bbd836115298185038261338c565b60405191829160208352602083019061322d565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061158157509091508101602001611529611519565b919260018160209254838588010152019101909291611569565b60ff191660208086019190915291151560051b840190910191506115299050611519565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114fc565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b5761166490613907565b60058110158061124b57600282149081156116a0575b811561168e575b6020826040519015158152f35b905061124b5760046020911482611681565b5050600381145f61167a565b346105d85760203660031901126105d8576004355f6101606040516116d081613336565b8281528260208201528260408201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152611713613690565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260405f2060405161174e81613353565b81546001600160a01b0381168252602082019364ffffffffff8260a01c168552604083019364ffffffffff8360c81c1685526060840160ff8460f01c1615158152608085019360f81c1515845260018201549360a08601956001600160a01b038616875260c081019560ff8160a01c16151587526117ed600260e084019660ff8460a81c161515885260ff61010086019460b01c1615158452016136ae565b61012083019081526117fe87613907565b600581101561124b5760021461198c575b5197516001600160a01b031692865f52600b60205260405f205464ffffffffff16995164ffffffffff1694511515915115159751151595511515965f52600360205260405f20546001600160a01b031692516001600160a01b03169a5164ffffffffff16905115159260405161188481613336565b8c81526020810191825260408101928352606081019384526080810194855260a0810195865260c0810196875260e0810197885261010081019889526101208101998a5261014081019a8b52610160019a8b526040519b8c52516001600160a01b031660208c01525164ffffffffff1660408b015251151560608a01525115156080890152516001600160a01b031660a08801525164ffffffffff1660c087015251151560e08601525115156101008501525115156101208401525180516001600160801b031661014084015260208101516001600160801b0316610160840152604001516001600160801b03166101808301525164ffffffffff166101a08201526101c090f35b5f855261180f565b346105d85760203660031901126105d85760043567ffffffffffffffff81116105d8576119c59036906004016132b8565b906119ce613ad5565b5f915b8083106119da57005b6119e583828461366c565b35926119ef613ad5565b835f52600a60205260ff600160405f20015460a81c1615611d3957835f52600a60205260ff600160405f20015460a01c165f14611a3957836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611d2757611a6e815f52600a6020526001600160a01b0360405f205416331490565b15611d1157611a7c81613825565b90805f52600a602052611a94600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081611ae8948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611cc6575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611bfa6001600160a01b03600160405f2001541694611bd2888588614345565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611c4b575b505050505060010191906119d1565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91611ca8575b50160361049f5780808080611c3c565b611cc0915060203d81116104d9576104cb818361338c565b87611c98565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611b32565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105d85760203660031901126105d857600435611d68613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57611d8c81613907565b600581101561124b5760048103611db057506315efa0f360e11b5f5260045260245ffd5b60038103611dcb575063d0a172b360e01b5f5260045260245ffd5b600214611e8757611df0815f52600a6020526001600160a01b0360405f205416331490565b15611d1157805f52600a60205260ff60405f205460f01c1615611e75576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105d85760203660031901126105d8576004356001600160a01b0381168091036105d8576001600160a01b035f5416338103611f60575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105335760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600b602052602064ffffffffff60405f205416604051908152f35b346105d85760203660031901126105d857611fdb613252565b5f546001600160a01b038116338103611f6057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105d85760203660031901126105d8576001600160a01b03612051613252565b16801561206e575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105d85760203660031901126105d85760206120b8600435613804565b6001600160a01b0360405191168152f35b346105d85760203660031901126105d8576004356120e5613690565b50805f52600a60205260ff600160405f20015460a81c161561064b57806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c1690604051926121558461331a565b83526020830152604082015261218d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b346105d8576101603660031901126105d8576121a9613ad5565b6040516121b5816132e9565b6121bd613252565b81526121c7613268565b60208201526121d46133ca565b60408201526064356001600160a01b03811681036105d857606082015260843580151581036105d857608082015260a43580151581036105d85760a082015260603660c31901126105d85760405161222b8161331a565b60c43564ffffffffff811681036105d857815260e43564ffffffffff811681036105d85760208201526101043564ffffffffff811681036105d857604082015260c08201526040610123193601126105d8576040519061228a82613370565b61012435906001600160a01b03821682036105d857826113ad9260209452610144358482015260e0820152613c25565b346105d85760403660031901126105d85760043567ffffffffffffffff81116105d8576122eb9036906004016132b8565b60243567ffffffffffffffff81116105d85761230b9036906004016132b8565b612316939193613ad5565b808303612632575f5b83811061232857005b61233381858561366c565b3561233f82868661366c565b355f5260036020526001600160a01b0360405f2054169061236183858961366c565b356001600160801b038116908181036105d8575061237d613ad5565b815f52600a60205260ff600160405f20015460a81c16156105c557815f52600a60205260ff600160405f20015460a01c166105b25782156109ce5780156109bb57815f5260036020526001600160a01b0360405f205416928381141580612622575b612608576001600160801b036123f48461431f565b168083116125ee5750825f52600a60205281600260405f20015460801c016001600160801b0381116105335761245390845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261246a600260405f20016136ae565b6001600160801b0361248e8160208401511692826040818351169201511690613402565b1611156125bc575b825f52600a6020526001600160a01b03600160405f200154166124ba838383614345565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125a6575b61252b575b5050505060010161231f565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104e0576392b9102b60e01b916001600160e01b0319915f91612588575b50160361049f5780808061251f565b6125a0915060203d81116104d9576104cb818361338c565b89612579565b50835f52600960205260ff60405f20541661251a565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612496565b828463066920d760e01b5f5260045260245260445260645ffd5b8263350b320360e11b5f526004523360245260445260645ffd5b5061262c83613b2f565b156123df565b827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57610a86602091613ba1565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f6126d482613907565b600581101561124b576002036126f2575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166126e5565b346105d8575f3660031901126105d85760206001600160a01b0360085416604051908152f35b346105d85760203660031901126105d85760043561274e613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c16156128cb5761278d81613b2f565b15611d1157805f5260036020526001600160a01b0360405f2054161515806128c4575b806128a7575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561285e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061284c57005b637e27328960e01b5f5260045260245ffd5b61287d835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612804565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127b6565b505f6127b0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105d8576111ae6129073661327e565b906040519261291760208561338c565b5f84526136f4565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105d85760203660031901126105d85760043561298b613ad5565b805f52600a60205260ff600160405f20015460a81c161561064b57805f52600a60205260ff600160405f20015460a01c165f146129d4576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611d2757612a06815f52600a6020526001600160a01b0360405f205416331490565b15611d1157612a1481613825565b90805f52600a602052612a2c600260405f20016136ae565b916001600160801b038351166001600160801b0382161015611cfe57815f52600a60205260ff60405f205460f01c1615611ceb57806001600160801b03602081612a80948188511603169501511690613402565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c21575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612b6a6001600160a01b03600160405f2001541694611bd2888588614345565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bad57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104e057630d4af11f60e31b916001600160e01b0319915f91612c025750160361049f57005b612c1b915060203d6020116104d9576104cb818361338c565b84610496565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612aca565b346105d85760203660031901126105d857612c5f613252565b6001600160a01b035f541690338203612d9e57806001600160a01b03913b15612d7257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104e0575f91612d43575b5015612d1857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612d65915060203d602011612d6b575b612d5d818361338c565b810190613654565b82612ccd565b503d612d53565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105d85760203660031901126105d8576001600160a01b03612dd6613252565b165f526009602052602060ff60405f2054166040519015158152f35b346105d8576111ae612e033661327e565b91613422565b346105d8575f3660031901126105d8576020600754604051908152f35b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b57612e5e90613907565b600581101561124b578060209115908115612e7f575b506040519015158152f35b600191501482612e74565b346105d85760203660031901126105d857600435805f52600a60205260ff600160405f20015460a81c161561064b576020905f90805f52600a835260ff60405f205460f01c1680612f1f575b612eed575b506001600160801b0360405191168152f35b612f199150805f52600a8352612f136001600160801b03600260405f2001541691613825565b90613402565b82612edb565b50805f52600a835260ff600160405f20015460a01c1615612ed6565b346105d85760403660031901126105d857612f54613252565b602435612f6081613804565b3315158061302d575b80612ffa575b612fce5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615612f6f565b50336001600160a01b0382161415612f69565b346105d85760203660031901126105d85760206120b86004356133e0565b346105d8575f3660031901126105d8576040515f6001548060011c9060018116801561310f575b6020831081146115bf5782855290811561159b57506001146130b157610bbd836115298185038261338c565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106130f557509091508101602001611529611519565b9192600181602092548385880101520191019092916130dd565b91607f1691613085565b346105d8575f3660031901126105d857602060405167016345785d8a00008152f35b346105d85760203660031901126105d857600435906001600160e01b031982168092036105d857817f490649060000000000000000000000000000000000000000000000000000000060209314908115613197575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156131e2575b81156131d1575b5083613190565b6301ffc9a760e01b915014836131ca565b7f5b5e139f00000000000000000000000000000000000000000000000000000000811491506131c3565b5f5b83811061321d5750505f910152565b818101518382015260200161320e565b906020916132468151809281855285808601910161320c565b601f01601f1916010190565b600435906001600160a01b03821682036105d857565b602435906001600160a01b03821682036105d857565b60609060031901126105d8576004356001600160a01b03811681036105d857906024356001600160a01b03811681036105d8579060443590565b9181601f840112156105d85782359167ffffffffffffffff83116105d8576020808501948460051b0101116105d857565b610100810190811067ffffffffffffffff82111761330657604052565b634e487b7160e01b5f52604160045260245ffd5b6060810190811067ffffffffffffffff82111761330657604052565b610180810190811067ffffffffffffffff82111761330657604052565b610140810190811067ffffffffffffffff82111761330657604052565b6040810190811067ffffffffffffffff82111761330657604052565b90601f8019910116810190811067ffffffffffffffff82111761330657604052565b67ffffffffffffffff811161330657601f01601f191660200190565b604435906001600160801b03821682036105d857565b6133e981613804565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161053357565b91906001600160a01b03168015610d2257815f5260036020526001600160a01b0360405f20541615158061364c575b8061362f575b61361c577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613567575b6001600160a01b03935085613530575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361351857505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b61354f825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556134b7565b91929050806135c5575b1561357e578282916134a7565b828461359657637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b5033841480156135f3575b806135715750825f526005602052336001600160a01b0360405f20541614613571565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166135d0565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613457565b506001613451565b908160209103126105d8575180151581036105d85790565b919081101561367c5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b6040519061369d8261331a565b5f6040838281528260208201520152565b906040516136bb8161331a565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b60c43564ffffffffff811681036105d85790565b90613700838284613422565b803b61370d575b50505050565b6020916137536001600160a01b03809316956040519586948594630a85bd0160e11b8652336004870152166024850152604484015260806064840152608483019061322d565b03815f865af15f91816137c3575b5061378f575061376f6142f0565b8051908161378a5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b9116036137b157505f808080613707565b633250574960e11b5f5260045260245ffd5b6137dd91925060203d6020116104d9576104cb818361338c565b905f613761565b908160209103126105d857516001600160e01b0319811681036105d85790565b805f5260036020526001600160a01b0360405f20541690811561284c575090565b805f52600b60205264ffffffffff60405f205416815f52600a60205264ffffffffff60405f205460a01c1690421080156138fd575b6138f757815f52600a60205264ffffffffff60405f205460c81c1690814210156138da578061388c92039042036144d3565b815f52600a6020526138af6001600160801b03600260405f2001541680926145bf565b9081116138c4576001600160801b0391501690565b505f52600a602052600260405f20015460801c90565b50505f52600a6020526001600160801b03600260405f2001541690565b50505f90565b504281101561385a565b805f52600a60205260ff600160405f20015460a01c165f146139295750600490565b805f52600a60205260405f205460f81c61399557805f52600a60205264ffffffffff60405f205460a01c1642106139905761396381613825565b905f52600a6020526001600160801b0380600260405f200154169116105f1461398b57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613ac3575b80613aa6575b612895577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613a6f575b1680613a57575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613a13565b613a8e835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613a0c565b50805f52600a60205260ff600160405f20015460b01c16156139c0565b506001600160a01b03821615156139ba565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613b0757565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f20541690813314918215613b75575b508115613b5c575090565b90506001600160a01b03613b7033926133e0565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f613b51565b805f52600a602052613bb8600260405f20016136ae565b90805f52600a60205260ff600160405f20015460a01c165f14613be65750602001516001600160801b031690565b90815f52600a60205260405f205460f81c613c085750613c0590613825565b90565b613c0591506001600160801b036040818351169201511690613402565b90613c466001600160801b03604084015116602060e085015101519061439c565b916001600160801b0383511660c082015190156142c85764ffffffffff815116156142a0576020810164ffffffffff81511680614214575b5050604064ffffffffff82511691019064ffffffffff82511690818110156141e657505064ffffffffff80421691511690818110156141b85750506007549280516001600160801b03169160405192613cd68461331a565b8352602083015f9052604083015f905260608101516001600160a01b03169260c082015190604082015164ffffffffff16946080840195888751151560a087015115159287516001600160a01b0316965164ffffffffff169160405197613d3c89613353565b885260208801928352604088019182526060880190815260808801915f835260a0890196875260c08901935f855260e08a0195600187526101008b019788526101208b01998a525f52600a60205260405f2099516001600160a01b03166001600160a01b03168a546001600160a01b031916178a5551908954905160c81b7dffffffffff00000000000000000000000000000000000000000000000000169160a01b78ffffffffff000000000000000000000000000000000000000016907fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff161717885551151587549060f01b7eff000000000000000000000000000000000000000000000000000000000000169060ff60f01b191617875551151586549060f81b7fff0000000000000000000000000000000000000000000000000000000000000016907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161786556001860193516001600160a01b03166001600160a01b031684546001600160a01b03191617845551151583549060a01b74ff0000000000000000000000000000000000000000169060ff60a01b19161783555115159082549051151560b01b76ff00000000000000000000000000000000000000000000169160a81b75ff00000000000000000000000000000000000000000016907fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff16171790556002820190519081516001600160801b03166001600160801b031681546001600160801b03191617815560208201516001600160801b0316613fbc91906001600160801b036001600160801b031983549260801b169116179055565b604001516001600160801b031690600301906001600160801b031681546001600160801b03191617905560c08101516020015164ffffffffff1680614198575b50600185016007556001600160a01b036020820151168015610d225761402a866001600160a01b039261399b565b1661416c576140556001600160a01b036060830151166001600160801b038451169030903390614479565b7f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c6101408660208501946001600160801b038651168061413d575b506141346001600160a01b03865116956001600160a01b03602082015116976001600160a01b03606083015116995115156001600160801b0360a0840151151592816001600160a01b0360e060c0880151970151511697604051998a523360208b01525116604089015251166060870152608086015260a085015260c084019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120820152a4565b614166906001600160a01b036060880151166001600160a01b0360e08901515116903390614479565b5f614090565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b855f52600b60205260405f209064ffffffffff198254161790555f613ffc565b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f9e7fd91f000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b64ffffffffff8351168181101561427257505064ffffffffff90511664ffffffffff60408301511690818110613c7e577f87d966a0000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f84fe0623000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b3d1561431a573d90614301826133ae565b9161430f604051938461338c565b82523d5f602084013e565b606090565b613c059061432c81613ba1565b905f52600a602052600260405f20015460801c90613402565b61439a926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261439560648361338c565b61466d565b565b9190916040516143ab81613370565b5f81525f6020820152926001600160801b03821690811561445c5767016345785d8a00008111614425576143e76001600160801b0391836145bf565b1660208501918183521115614411576001600160801b03918261440c92511690613402565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161446d81613370565b5f81525f602082015290565b9091926001600160a01b0361439a9481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261439560848361338c565b5f19670de0b6b3a7640000820991670de0b6b3a764000082029182808510940393808503941461459e578184101561456457670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b50915081156145ab570490565b634e487b7160e01b5f52601260045260245ffd5b9091905f198382098382029182808310920391808303921461465c57670de0b6b3a764000082101561462c577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b5f806001600160a01b0361469693169360208151910182865af161468f6142f0565b90836146f2565b80519081151591826146d7575b50506146ac5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6146ea9250602080918301019101613654565b155f806146a3565b9061472f575080511561470757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614775575b614740575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561473856fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP_TRANCHED = hex"60c0604052346103e157614e306060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601b84527f5361626c696572204c6f636b7570205472616e63686564204e46540000000000602085015261009860406103e5565b600e81526d5341422d4c4f434b55502d54524160901b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755614a25908161040b823960805181613e37015260a051818181612fa60152613ee00152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461331257508063027b6744146132f057806306fdde0314613235578063081812fc14613217578063095ea7b3146131125780631400ecec146130615780631c1cdd4c14612ffd5780631e99d56914612fe057806323b872dd14612fc95780632fe4304114612f8f578063303acc8514612f5257806332fbe22b14612df5578063406887cb14612c8657806340e58ee5146129af578063425d30dd1461295f57806342842e0e1461293657806342966c6814612772578063442675701461274c5780634857501f146126db5780634869e12d146126a15780634cc55e11146122fb57806357404b121461226d5780636352211e1461223e5780636d0cee751461223e57806370a08231146121d457806375829def146121665780637cad6cd1146120755780637de6b1db14611f285780637f5799f914611ecf5780638659c27014611b17578063894e9a0d146117d8578063897f362b1461150d5780638f69b9931461148d5780639067b6771461143e57806395d89b4114611336578063a22cb46514611282578063a80fc07114611231578063ad35efd4146111d2578063b256456914611182578063b88d4fde146110f8578063b8a3be66146110c3578063b971302a14611075578063bc2be1be14611026578063c156a11d14610c0a578063c87b56dd14610aff578063d4dbd20b14610aae578063d511609f14610a63578063d975dfed14610a18578063e985e9c5146109bf578063ea5ead1914610692578063eac8f5b814610641578063f590c176146105e5578063f851a440146105c05763fdd46d601461026e575f80fd5b346105bc5760603660031901126105bc5760043561028a61343f565b90604435916001600160801b038316908184036105bc576102a9613e2d565b825f52600a60205260ff600160405f20015460a81c16156105a957825f52600a60205260ff600160405f20015460a01c16610596576001600160a01b03811690811561058357821561057057835f5260036020526001600160a01b0360405f205416948583141580610560575b610545576001600160801b0361032b86614685565b1680851161052b575061035090855f52600a602052600260405f20015460801c6146ab565b5f858152600a6020526040902060020180546001600160801b031660809290921b6001600160801b03191691909117815561038a906139d3565b6001600160801b036103ae8160208401511692826040818351169201511690613616565b1611156104f9575b835f52600a6020526103da836001600160a01b03600160405f200154169283614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806104e3575b61044057005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916104a9575b50160361049757005b636ade251160e01b5f5260045260245ffd5b6104cb915060203d6020116104d1575b6104c381836135a2565b810190613b16565b5f61048e565b503d6104b9565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661043a565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556103b6565b848663066920d760e01b5f5260045260245260445260645ffd5b828563350b320360e11b5f526004523360245260445260645ffd5b5061056a85614560565b15610316565b8363b2ae763360e01b5f5260045260245ffd5b83632da33e5b60e01b5f5260045260245ffd5b826315efa0f360e11b5f5260045260245ffd5b8263699d2de960e01b5f5260045260245ffd5b5f80fd5b346105bc575f3660031901126105bc5760206001600160a01b035f5416604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346105bc5760403660031901126105bc576004356106ae61343f565b6106b782614685565b916106c0613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c166109ad576001600160a01b038216801561099a576001600160801b03841692831561098757825f5260036020526001600160a01b0360405f205416948583141580610977575b61095c576001600160801b0361074c85614685565b16808611610942575061077190845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b0319169190911781556107ab906139d3565b6001600160801b036107cf8160208401511692826040818351169201511690613616565b161115610910575b825f52600a6020526107fb846001600160a01b03600160405f200154169283614809565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a183331415806108fa575b61086b575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af19081156104d8576392b9102b60e01b916001600160e01b0319915f916108db575b5016036108c8578180610860565b50636ade251160e01b5f5260045260245ffd5b6108f4915060203d6020116104d1576104c381836135a2565b856108ba565b50835f52600960205260ff60405f20541661085b565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556107d7565b858563066920d760e01b5f5260045260245260445260645ffd5b828463350b320360e11b5f526004523360245260445260645ffd5b5061098184614560565b15610737565b8263b2ae763360e01b5f5260045260245ffd5b50632da33e5b60e01b5f5260045260245ffd5b6315efa0f360e11b5f5260045260245ffd5b346105bc5760403660031901126105bc576109d8613429565b6001600160a01b036109e861343f565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a52602091614685565b6001600160801b0360405191168152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a6020526020600260405f20015460801c604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346105bc5760203660031901126105bc57600435610b1c81613b36565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa80156104d8575f90610b8d575b610b8990604051918291602083526020830190613404565b0390f35b503d805f833e610b9d81836135a2565b8101906020818303126105bc5780519067ffffffffffffffff82116105bc57019080601f830112156105bc57815191610bd5836135c4565b91610be360405193846135a2565b838352602084830101116105bc57610b8992610c0591602080850191016133e3565b610b71565b346105bc5760403660031901126105bc57600435610c2661343f565b610c2e613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f5260036020526001600160a01b0360405f20541690813303610ffc57610c7083614685565b906001600160801b0382169182158015610d04575b50506001600160a01b03811615610cf157610ca8846001600160a01b0392613cf3565b169182610cc25783637e27328960e01b5f5260045260245ffd5b8084918403610cd657602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610d0c613e2d565b855f52600a60205260ff600160405f20015460a81c1615610fe957855f52600a60205260ff600160405f20015460a01c16610fd6578415610fc357610fb057845f5260036020526001600160a01b0360405f205416908185141580610fa0575b610f85576001600160801b03610d8187614685565b16808511610f6b5750610da690865f52600a602052600260405f20015460801c6146ab565b5f868152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155610de0906139d3565b6001600160801b03610e048160208401511692826040818351169201511690613616565b161115610f39575b845f52600a6020526001600160a01b03600160405f20015416610e30848683614809565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a18033141580610f23575b610e9b575b80610c85565b6040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f91610f04575b501614610e9557636ade251160e01b5f5260045260245ffd5b610f1d915060203d6020116104d1576104c381836135a2565b88610eeb565b50805f52600960205260ff60405f205416610e90565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610e0c565b848763066920d760e01b5f5260045260245260445260645ffd5b848663350b320360e11b5f526004523360245260445260645ffd5b50610faa86614560565b15610d6c565b8463b2ae763360e01b5f5260045260245ffd5b85632da33e5b60e01b5f5260045260245ffd5b856315efa0f360e11b5f5260045260245ffd5b8563699d2de960e01b5f5260045260245ffd5b82632082501160e01b5f526004523360245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160a01b0360405f205416604051908152f35b346105bc5760203660031901126105bc576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346105bc5760803660031901126105bc57611111613429565b61111961343f565b6064359167ffffffffffffffff83116105bc57366023840112156105bc57826004013591611146836135c4565b9261115460405194856135a2565b80845236602482870101116105bc576020815f9260246111809801838801378501015260443591613a26565b005b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761120a90613c5f565b604051600582101561121d576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346105bc5760403660031901126105bc5761129b613429565b602435908115158092036105bc576001600160a01b031690811561130a57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc575f3660031901126105bc576040515f6002548060011c90600181168015611434575b602083108114611420578285529081156113fc575060011461139e575b610b898361138a818503826135a2565b604051918291602083526020830190613404565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b8082106113e25750909150810160200161138a61137a565b9192600181602092548385880101520191019092916113ca565b60ff191660208086019190915291151560051b8401909101915061138a905061137a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161135d565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576114c590613c5f565b60058110158061121d5760028214908115611501575b81156114ef575b6020826040519015158152f35b905061121d57600460209114826114e2565b5050600381145f6114db565b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc578036036101206003198201126105bc57611548613e2d565b60c482013590602219018112156105bc5781019060048201359167ffffffffffffffff83116105bc5760248101908360061b80360383136105bc5760046020916115918761387a565b9661159f60405198896135a2565b875282870193010101913683116105bc57905b8282106117be575050508151916115c88361387a565b926115d660405194856135a2565b808452601f196115e58261387a565b015f5b81811061179b57505064ffffffffff4216916001600160801b0361160b82613b57565b51511664ffffffffff80602061162085613b57565b51015116850116604051916116348361354d565b8252602082015261164486613b57565b5261164e85613b57565b5060015b8281106117265750505061166882600401613a05565b9261167560248401613a05565b9261168260448201613933565b916064820135936001600160a01b0385168095036105bc5760209661171e966116de966001600160801b03611713976001600160a01b036116c560848a01613a19565b94816116d360a48c01613a19565b976040519d8e613530565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e43691016138c8565b610100820152613e87565b604051908152f35b806001600160801b0361173b60019385613b64565b51511664ffffffffff8060206117545f1986018c613b64565b510151168160206117658689613b64565b510151160116604051916117788361354d565b825260208201526117898289613b64565b526117948188613b64565b5001611652565b6020906040516117aa8161354d565b5f81525f83820152828289010152016115e8565b60206040916117cd3685613892565b8152019101906115b2565b346105bc5760203660031901126105bc5760043560606101606040516117fd81613569565b5f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f61012082015260405161184381613586565b5f81525f60208201525f60408201526101408201520152805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260405f2060405191610140830183811067ffffffffffffffff821117611b03576040528154916001600160a01b0383168452602084019264ffffffffff8160a01c168452604085019064ffffffffff8160c81c16825285606081019260ff8360f01c1615158452608082019260f81c1515835260018501549260a08301956001600160a01b0385168752611940600260c086019260ff8860a01c161515845260ff61010060e0890198828b60a81c1615158a52019860b01c1615158852016139d3565b6101208b0190815261195189613c5f565b600581101561121d57600214611afb575b5196516001600160a01b0316925164ffffffffff169551151590511515935115159451151595885f52600360205260405f20546001600160a01b03169a516001600160a01b0316995164ffffffffff16985f52600b60205260405f2092511515926040519a6119d08c613569565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952611a249061395f565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e08201610b89916134d4565b5f8752611962565b634e487b7160e01b5f52604160045260245ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc57611b489036906004016134a3565b90611b51613e2d565b5f915b808310611b5d57005b611b6883828461390f565b3592611b72613e2d565b835f52600a60205260ff600160405f20015460a81c1615611ebc57835f52600a60205260ff600160405f20015460a01c165f14611bbc57836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611eaa57611bf1815f52600a6020526001600160a01b0360405f205416331490565b15611e9457611bff81613b78565b90805f52600a602052611c17600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081611c6b948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611e49575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611d7d6001600160a01b03600160405f2001541694611d55888588614809565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611dce575b50505050506001019190611b54565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91611e2b575b5016036104975780808080611dbf565b611e43915060203d81116104d1576104c381836135a2565b87611e1b565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611cb5565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f5260045260245ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600b602052610b89611f1460405f2061395f565b6040519182916020835260208301906134d4565b346105bc5760203660031901126105bc57600435611f44613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57611f6881613c5f565b600581101561121d5760048103611f8c57506315efa0f360e11b5f5260045260245ffd5b60038103611fa7575063d0a172b360e01b5f5260045260245ffd5b60021461206357611fcc815f52600a6020526001600160a01b0360405f205416331490565b15611e9457805f52600a60205260ff60405f205460f01c1615612051576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b6308aca53f60e21b5f5260045260245ffd5b346105bc5760203660031901126105bc576004356001600160a01b0381168091036105bc576001600160a01b035f5416338103612150575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161213c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5761217f613429565b5f546001600160a01b03811633810361215057506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346105bc5760203660031901126105bc576001600160a01b036121f5613429565b168015612212575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346105bc5760203660031901126105bc57602061225c600435613b36565b6001600160a01b0360405191168152f35b346105bc5760203660031901126105bc57600435612289613947565b50805f52600a60205260ff600160405f20015460a81c161561062f575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166122d38361354d565b825260208201526122f98251809264ffffffffff60208092828151168552015116910152565bf35b346105bc5760403660031901126105bc5760043567ffffffffffffffff81116105bc5761232c9036906004016134a3565b9060243567ffffffffffffffff81116105bc5761234d9036906004016134a3565b919092612358613e2d565b828103612671575f5b81811061236a57005b61237581838561390f565b3561238182848661390f565b355f5260036020526001600160a01b0360405f205416906123ab6123a684888a61390f565b613933565b916123b4613e2d565b815f52600a60205260ff600160405f20015460a81c161561101357815f52600a60205260ff600160405f20015460a01c1661265e57801561099a576001600160801b03831690811561098757825f5260036020526001600160a01b0360405f20541693848214158061264e575b612633576001600160801b0361243685614685565b16808411612619575061245b90845f52600a602052600260405f20015460801c6146ab565b5f848152600a6020526040902060020180546001600160801b031660809290921b6001600160801b031916919091178155612495906139d3565b6001600160801b036124b98160208401511692826040818351169201511690613616565b1611156125e7575b825f52600a6020526001600160a01b03600160405f200154166124e5838383614809565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806125d1575b612556575b50505050600101612361565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af19081156104d8576392b9102b60e01b916001600160e01b0319915f916125b3575b5016036104975780808061254a565b6125cb915060203d81116104d1576104c381836135a2565b896125a4565b50835f52600960205260ff60405f205416612545565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556124c1565b838563066920d760e01b5f5260045260245260445260645ffd5b508263350b320360e11b5f526004523360245260445260645ffd5b5061265884614560565b15612421565b506315efa0f360e11b5f5260045260245ffd5b90507fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f57610a526020916145d2565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f61271482613c5f565b600581101561121d57600203612732575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612725565b346105bc575f3660031901126105bc5760206001600160a01b0360085416604051908152f35b346105bc5760203660031901126105bc5760043561278e613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c161561290b576127cd81614560565b15611e9457805f5260036020526001600160a01b0360405f205416151580612904575b806128e7575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f205416801590811561289e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a45061288c57005b637e27328960e01b5f5260045260245ffd5b6128bd835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612844565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c16156127f6565b505f6127f0565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346105bc5761118061294736613469565b90604051926129576020856135a2565b5f8452613a26565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346105bc5760203660031901126105bc576004356129cb613e2d565b805f52600a60205260ff600160405f20015460a81c161561062f57805f52600a60205260ff600160405f20015460a01c165f14612a14576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611eaa57612a46815f52600a6020526001600160a01b0360405f205416331490565b15611e9457612a5481613b78565b90805f52600a602052612a6c600260405f20016139d3565b916001600160801b038351166001600160801b0382161015611e8157815f52600a60205260ff60405f205460f01c1615611e6e57806001600160801b03602081612ac0948188511603169501511690613616565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612c61575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50612baa6001600160a01b03600160405f2001541694611d55888588614809565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416612bed57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af19081156104d857630d4af11f60e31b916001600160e01b0319915f91612c425750160361049757005b612c5b915060203d6020116104d1576104c381836135a2565b8461048e565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612b0a565b346105bc5760203660031901126105bc57612c9f613429565b6001600160a01b035f541690338203612dde57806001600160a01b03913b15612db257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa9081156104d8575f91612d83575b5015612d5857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b612da5915060203d602011612dab575b612d9d81836135a2565b8101906138f7565b82612d0d565b503d612d93565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346105bc5760203660031901126105bc5760043567ffffffffffffffff81116105bc5761014060031982360301126105bc57612e2f613e2d565b604051612e3b81613530565b612e4782600401613455565b8152612e5560248301613455565b6020820152612e66604483016135e0565b604082015260648201356001600160a01b03811681036105bc576060820152612e9160848301613523565b6080820152612ea260a48301613523565b60a0820152612eb360c48301613868565b60c082015260e482013567ffffffffffffffff81116105bc57820191366023840112156105bc57600483013592612ee98461387a565b90612ef760405192836135a2565b848252602060048184019660061b83010101903682116105bc57602401945b818610612f3857602061171e86611713878760e08401526101043691016138c8565b6020604091612f473689613892565b815201950194612f16565b346105bc5760203660031901126105bc576001600160a01b03612f73613429565b165f526009602052602060ff60405f2054166040519015158152f35b346105bc575f3660031901126105bc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346105bc57611180612fda36613469565b91613636565b346105bc575f3660031901126105bc576020600754604051908152f35b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f5761303590613c5f565b600581101561121d578060209115908115613056575b506040519015158152f35b60019150148261304b565b346105bc5760203660031901126105bc57600435805f52600a60205260ff600160405f20015460a81c161561062f576020905f90805f52600a835260ff60405f205460f01c16806130f6575b6130c4575b506001600160801b0360405191168152f35b6130f09150805f52600a83526130ea6001600160801b03600260405f2001541691613b78565b90613616565b826130b2565b50805f52600a835260ff600160405f20015460a01c16156130ad565b346105bc5760403660031901126105bc5761312b613429565b60243561313781613b36565b33151580613204575b806131d1575b6131a55781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613146565b50336001600160a01b0382161415613140565b346105bc5760203660031901126105bc57602061225c6004356135f4565b346105bc575f3660031901126105bc576040515f6001548060011c906001811680156132e6575b602083108114611420578285529081156113fc575060011461328857610b898361138a818503826135a2565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106132cc5750909150810160200161138a61137a565b9192600181602092548385880101520191019092916132b4565b91607f169161325c565b346105bc575f3660031901126105bc57602060405167016345785d8a00008152f35b346105bc5760203660031901126105bc57600435906001600160e01b031982168092036105bc57817f49064906000000000000000000000000000000000000000000000000000000006020931490811561336e575b5015158152f35b7f80ac58cd000000000000000000000000000000000000000000000000000000008114915081156133b9575b81156133a8575b5083613367565b6301ffc9a760e01b915014836133a1565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061339a565b5f5b8381106133f45750505f910152565b81810151838201526020016133e5565b9060209161341d815180928185528580860191016133e3565b601f01601f1916010190565b600435906001600160a01b03821682036105bc57565b602435906001600160a01b03821682036105bc57565b35906001600160a01b03821682036105bc57565b60609060031901126105bc576004356001600160a01b03811681036105bc57906024356001600160a01b03811681036105bc579060443590565b9181601f840112156105bc5782359167ffffffffffffffff83116105bc576020808501948460051b0101116105bc57565b90602080835192838152019201905f5b8181106134f15750505090565b825180516001600160801b0316855260209081015164ffffffffff1681860152604090940193909201916001016134e4565b359081151582036105bc57565b610120810190811067ffffffffffffffff821117611b0357604052565b6040810190811067ffffffffffffffff821117611b0357604052565b610180810190811067ffffffffffffffff821117611b0357604052565b6060810190811067ffffffffffffffff821117611b0357604052565b90601f8019910116810190811067ffffffffffffffff821117611b0357604052565b67ffffffffffffffff8111611b0357601f01601f191660200190565b35906001600160801b03821682036105bc57565b6135fd81613b36565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161213c57565b91906001600160a01b03168015610cf157815f5260036020526001600160a01b0360405f205416151580613860575b80613843575b613830577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f2054169282331515928361377b575b6001600160a01b03935085613744575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a41680830361372c57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613763825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f1981540190556136cb565b91929050806137d9575b15613792578282916136bb565b82846137aa57637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613807575b806137855750825f526005602052336001600160a01b0360405f20541614613785565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f2054166137e4565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c161561366b565b506001613665565b359064ffffffffff821682036105bc57565b67ffffffffffffffff8111611b035760051b60200190565b91908260409103126105bc576040516138aa8161354d565b60206138c38183956138bb816135e0565b855201613868565b910152565b91908260409103126105bc576040516138e08161354d565b60208082946138ee81613455565b84520135910152565b908160209103126105bc575180151581036105bc5790565b919081101561391f5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036105bc5790565b604051906139548261354d565b5f6020838281520152565b90815461396b8161387a565b9261397960405194856135a2565b81845260208401905f5260205f205f915b8383106139975750505050565b6001602081926040516139a98161354d565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061398a565b906040516139e081613586565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b356001600160a01b03811681036105bc5790565b3580151581036105bc5790565b90613a32838284613636565b803b613a3f575b50505050565b602091613a856001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613404565b03815f865af15f9181613af5575b50613ac15750613aa1614656565b80519081613abc5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b911603613ae357505f808080613a39565b633250574960e11b5f5260045260245ffd5b613b0f91925060203d6020116104d1576104c381836135a2565b905f613a93565b908160209103126105bc57516001600160e01b0319811681036105bc5790565b805f5260036020526001600160a01b0360405f20541690811561288c575090565b80511561391f5760200190565b805182101561391f5760209160051b010190565b9064ffffffffff421691805f52600b602052613b9660405f2061395f565b908364ffffffffff6020613ba985613b57565b5101511611613c5857805f52600a6020528364ffffffffff60405f205460c81c161115613c3957506001600160801b03613be282613b57565b515116916001925b8251841015613c32578464ffffffffff6020613c068787613b64565b5101511611613c32576001600160801b0360019181613c258787613b64565b5151160116930192613bea565b9350915050565b919250505f52600a6020526001600160801b03600260405f2001541690565b505f925050565b805f52600a60205260ff600160405f20015460a01c165f14613c815750600490565b805f52600a60205260405f205460f81c613ced57805f52600a60205264ffffffffff60405f205460a01c164210613ce857613cbb81613b78565b905f52600a6020526001600160801b0380600260405f200154169116105f14613ce357600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580613e1b575b80613dfe575b6128d5577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283613dc7575b1680613daf575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055613d6b565b613de6835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613d64565b50805f52600a60205260ff600160405f20015460b01c1615613d18565b506001600160a01b0382161515613d12565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003613e5f57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90613ea96001600160801b0360408401511660206101008501510151906146cb565b916001600160801b038351169060e08101519160c082019264ffffffffff845116821561453857801561451057815180156144e8577f000000000000000000000000000000000000000000000000000000000000000081116144bd575064ffffffffff6020613f1784613b57565b5101511681101561447957505f905f905f81515f905b8082106143f1575050505064ffffffffff804216911690818110156143c35750506001600160801b03169081810361439557505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166001600160801b03198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff0000000000000000000000000000000000000000000000000060206140f98751975f19890190613b64565b51015160c81b169360a01b169116171785555f5b8181106142e3575050600187016007556001600160a01b036020830151168015610cf157614143886001600160a01b0392613cf3565b166142b75786826141916001600160a01b0360607ffeb1cb9ce021c8bd5fb1eb836e6284c68866fa32d1d844238de19955238f8076960151166001600160801b0385511690309033906147a8565b6001600160801b0360208401511680614287575b506001600160a01b038151169461427c61425e6001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff604051996142038b61354d565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c08701526101408601906134d4565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b6142b1906001600160a01b036060840151166001600160a01b0361010085015151169033906147a8565b5f6141a5565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f20906142fe8160e0870151613b64565b5182549268010000000000000000841015611b03576001840180825584101561391f576001936020915f52815f2001916001600160801b0380825116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b1691161790550161410d565b7fa4cdf853000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193614415906001600160801b0361440c8588613b64565b515116906146ab565b9364ffffffffff8060206144298685613b64565b5101511694168085111561444557506001849301909291613f2d565b8490847fbfc5f2fa000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff602061448a84613b57565b51015116907fab900963000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f76d9c284000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f814426ed000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f205416908133149182156145a6575b50811561458d575090565b90506001600160a01b036145a133926135f4565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614582565b805f52600a6020526145e9600260405f20016139d3565b90805f52600a60205260ff600160405f20015460a01c165f146146175750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614639575061463690613b78565b90565b61463691506001600160801b036040818351169201511690613616565b3d15614680573d90614667826135c4565b9161467560405193846135a2565b82523d5f602084013e565b606090565b61463690614692816145d2565b905f52600a602052600260405f20015460801c90613616565b906001600160801b03809116911601906001600160801b03821161213c57565b9190916040516146da8161354d565b5f81525f6020820152926001600160801b03821690811561478b5767016345785d8a00008111614754576147166001600160801b0391836148de565b1660208501918183521115614740576001600160801b03918261473b92511690613616565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b505050905060405161479c8161354d565b5f81525f602082015290565b9091926001600160a01b036148079481604051957f23b872dd0000000000000000000000000000000000000000000000000000000060208801521660248601521660448401526064830152606482526148026084836135a2565b614859565b565b614807926001600160a01b03604051937fa9059cbb0000000000000000000000000000000000000000000000000000000060208601521660248401526044830152604482526148026064836135a2565b5f806001600160a01b0361488293169360208151910182865af161487b614656565b908361498c565b80519081151591826148c3575b50506148985750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6148d692506020809183010191016138f7565b155f8061488f565b9091905f198382098382029182808310920391808303921461497b57670de0b6b3a764000082101561494b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906149c957508051156149a157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580614a0f575b6149da575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156149d256fea164736f6c634300081a000a"; - bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = + bytes public constant BYTECODE_MERKLE_FACTORY = hex"60808060405234601557613bb9908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c80631e3238761461044c5780634d7c0f11146103795763769bed201461003a575f80fd5b346103755760c03660031901126103755760043567ffffffffffffffff81116103755761006b9036906004016108c2565b602435906001600160a01b03821691828103610375576040366043190112610375576040519061009a8261080f565b60443564ffffffffff8116810361037557825260643564ffffffffff811681036103755760208301528251906020840151151583604086015192606087015160808801519160405180602081019460208652604082016100f9916109ca565b03601f198101825261010b908261082b565b60a08a01519360c08b0151604051818192519081602084019160200191610131926109a9565b810103808252610144906020018261082b565b61014d906109ef565b9060e08c01511515926040519560208701988961017c9164ffffffffff60208092828151168552015116910152565b6040875261018b60608861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a0161020f926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b7830161024c926109a9565b0160620103605501601f1981018252610265908261082b565b51902060405161157280820182811067ffffffffffffffff821117610361578291610ae88339608081526102c260406102a16080840189610a61565b92896020820152018664ffffffffff60208092828151168552015116910152565b03905ff59283156103565761031961033b937f2ba0fe49588281dbb122dd3b7f3e2b3396338f70dbe3c62bf3e3888b4ba7ffb8926001600160a01b036020971695869560405194859460c0865260c0860190610a61565b9289850152604084019064ffffffffff60208092828151168552015116910152565b608435608083015260a43560a08301520390a2604051908152f35b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b346103755760203660031901126103755760043567ffffffffffffffff811161037557366023820112156103755780600401359067ffffffffffffffff8211610375573660248360061b83010111610375575f90815b8383101561042d5760248360061b830101359067ffffffffffffffff82168092036103755767ffffffffffffffff160167ffffffffffffffff8111610419576001909201916103cf565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b346103755760a03660031901126103755760043567ffffffffffffffff81116103755761047d9036906004016108c2565b6024356001600160a01b03811690818103610375576044359067ffffffffffffffff8211610375573660238301121561037557816004013567ffffffffffffffff811161036157604051926104d860208360051b018561082b565b8184526024602085019260061b8201019036821161037557602401915b8183106107c2575050505f9082515f905b8082106107835750508451906020860151151584604088015192606089015160808a0151916040518060208101946020865260408201610545916109ca565b03601f1981018252610557908261082b565b8b60a08101519460c082015160405181819251908160208401916020019161057e926109a9565b810103808252610591906020018261082b565b61059a906109ef565b9160e001511515926040519586602081019960208b52604082016105bd91610a11565b03601f19810188526105cf908861082b565b6040519a8b9a60208c019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348d015260f81b60488c015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660498b01526bffffffffffffffffffffffff199060601b16604e8a015251908160628a01610653926109a9565b8701946062860152608285015260f81b60a28401526bffffffffffffffffffffffff199060601b1660a383015251918260b78301610690926109a9565b0160620103605501601f19810182526106a9908261082b565b519020604051611b538082019082821067ffffffffffffffff8311176103615782916106fa9161205a8439606081526106e5606082018a610a61565b90886020820152604081830391015286610a11565b03905ff58015610356576020947ffe44018cf74992b2720702385a1728bd329dd136e4f651203176c81c12710a8b926107626001600160a01b03610750941696879660405195869560c0875260c0870190610a61565b918a8601528482036040860152610a11565b906060830152606435608083015260843560a08301520390a2604051908152f35b909284518410156107ae5760019064ffffffffff6020808760051b8901015101511601930190610506565b634e487b7160e01b5f52603260045260245ffd5b60408336031261037557604051906107d98261080f565b83359067ffffffffffffffff8216820361037557826020926040945261080083870161085a565b838201528152019201916104f5565b6040810190811067ffffffffffffffff82111761036157604052565b90601f8019910116810190811067ffffffffffffffff82111761036157604052565b3590811515820361037557565b359064ffffffffff8216820361037557565b81601f820112156103755780359067ffffffffffffffff821161036157604051926108a1601f8401601f19166020018561082b565b8284526020838301011161037557815f926020809301838601378301015290565b919091610100818403126103755760405190610100820182811067ffffffffffffffff82111761036157604052819381356001600160a01b03811681036103755783526109116020830161084d565b60208401526109226040830161085a565b604084015260608201356001600160a01b0381168103610375576060840152608082013567ffffffffffffffff8111610375578161096191840161086c565b608084015260a082013560a084015260c08201359067ffffffffffffffff8211610375578261099960e094926109a49486940161086c565b60c08601520161084d565b910152565b5f5b8381106109ba5750505f910152565b81810151838201526020016109ab565b906020916109e3815180928185528580860191016109a9565b601f01601f1916010190565b602081519101519060208110610a03575090565b5f199060200360031b1b1690565b90602080835192838152019201905f5b818110610a2e5750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015260409094019390920191600101610a21565b906001600160a01b03825116815260208201511515602082015264ffffffffff60408301511660408201526001600160a01b03606083015116606082015260e080610adc610ac0608086015161010060808701526101008601906109ca565b60a086015160a086015260c086015185820360c08701526109ca565b93015115159101529056fe610160806040523461042857611572803803809161001d8285610560565b833981019080820390608082126104285780516001600160401b03811161042857810190610100828503126104285760405161010081016001600160401b038111828210176105355760405282516001600160a01b038116810361042857815261008960208401610583565b6020820190815261009c60408501610590565b60408301908152606085015194906001600160a01b0386168603610428576060840195865260808201516001600160401b03811161042857886100e09184016105de565b6080850190815260a08381015190860190815260c084015190999192916001600160401b0382116104285761011c60e09161012a9387016105de565b9460c0880195865201610583565b9360e0860194855260208701519560018060a01b038716998a880361042857604090603f1901126104285760408051989089016001600160401b0381118a8210176105355761018d9160609160405261018560408201610590565b8b5201610590565b9860208901998a52855151602081116105495750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c0525180519097906001600160401b03811161053557600154600181811c9116801561052b575b602082101461051757601f81116104b4575b506020601f821160011461044857819064ffffffffff98999a5f9261043d575b50508160011b915f199060031b1c1916176001555b5160e052516040516102736020828161026281830196878151938492016105bd565b81010301601f198101835282610560565b519051906020811061042c575b50610100525115156101205261014052511669ffffffffff0000000000600454925160281b169160018060501b031916171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102f0606486610560565b84519082855af16102ff610623565b816103f1575b50806103e7575b156103a2575b604051610e4e90816107248239608051818181610409015281816106440152610ae6015260a05181818161067501526109fe015260c0518181816101520152818161095501528181610c250152610d80015260e05181818161029f015261059d01526101005181610caa01526101205181818161069f01526109c201526101405181818161019501526107b40152f35b6103da6103df936040519063095ea7b360e01b602083015260248201525f6044820152604481526103d4606482610560565b82610652565b610652565b5f8080610312565b50803b151561030c565b8051801592508215610406575b50505f610305565b81925090602091810103126104285760206104219101610583565b5f806103fe565b5f80fd5b5f199060200360031b1b165f610280565b015190505f8061022b565b601f1982169960015f52815f209a5f5b81811061049c57509164ffffffffff999a9b91846001959410610484575b505050811b01600155610240565b01515f1960f88460031b161c191690555f8080610476565b838301518d556001909c019b60209384019301610458565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c8101916020841061050d575b601f0160051c01905b818110610502575061020b565b5f81556001016104f5565b90915081906104ec565b634e487b7160e01b5f52602260045260245ffd5b90607f16906101f9565b634e487b7160e01b5f52604160045260245ffd5b630f39860960e01b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b0382119082101761053557604052565b5190811515820361042857565b519064ffffffffff8216820361042857565b6001600160401b03811161053557601f01601f191660200190565b5f5b8381106105ce5750505f910152565b81810151838201526020016105bf565b81601f820112156104285780516105f4816105a2565b926106026040519485610560565b818452602082840101116104285761062091602080850191016105bd565b90565b3d1561064d573d90610634826105a2565b916106426040519384610560565b82523d5f602084013e565b606090565b5f8061067a9260018060a01b03169360208151910182865af1610673610623565b90836106c5565b80519081151591826106a2575b50506106905750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104285760206106bd9101610583565b155f80610687565b906106e957508051156106da57805190602001fd5b630a12f52160e11b5f5260045ffd5b8151158061071a575b6106fa575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156106f256fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610c94575080631686c90914610a2357806316c3549d146109e75780631bfd6814146109ab5780633bfe03a81461097d5780633f31ae3f1461042d5780634800d97f146103ea57806349fc73dd146102e65780634e390d3e146102c257806351e75e8b1461028857806375829def146101d357806390e64d13146101b95780639e93e57714610176578063bb4b573414610135578063ce516507146100f55763f851a440146100cc575f80fd5b346100f1575f3660031901126100f15760206001600160a01b035f5416604051908152f35b5f80fd5b346100f15760203660031901126100f157602061012b60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100f1575f3660031901126100f157602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f1575f3660031901126100f157602061012b610d78565b346100f15760203660031901126100f1576101ec610d24565b5f546001600160a01b03811633810361025957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100f1575f3660031901126100f15760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f1575f3660031901126100f157602064ffffffffff60035416604051908152f35b346100f1575f3660031901126100f1576040515f6001548060011c906001811680156103e0575b6020831081146103cc578285529081156103a8575060011461034a575b6103468361033a81850382610d56565b60405191829182610cdd565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061038e5750909150810160200161033a61032a565b919260018160209254838588010152019101909291610376565b60ff191660208086019190915291151560051b8401909101915061033a905061032a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161030d565b346100f1575f3660031901126100f15760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f15760803660031901126100f1576004356024356001600160a01b0381168091036100f157604435916fffffffffffffffffffffffffffffffff83168093036100f1576064359067ffffffffffffffff82116100f157366023830112156100f157816004013567ffffffffffffffff81116100f1578060051b92602484820101903682116100f1576040516020810190858252876040820152886060820152606081526104de608082610d56565b51902060405160208101918252602081526104fa604082610d56565b51902092610506610d78565b6109265761052b8560ff6001918060081c5f526002602052161b60405f205416151590565b6108fa5761053f6020604051970187610d56565b8552602401602085015b8282106108ea57505050935f945b83518610156105995760208660051b85010151908181105f14610588575f52602052600160405f205b950194610557565b905f52602052600160405f20610580565b84907f0000000000000000000000000000000000000000000000000000000000000000036108c25760035464ffffffffff8116156108a8575b508260081c5f52600260205260405f20600160ff85161b81541790556001600160a01b035f54169160405161060681610d3a565b5f81525f602082015260405193610100850185811067ffffffffffffffff8211176108945760405284526020840183815260408501838152606086017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808701907f00000000000000000000000000000000000000000000000000000000000000001515825260a08801927f000000000000000000000000000000000000000000000000000000000000000015158452604051946106cf86610d3a565b60045464ffffffffff8116875260281c64ffffffffff16602087015260c08a0195865260e08a01968752604051997fab167ccc000000000000000000000000000000000000000000000000000000008b52516001600160a01b031660048b0152516001600160a01b031660248a0152516fffffffffffffffffffffffffffffffff166044890152516001600160a01b03166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e48501525180516001600160a01b03166101048501526020015161012484015282807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61014492602095f1928315610889575f93610831575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610881575b8161084e60209383610d56565b810103126100f15792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6107f5565b3d9150610841565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff19164264ffffffffff1617600355836105d2565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610549565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100f1575f3660031901126100f157604060045464ffffffffff825191818116835260281c166020820152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f1575f3660031901126100f15760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f15760403660031901126100f157610a3c610d24565b6024356fffffffffffffffffffffffffffffffff81168091036100f1576001600160a01b035f5416338103610259575064ffffffffff6003541680151580610c5f575b80610c50575b610bf657506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610adc606485610d56565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610bea573d67ffffffffffffffff811161089457610b4f9160405191610b3f6020601f19601f8401160184610d56565b82523d5f602084013e5b83610db5565b8051908115159182610bc6575b5050610b9b57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100f157602001518015908115036100f1578480610b5c565b610b4f90606090610b49565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610c59610d78565b15610a85565b5062093a80810164ffffffffff8111610c805764ffffffffff164211610a7f565b634e487b7160e01b5f52601160045260245ffd5b346100f1575f3660031901126100f157610346907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261033a604082610d56565b9190916020815282518060208301525f5b818110610d0e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610cee565b600435906001600160a01b03821682036100f157565b6040810190811067ffffffffffffffff82111761089457604052565b90601f8019910116810190811067ffffffffffffffff82111761089457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610dad575090565b905042101590565b90610df25750805115610dca57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610e38575b610e03575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610dfb56fea164736f6c634300081a000a610180806040523461044857611b53803803809161001d82856106ab565b83398101906060818303126104485780516001600160401b03811161044857810161010081840312610448576040519061010082016001600160401b038111838210176105025760405280516001600160a01b0381168103610448578252610087602082016106ce565b916020810192835261009b604083016106db565b60408201908152606083015193906001600160a01b0385168503610448576060830194855260808401516001600160401b03811161044857876100df918601610729565b916080840192835260a08501519360a0810194855260c086015160018060401b0381116104485760e06101178b610125938a01610729565b9760c08401988952016106ce565b60e082019081526020890151989097906001600160a01b038a168a03610448576040810151906001600160401b03821161044857018a601f82011215610448578051906001600160401b0382116105025760209b8c6040519d8e61018e828760051b01826106ab565b858152019360061b8301019181831161044857602001925b82841061064f5750505050865151602081116106385750515f80546001600160a01b0319166001600160a01b0392831617905590511660805251151560a0525164ffffffffff1660c052518051906001600160401b0382116105025760015490600182811c9216801561062e575b602083101461061a5781601f8493116105ac575b50602090601f8311600114610546575f9261053b575b50508160011b915f199060031b1c1916176001555b5160e05251604051610286602082816102758183019687815193849201610708565b81010301601f1981018352826106ab565b519051906020811061052a575b506101005251151561012052610140528051905f915f915b81831061044c57836101605260018060a01b036080511660018060a01b03610140511690604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526102ff6064866106ab565b84519082855af161030e610782565b81610411575b5080610407575b156103c2575b6040516112d0908161088382396080518181816105590152818161088e0152610e8e015260a0518181816108b80152610daf015260c0518181816102a101528181610d0901528181610fcd0152611114015260e0518181816103ef01526107260152610100518161103e0152610120518181816108ea0152610d7301526101405181818161011f01526109d00152610160518181816102e5015261060a0152f35b6103fa6103ff936040519063095ea7b360e01b602083015260248201525f6044820152604481526103f46064826106ab565b826107b1565b6107b1565b808080610321565b50803b151561031b565b8051801592508215610426575b505084610314565b819250906020918101031261044857602061044191016106ce565b848061041e565b5f80fd5b91929091906001600160401b03610463858461076e565b5151166001600160401b03918216019081116105165792610484818361076e565b519060045491680100000000000000008310156105025760018301806004558310156104ee5760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ab565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f610293565b015190505f8061023e565b60015f9081528281209350601f198516905b818110610594575090846001959493921061057c575b505050811b01600155610253565b01515f1960f88460031b161c191690555f808061056e565b92936020600181928786015181550195019301610558565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610610575b90601f859493920160051c01905b8181106106025750610228565b5f81558493506001016105f5565b90915081906105e7565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610214565b630f39860960e01b5f52600452602060245260445ffd5b6040848303126104485760408051919082016001600160401b03811183821017610502576040528451906001600160401b038216820361044857826020926040945261069c8388016106db565b838201528152019301926101a6565b601f909101601f19168101906001600160401b0382119082101761050257604052565b5190811515820361044857565b519064ffffffffff8216820361044857565b6001600160401b03811161050257601f01601f191660200190565b5f5b8381106107195750505f910152565b818101518382015260200161070a565b81601f8201121561044857805161073f816106ed565b9261074d60405194856106ab565b818452602082840101116104485761076b9160208085019101610708565b90565b80518210156104ee5760209160051b010190565b3d156107ac573d90610793826106ed565b916107a160405193846106ab565b82523d5f602084013e565b606090565b5f806107d99260018060a01b03169360208151910182865af16107d2610782565b9083610824565b8051908115159182610801575b50506107ef5750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261044857602061081c91016106ce565b155f806107e6565b90610848575080511561083957805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610879575b610859575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561085156fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314611028575080631686c90914610dd457806316c3549d14610d985780631bfd681414610d5c5780633f31ae3f1461057d5780634800d97f1461053a57806349fc73dd146104365780634e390d3e1461041257806351e75e8b146103d857806375829def1461032357806390e64d1314610309578063936c63d9146102c5578063bb4b573414610284578063bf4ed03f14610183578063ce51650714610143578063da792468146101005763f851a440146100d7575f80fd5b346100fc575f3660031901126100fc5760206001600160a01b035f5416604051908152f35b5f80fd5b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760203660031901126100fc57602061017960043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100fc575f3660031901126100fc5760045461019f81611149565b906101ad60405192836110ea565b80825260045f9081526020830191907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b835b838310610247578486604051918291602083019060208452518091526040830191905f5b818110610211575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff168186015286955060409094019390920191600101610203565b600160208192604051610259816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906101df565b346100fc575f3660031901126100fc57602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc575f3660031901126100fc57602061017961110c565b346100fc5760203660031901126100fc5761033c6110b8565b5f546001600160a01b0381163381036103a957506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100fc575f3660031901126100fc5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100fc575f3660031901126100fc57602064ffffffffff60035416604051908152f35b346100fc575f3660031901126100fc576040515f6001548060011c90600181168015610530575b60208310811461051c578285529081156104f8575060011461049a575b6104968361048a818503826110ea565b60405191829182611071565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104de5750909150810160200161048a61047a565b9192600181602092548385880101520191019092916104c6565b60ff191660208086019190915291151560051b8401909101915061048a905061047a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161045d565b346100fc575f3660031901126100fc5760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100fc5760803660031901126100fc57600435602435906001600160a01b0382168092036100fc57604435916001600160801b038316918284036100fc576064359367ffffffffffffffff85116100fc57366023860112156100fc5784600401359467ffffffffffffffff86116100fc5760248660051b8201013681116100fc5767ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610d3157506040516020810190858252866040820152876060820152606081526106606080826110ea565b519020604051602081019182526020815261067c6040826110ea565b5190209161068861110c565b610cda576106ad8560ff6001918060081c5f526002602052161b60405f205416151590565b610cae576106ba88611149565b976106c8604051998a6110ea565b8852602401602088015b828210610c9e57505050925f935b8651851015610722576106f38588611161565b519081811015610711575f52602052600160405f205b9401936106e0565b905f52602052600160405f20610709565b85907f000000000000000000000000000000000000000000000000000000000000000003610c765760035464ffffffffff811615610c5c575b506004549261076984611149565b9361077760405195866110ea565b80855260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602087015b838310610c1f57505050505f84516107bd81611149565b956107cb60405197886110ea565b818752601f196107da83611149565b015f5b818110610bfc5750505f905b828210610b275750506001600160801b038216848111610b13578411610ae8575b5050508360081c5f52600260205260405f20600160ff86161b81541790556001600160a01b035f541692604051610840816110ce565b5f81525f60208201526040519161010083019583871067ffffffffffffffff881117610ad4576001600160a01b039660409492939452815260208101918583526040820185815260608301887f00000000000000000000000000000000000000000000000000000000000000001681528860808501917f0000000000000000000000000000000000000000000000000000000000000000151583526001600160801b0360a08701947f00000000000000000000000000000000000000000000000000000000000000001515865260c0880196875260e08801998a526040519c8d997f897f362b000000000000000000000000000000000000000000000000000000008b52602060048c0152816101448c019a511660248c0152511660448a0152511660648801525116608486015251151560a485015251151560c4840152519061012060e48401528151809152602061016484019201905f5b818110610a9f57505050819060208094516001600160a01b03815116610104850152015161012483015203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1928315610a94575f93610a3c575b50907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d60406020958594825191825287820152a3604051908152f35b939250906020843d602011610a8c575b81610a59602093836110ea565b810103126100fc5792519192907f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610a00565b3d9150610a4c565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610999565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610aff83925f190188611161565b51930316818351160116905284808061080a565b634e487b7160e01b5f52600160045260245ffd5b9092610b4867ffffffffffffffff610b3f8685611161565b51511687611189565b6001600160801b038111610bd1576001600160801b038091169164ffffffffff6020610b748887611161565b5101511660405190610b85826110ce565b8482526020820152610b97878c611161565b52610ba2868b611161565b5016016001600160801b038111610bbd5792600101906107e9565b634e487b7160e01b5f52601160045260245ffd5b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b602090604051610c0b816110ce565b5f81525f8382015282828c010152016107dd565b600160208192604051610c31816110ce565b64ffffffffff865467ffffffffffffffff8116835260401c16838201528152019201920191906107a6565b64ffffffffff19164264ffffffffff16176003558461075b565b7ffe365d76000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106d2565b847fcd4c86cc000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f99657b41000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc575f3660031901126100fc5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100fc5760403660031901126100fc57610ded6110b8565b6024356001600160801b0381168091036100fc576001600160a01b035f54163381036103a9575064ffffffffff6003541680151580611007575b80610ff8575b610f9e57506040515f806001600160a01b0360208401957fa9059cbb000000000000000000000000000000000000000000000000000000008752169485602485015284604485015260448452610e846064856110ea565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610f92573d67ffffffffffffffff8111610ad457610ef79160405191610ee76020601f19601f84011601846110ea565b82523d5f602084013e5b83611237565b8051908115159182610f6e575b5050610f4357507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100fc57602001518015908115036100fc578480610f04565b610ef790606090610ef1565b7f6df0cfdb000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b5061100161110c565b15610e2d565b5062093a80810164ffffffffff8111610bbd5764ffffffffff164211610e27565b346100fc575f3660031901126100fc57610496907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261048a6040826110ea565b9190916020815282518060208301525f5b8181106110a2575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611082565b600435906001600160a01b03821682036100fc57565b6040810190811067ffffffffffffffff821117610ad457604052565b90601f8019910116810190811067ffffffffffffffff821117610ad457604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611141575090565b905042101590565b67ffffffffffffffff8111610ad45760051b60200190565b80518210156111755760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b9091905f198382098382029182808310920391808303921461122657670de0b6b3a76400008210156111f6577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90611274575080511561124c57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b815115806112ba575b611285575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561127d56fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c08190526102e0819052610320819052610340819052610360819052610380526103a08190526103c0526103008190526100b6906100ad600435614824565b61032052614b1e565b61034052610300516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b61026052610300516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b501661028052610300516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b61036052610300516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b6020610240015190602460206001600160a01b0360c0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360c0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610521945f91614589575b50169116615318565b610340516103a05190939091906105ac600161054a6064610543818806615994565b96046154e9565b6020604051968261056489945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810186520184614710565b61016061024001519361012061024001519760e061024001519760405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260a06101605101516108eb6109ca60046007602760586106e260c0610160510151610160515190615a95565b60b76106ed5f615d85565b985f6102205260206102205261071560405161070c6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b6107298c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161076f81846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d282518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109858251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ac82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108eb610a3860046007602760586040516109fd6102205182614710565b5f815260b7610a0c6001615d85565b98601b6028610a1a8c615e90565b610a2384615f08565b8082111561456457505b019a6107298c6154e9565b61016083015261018082015260206101605101516108eb610a796004600760276058604051610a6a6102205182614710565b5f815260b7610a0c6002615d85565b8252602082015260286080610160510151604051610a9a6102205182614710565b5f81526108eb610ae46004600760276058610ab56003615d85565b9660b7610ac189615e90565b610aca8b615f08565b8082111561455c5750995b601b8c8c019a6107298c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7361010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b949190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf6610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d628183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119416118bc6073606b60405196610eeb6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113506101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193c60146022611409615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153e6025603589605e8751956102205189019661147f818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e282518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165585602361154c615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d5818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161e82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117df60726023611664615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f3815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173782609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e7615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119058251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e05261195561194f614d46565b856157b3565b938415614541575b5060c061010081905260405191906119759083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a528160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dcd6102205182614710565b5f8152955b156141d957604051611de66101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b6040519261201f6107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ee9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0c926146ca565b016032018082518093610220510191612a24926146ca565b018082518093610220510191612a39926146ca565b018082518093610220510191612a4e926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6e9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abe926146ca565b60805101815191826026830191610220510191612ada926146ca565b016026018082518093610220510191612af2926146ca565b0160a051519080826102205160a0510191612b0c926146ca565b0160e051519080826102205160e0510191612b26926146ca565b018082518093610220510191612b3b926146ca565b01610140515190808261022051610140510191612b57926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9991614710565b6101605160e0015190610160516101000151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b61038052610300518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b6102e0819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516103005182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103205161026051610340516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61032051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e0000000000000000610120518201529061200f565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd2565b61455591945061454f614d81565b906157b3565b925f61195d565b905099610ad5565b9050610a2d565b601b60d09a610720565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610518565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104b9565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b600d81527f4c6f636b7570204c696e65617200000000000000000000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b600e81527f4c6f636b75702044796e616d6963000000000000000000000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b600f81527f4c6f636b7570205472616e636865640000000000000000000000000000000000602082015290565b614a279083519384937f7498e3a50000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; @@ -210,27 +210,22 @@ contract Precompiles { require(address(batchLockup) != address(0), "Lockup Precompiles: deployment failed for BatchLockup contract"); } - /// @notice Deploys {SablierMerkleLockupFactory} from precompiled bytecode. - function deployMerkleLockupFactory() public returns (ISablierMerkleLockupFactory factory) { - bytes memory creationBytecode = BYTECODE_MERKLE_LOCKUP_FACTORY; + /// @notice Deploys {SablierMerkleFactory} from precompiled bytecode. + function deployMerkleFactory() public returns (ISablierMerkleFactory factory) { + bytes memory creationBytecode = BYTECODE_MERKLE_FACTORY; assembly { factory := create(0, add(creationBytecode, 0x20), mload(creationBytecode)) } - require( - address(factory) != address(0), "Lockup Precompiles: deployment failed for MerkleLockupFactory contract" - ); + require(address(factory) != address(0), "Lockup Precompiles: deployment failed for MerkleFactory contract"); } /// @notice Deploys all Periphery contracts in the following order: /// /// 1. {SablierBatchLockup} - /// 2. {SablierMerkleLockupFactory} - function deployPeriphery() - public - returns (ISablierBatchLockup batchLockup, ISablierMerkleLockupFactory merkleLockupFactory) - { + /// 2. {SablierMerkleFactory} + function deployPeriphery() public returns (ISablierBatchLockup batchLockup, ISablierMerkleFactory merkleFactory) { batchLockup = deployBatchLockup(); - merkleLockupFactory = deployMerkleLockupFactory(); + merkleFactory = deployMerkleFactory(); } /// @notice Deploys the entire Lockup Protocol from precompiled bytecode. @@ -240,7 +235,7 @@ contract Precompiles { /// 3. {SablierLockupLinear} /// 4. {SablierLockupTranched} /// 5. {SablierBatchLockup} - /// 6. {SablierMerkleLockupFactory} + /// 6. {SablierMerkleFactory} function deployProtocol(address initialAdmin) public returns ( @@ -249,13 +244,13 @@ contract Precompiles { ISablierLockupLinear lockupLinear, ISablierLockupTranched lockupTranched, ISablierBatchLockup batchLockup, - ISablierMerkleLockupFactory merkleLockupFactory + ISablierMerkleFactory merkleFactory ) { // Deploy Core. (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched) = deployCore(initialAdmin); // Deploy Periphery. - (batchLockup, merkleLockupFactory) = deployPeriphery(); + (batchLockup, merkleFactory) = deployPeriphery(); } } diff --git a/script/DeployDeterministicProtocol.s.sol b/script/DeployDeterministicProtocol.s.sol index b506fdece..ca753bd5c 100644 --- a/script/DeployDeterministicProtocol.s.sol +++ b/script/DeployDeterministicProtocol.s.sol @@ -5,7 +5,7 @@ import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; -import { SablierMerkleLockupFactory } from "../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "./Base.s.sol"; @@ -23,7 +23,7 @@ contract DeployDeterministicProtocol is BaseScript { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleFactory ) { bytes32 salt = constructCreate2Salt(); @@ -38,6 +38,6 @@ contract DeployDeterministicProtocol is BaseScript { // Deploy Periphery. batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); + merkleFactory = new SablierMerkleFactory{ salt: salt }(); } } diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol index 5c5ce05d1..07fd2ad46 100644 --- a/script/DeployProtocol.s.sol +++ b/script/DeployProtocol.s.sol @@ -5,7 +5,7 @@ import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; -import { SablierMerkleLockupFactory } from "../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "./Base.s.sol"; @@ -23,7 +23,7 @@ contract DeployProtocol is BaseScript { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleFactory ) { // Deploy Core. @@ -34,6 +34,6 @@ contract DeployProtocol is BaseScript { // Deploy Periphery. batchLockup = new SablierBatchLockup(); - merkleLockupFactory = new SablierMerkleLockupFactory(); + merkleFactory = new SablierMerkleFactory(); } } diff --git a/script/periphery/CreateMerkleInstant.s.sol b/script/periphery/CreateMerkleInstant.s.sol new file mode 100644 index 000000000..b4ca6f39e --- /dev/null +++ b/script/periphery/CreateMerkleInstant.s.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierMerkleFactory } from "../../src/periphery/interfaces/ISablierMerkleFactory.sol"; +import { ISablierMerkleInstant } from "../../src/periphery/interfaces/ISablierMerkleInstant.sol"; +import { MerkleBase } from "../../src/periphery/types/DataTypes.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract CreateMerkleInstant is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (ISablierMerkleInstant merkleInstant) { + // Prepare the constructor parameters. + // TODO: Update address once deployed. + ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); + + MerkleBase.ConstructorParams memory baseParams; + baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); + baseParams.expiration = uint40(block.timestamp + 30 days); + baseParams.initialAdmin = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; + baseParams.ipfsCID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; + baseParams.merkleRoot = 0x0000000000000000000000000000000000000000000000000000000000000000; + baseParams.name = "The Boys Instant"; + + uint256 campaignTotalAmount = 10_000e18; + uint256 recipientCount = 100; + + // Deploy MerkleInstant contract. + merkleInstant = merkleFactory.createMerkleInstant(baseParams, campaignTotalAmount, recipientCount); + } +} diff --git a/script/periphery/CreateMerkleLL.s.sol b/script/periphery/CreateMerkleLL.s.sol index d780b97a9..823fd2f7c 100644 --- a/script/periphery/CreateMerkleLL.s.sol +++ b/script/periphery/CreateMerkleLL.s.sol @@ -5,9 +5,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { LockupLinear } from "../../src/core/types/DataTypes.sol"; +import { ISablierMerkleFactory } from "../../src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleLL } from "../../src/periphery/interfaces/ISablierMerkleLL.sol"; -import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; -import { MerkleLockup } from "../../src/periphery/types/DataTypes.sol"; +import { MerkleBase } from "../../src/periphery/types/DataTypes.sol"; import { BaseScript } from "../Base.s.sol"; @@ -15,30 +15,27 @@ contract CreateMerkleLL is BaseScript { /// @dev Deploy via Forge. function run() public virtual broadcast returns (ISablierMerkleLL merkleLL) { // Prepare the constructor parameters. - ISablierMerkleLockupFactory merkleLockupFactory = - ISablierMerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); // TODO: Update address once deployed. + // TODO: Update address once deployed. + ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); - MerkleLockup.ConstructorParams memory baseParams; + MerkleBase.ConstructorParams memory baseParams; baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); - baseParams.cancelable = true; baseParams.expiration = uint40(block.timestamp + 30 days); baseParams.initialAdmin = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; baseParams.ipfsCID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; baseParams.merkleRoot = 0x0000000000000000000000000000000000000000000000000000000000000000; baseParams.name = "The Boys LL"; - baseParams.transferable = true; - - // TODO: Update address once deployed. - ISablierLockupLinear lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); - LockupLinear.Durations memory streamDurations; - streamDurations.cliff = 0; - streamDurations.total = 3600; - uint256 campaignTotalAmount = 10_000e18; - uint256 recipientCount = 100; // Deploy MerkleLL contract. - merkleLL = merkleLockupFactory.createMerkleLL( - baseParams, lockupLinear, streamDurations, campaignTotalAmount, recipientCount - ); + // TODO: Update address once deployed. + merkleLL = merkleFactory.createMerkleLL({ + baseParams: baseParams, + lockupLinear: ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E), + cancelable: true, + transferable: true, + streamDurations: LockupLinear.Durations({ cliff: 0, total: 3600 }), + aggregateAmount: 10_000e18, + recipientCount: 100 + }); } } diff --git a/script/periphery/CreateMerkleLT.s.sol b/script/periphery/CreateMerkleLT.s.sol index 3195c6f9b..04be87319 100644 --- a/script/periphery/CreateMerkleLT.s.sol +++ b/script/periphery/CreateMerkleLT.s.sol @@ -5,9 +5,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD2x18 } from "@prb/math/src/UD2x18.sol"; import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; -import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleFactory } from "../../src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleLT } from "../../src/periphery/interfaces/ISablierMerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; import { BaseScript } from "../Base.s.sol"; @@ -15,32 +15,33 @@ contract CreateMerkleLT is BaseScript { /// @dev Deploy via Forge. function run() public virtual broadcast returns (ISablierMerkleLT merkleLT) { // Prepare the constructor parameters. - ISablierMerkleLockupFactory merkleLockupFactory = - ISablierMerkleLockupFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); // TODO: Update address once deployed. + // TODO: Update address once deployed. + ISablierMerkleFactory merkleFactory = ISablierMerkleFactory(0xF35aB407CF28012Ba57CAF5ee2f6d6E4420253bc); - MerkleLockup.ConstructorParams memory baseParams; + MerkleBase.ConstructorParams memory baseParams; baseParams.asset = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); - baseParams.cancelable = true; baseParams.expiration = uint40(block.timestamp + 30 days); baseParams.initialAdmin = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; baseParams.ipfsCID = "QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR"; baseParams.merkleRoot = 0x0000000000000000000000000000000000000000000000000000000000000000; baseParams.name = "The Boys LT"; - baseParams.transferable = true; - // TODO: Update address once deployed. - ISablierLockupTranched lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = new MerkleLT.TrancheWithPercentage[](2); tranchesWithPercentages[0] = MerkleLT.TrancheWithPercentage({ unlockPercentage: UD2x18.wrap(50), duration: 3600 }); tranchesWithPercentages[1] = MerkleLT.TrancheWithPercentage({ unlockPercentage: UD2x18.wrap(50), duration: 7200 }); - uint256 campaignTotalAmount = 10_000e18; - uint256 recipientCount = 100; // Deploy MerkleLT contract. - merkleLT = merkleLockupFactory.createMerkleLT( - baseParams, lockupTranched, tranchesWithPercentages, campaignTotalAmount, recipientCount - ); + // TODO: Update address once deployed. + merkleLT = merkleFactory.createMerkleLT({ + baseParams: baseParams, + lockupTranched: ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8), + cancelable: true, + transferable: true, + tranchesWithPercentages: tranchesWithPercentages, + aggregateAmount: 10_000e18, + recipientCount: 100 + }); } } diff --git a/script/periphery/DeployDeterministicPeriphery.s.sol b/script/periphery/DeployDeterministicPeriphery.s.sol index 8cde8dc60..40c8bf2ac 100644 --- a/script/periphery/DeployDeterministicPeriphery.s.sol +++ b/script/periphery/DeployDeterministicPeriphery.s.sol @@ -2,14 +2,14 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; -import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all Periphery contracts at deterministic addresses across chains, in the following order: /// /// 1. {SablierBatchLockup} -/// 2. {SablierMerkleLockupFactory} +/// 2. {SablierMerkleFactory} /// /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicPeriphery is BaseScript { @@ -18,10 +18,10 @@ contract DeployDeterministicPeriphery is BaseScript { public virtual broadcast - returns (SablierBatchLockup batchLockup, SablierMerkleLockupFactory merkleLockupFactory) + returns (SablierBatchLockup batchLockup, SablierMerkleFactory merkleFactory) { bytes32 salt = constructCreate2Salt(); batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); + merkleFactory = new SablierMerkleFactory{ salt: salt }(); } } diff --git a/script/periphery/DeployMerkleFactory.s.sol b/script/periphery/DeployMerkleFactory.s.sol new file mode 100644 index 000000000..c44cea888 --- /dev/null +++ b/script/periphery/DeployMerkleFactory.s.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; + +import { BaseScript } from "../Base.s.sol"; + +contract DeployMerkleFactory is BaseScript { + /// @dev Deploy via Forge. + function run() public virtual broadcast returns (SablierMerkleFactory merkleFactory) { + merkleFactory = new SablierMerkleFactory(); + } +} diff --git a/script/periphery/DeployMerkleLockupFactory.s.sol b/script/periphery/DeployMerkleLockupFactory.s.sol deleted file mode 100644 index 4b84e4c62..000000000 --- a/script/periphery/DeployMerkleLockupFactory.s.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; - -import { BaseScript } from "../Base.s.sol"; - -contract DeployMerkleLockupFactory is BaseScript { - /// @dev Deploy via Forge. - function run() public virtual broadcast returns (SablierMerkleLockupFactory merkleLockupFactory) { - merkleLockupFactory = new SablierMerkleLockupFactory(); - } -} diff --git a/script/periphery/DeployPeriphery.s.sol b/script/periphery/DeployPeriphery.s.sol index 519272717..9e8d554d2 100644 --- a/script/periphery/DeployPeriphery.s.sol +++ b/script/periphery/DeployPeriphery.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22 <0.9.0; -import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { BaseScript } from "../Base.s.sol"; @@ -9,16 +9,16 @@ import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all Periphery contract in the following order: /// /// 1. {SablierBatchLockup} -/// 2. {SablierMerkleLockupFactory} +/// 2. {SablierMerkleFactory} contract DeployPeriphery is BaseScript { /// @dev Deploy via Forge. function run() public virtual broadcast - returns (SablierBatchLockup batchLockup, SablierMerkleLockupFactory merkleLockupFactory) + returns (SablierBatchLockup batchLockup, SablierMerkleFactory merkleFactory) { batchLockup = new SablierBatchLockup(); - merkleLockupFactory = new SablierMerkleLockupFactory(); + merkleFactory = new SablierMerkleFactory(); } } diff --git a/shell/deploy-multi-chain.sh b/shell/deploy-multi-chain.sh index 89dec2660..5ee8ecf78 100755 --- a/shell/deploy-multi-chain.sh +++ b/shell/deploy-multi-chain.sh @@ -360,7 +360,7 @@ for chain in "${provided_chains[@]}"; do lockupDynamic_address=$(echo "${output}" | awk '/lockupDynamic: contract/{print $NF}') lockupLinear_address=$(echo "${output}" | awk '/lockupLinear: contract/{print $NF}') lockupTranched_address=$(echo "${output}" | awk '/lockupTranched: contract/{print $NF}') - merkleLockupFactory_address=$(echo "${output}" | awk '/merkleLockupFactory: contract/{print $NF}') + merkleFactory_address=$(echo "${output}" | awk '/merkleFactory: contract/{print $NF}') nftDescriptor_address=$(echo "${output}" | awk '/nftDescriptor: contract/{print $NF}') # Save to the chain file @@ -372,7 +372,7 @@ for chain in "${provided_chains[@]}"; do echo "SablierLockupTranched = ${lockupTranched_address}" echo "Periphery Contracts" echo "SablierBatchLockup = ${batchLockup_address}" - echo "SablierMerkleLockupFactory = ${merkleLockupFactory_address}" + echo "SablierMerkleFactory = ${merkleFactory_address}" } >> "$chain_file" echo -e "${SC}${TICK} Deployed on ${chain}. You can find the addresses in ${chain_file}${NC}" diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh index 9a57d1775..8135739a3 100755 --- a/shell/prepare-artifacts.sh +++ b/shell/prepare-artifacts.sh @@ -52,14 +52,16 @@ cp out-optimized/Errors.sol/Errors.json $core_libraries periphery=./artifacts/periphery cp out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json $periphery +cp out-optimized/SablierMerkleFactory.sol/SablierMerkleFactory.json $periphery +cp out-optimized/SablierMerkleInstant.sol/SablierMerkleInstant.json $periphery cp out-optimized/SablierMerkleLL.sol/SablierMerkleLL.json $periphery -cp out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json $periphery cp out-optimized/SablierMerkleLT.sol/SablierMerkleLT.json $periphery periphery_interfaces=./artifacts/periphery/interfaces cp out-optimized/ISablierBatchLockup.sol/ISablierBatchLockup.json $periphery_interfaces +cp out-optimized/ISablierMerkleFactory.sol/ISablierMerkleFactory.json $periphery_interfaces +cp out-optimized/ISablierMerkleInstant.sol/ISablierMerkleInstant.json $periphery_interfaces cp out-optimized/ISablierMerkleLL.sol/ISablierMerkleLL.json $periphery_interfaces -cp out-optimized/ISablierMerkleLockupFactory.sol/ISablierMerkleLockupFactory.json $periphery_interfaces cp out-optimized/ISablierMerkleLT.sol/ISablierMerkleLT.json $periphery_interfaces periphery_libraries=./artifacts/periphery/libraries diff --git a/shell/update-precompiles.sh b/shell/update-precompiles.sh index 4b1b0a80e..1e42d0104 100755 --- a/shell/update-precompiles.sh +++ b/shell/update-precompiles.sh @@ -16,7 +16,7 @@ batch_lockup=$(cat out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json lockup_dynamic=$(cat out-optimized/SablierLockupDynamic.sol/SablierLockupDynamic.json | jq -r '.bytecode.object' | cut -c 3-) lockup_linear=$(cat out-optimized/SablierLockupLinear.sol/SablierLockupLinear.json | jq -r '.bytecode.object' | cut -c 3-) lockup_tranched=$(cat out-optimized/SablierLockupTranched.sol/SablierLockupTranched.json | jq -r '.bytecode.object' | cut -c 3-) -merkle_lockup_factory=$(cat out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json | jq -r '.bytecode.object' | cut -c 3-) +merkle_factory=$(cat out-optimized/SablierMerkleFactory.sol/SablierMerkleFactory.json | jq -r '.bytecode.object' | cut -c 3-) nft_descriptor=$(cat out-optimized/LockupNFTDescriptor.sol/LockupNFTDescriptor.json | jq -r '.bytecode.object' | cut -c 3-) precompiles_path="precompiles/Precompiles.sol" @@ -30,7 +30,7 @@ sd "(BYTECODE_BATCH_LOCKUP =)[^;]+;" "\$1 hex\"$batch_lockup\";" $precompiles_pa sd "(BYTECODE_LOCKUP_DYNAMIC =)[^;]+;" "\$1 hex\"$lockup_dynamic\";" $precompiles_path sd "(BYTECODE_LOCKUP_LINEAR =)[^;]+;" "\$1 hex\"$lockup_linear\";" $precompiles_path sd "(BYTECODE_LOCKUP_TRANCHED =)[^;]+;" "\$1 hex\"$lockup_tranched\";" $precompiles_path -sd "(BYTECODE_MERKLE_LOCKUP_FACTORY =)[^;]+;" "\$1 hex\"$merkle_lockup_factory\";" $precompiles_path +sd "(BYTECODE_MERKLE_FACTORY =)[^;]+;" "\$1 hex\"$merkle_factory\";" $precompiles_path sd "(BYTECODE_NFT_DESCRIPTOR =)[^;]+;" "\$1 hex\"$nft_descriptor\";" $precompiles_path # Reformat the code with Forge diff --git a/src/periphery/SablierMerkleLockupFactory.sol b/src/periphery/SablierMerkleFactory.sol similarity index 56% rename from src/periphery/SablierMerkleLockupFactory.sol rename to src/periphery/SablierMerkleFactory.sol index 196ed64c3..3cb2260fb 100644 --- a/src/periphery/SablierMerkleLockupFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -7,21 +7,23 @@ import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.so import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; import { LockupLinear } from "../core/types/DataTypes.sol"; +import { ISablierMerkleFactory } from "./interfaces/ISablierMerkleFactory.sol"; +import { ISablierMerkleInstant } from "./interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; -import { ISablierMerkleLockupFactory } from "./interfaces/ISablierMerkleLockupFactory.sol"; import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; +import { SablierMerkleInstant } from "./SablierMerkleInstant.sol"; import { SablierMerkleLL } from "./SablierMerkleLL.sol"; import { SablierMerkleLT } from "./SablierMerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "./types/DataTypes.sol"; -/// @title SablierMerkleLockupFactory -/// @notice See the documentation in {ISablierMerkleLockupFactory}. -contract SablierMerkleLockupFactory is ISablierMerkleLockupFactory { +/// @title SablierMerkleFactory +/// @notice See the documentation in {ISablierMerkleFactory}. +contract SablierMerkleFactory is ISablierMerkleFactory { /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLockupFactory + /// @inheritdoc ISablierMerkleFactory function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) external pure @@ -39,10 +41,41 @@ contract SablierMerkleLockupFactory is ISablierMerkleLockupFactory { USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice inheritdoc ISablierMerkleLockupFactory + /// @notice inheritdoc ISablierMerkleFactory + function createMerkleInstant( + MerkleBase.ConstructorParams memory baseParams, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierMerkleInstant merkleInstant) + { + // Hash the parameters to generate a salt. + bytes32 salt = keccak256( + abi.encodePacked( + msg.sender, + baseParams.asset, + baseParams.expiration, + baseParams.initialAdmin, + abi.encode(baseParams.ipfsCID), + baseParams.merkleRoot, + bytes32(abi.encodePacked(baseParams.name)) + ) + ); + + // Deploy the MerkleInstant contract with CREATE2. + merkleInstant = new SablierMerkleInstant{ salt: salt }(baseParams); + + // Log the creation of the MerkleInstant contract, including some metadata that is not stored on-chain. + emit CreateMerkleInstant(merkleInstant, baseParams, aggregateAmount, recipientCount); + } + + /// @notice inheritdoc ISablierMerkleFactory function createMerkleLL( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupLinear lockupLinear, + bool cancelable, + bool transferable, LockupLinear.Durations memory streamDurations, uint256 aggregateAmount, uint256 recipientCount @@ -55,29 +88,41 @@ contract SablierMerkleLockupFactory is ISablierMerkleLockupFactory { abi.encodePacked( msg.sender, baseParams.asset, - baseParams.cancelable, baseParams.expiration, baseParams.initialAdmin, abi.encode(baseParams.ipfsCID), baseParams.merkleRoot, bytes32(abi.encodePacked(baseParams.name)), - baseParams.transferable, lockupLinear, + cancelable, + transferable, abi.encode(streamDurations) ) ); - // Deploy the MerkleLockup contract with CREATE2. - merkleLL = new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, streamDurations); + // Deploy the MerkleLL contract with CREATE2. + merkleLL = + new SablierMerkleLL{ salt: salt }(baseParams, lockupLinear, cancelable, transferable, streamDurations); - // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. - emit CreateMerkleLL(merkleLL, baseParams, lockupLinear, streamDurations, aggregateAmount, recipientCount); + // Log the creation of the MerkleLL contract, including some metadata that is not stored on-chain. + emit CreateMerkleLL( + merkleLL, + baseParams, + lockupLinear, + cancelable, + transferable, + streamDurations, + aggregateAmount, + recipientCount + ); } - /// @notice inheritdoc ISablierMerkleLockupFactory + /// @notice inheritdoc ISablierMerkleFactory function createMerkleLT( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupTranched lockupTranched, + bool cancelable, + bool transferable, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, uint256 aggregateAmount, uint256 recipientCount @@ -104,26 +149,30 @@ contract SablierMerkleLockupFactory is ISablierMerkleLockupFactory { abi.encodePacked( msg.sender, baseParams.asset, - baseParams.cancelable, baseParams.expiration, baseParams.initialAdmin, abi.encode(baseParams.ipfsCID), baseParams.merkleRoot, bytes32(abi.encodePacked(baseParams.name)), - baseParams.transferable, lockupTranched, + cancelable, + transferable, abi.encode(tranchesWithPercentages) ) ); - // Deploy the MerkleLockup contract with CREATE2. - merkleLT = new SablierMerkleLT{ salt: salt }(baseParams, lockupTranched, tranchesWithPercentages); + // Deploy the MerkleLT contract with CREATE2. + merkleLT = new SablierMerkleLT{ salt: salt }( + baseParams, lockupTranched, cancelable, transferable, tranchesWithPercentages + ); - // Log the creation of the MerkleLockup contract, including some metadata that is not stored on-chain. + // Log the creation of the MerkleLT contract, including some metadata that is not stored on-chain. emit CreateMerkleLT( merkleLT, baseParams, lockupTranched, + cancelable, + transferable, tranchesWithPercentages, totalDuration, aggregateAmount, diff --git a/src/periphery/SablierMerkleInstant.sol b/src/periphery/SablierMerkleInstant.sol new file mode 100644 index 000000000..62c3450d1 --- /dev/null +++ b/src/periphery/SablierMerkleInstant.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import { SablierMerkleBase } from "./abstracts/SablierMerkleBase.sol"; +import { ISablierMerkleInstant } from "./interfaces/ISablierMerkleInstant.sol"; +import { MerkleBase } from "./types/DataTypes.sol"; + +/// @title SablierMerkleInstant +/// @notice See the documentation in {ISablierMerkleInstant}. +contract SablierMerkleInstant is + ISablierMerkleInstant, // 2 inherited components + SablierMerkleBase // 4 inherited components +{ + using BitMaps for BitMaps.BitMap; + using SafeERC20 for IERC20; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Constructs the contract by initializing the immutable state variables. + constructor(MerkleBase.ConstructorParams memory baseParams) SablierMerkleBase(baseParams) { } + + /*////////////////////////////////////////////////////////////////////////// + USER-FACING NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierMerkleInstant + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + override + { + // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second + // preimage attacks. + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); + + // Check: validate the function. + _checkClaim(index, leaf, merkleProof); + + // Effect: mark the index as claimed. + _claimedBitMap.set(index); + + // Interaction: withdraw the assets to the recipient. + ASSET.safeTransfer(recipient, amount); + + // Log the claim. + emit Claim(index, recipient, amount); + } +} diff --git a/src/periphery/SablierMerkleLL.sol b/src/periphery/SablierMerkleLL.sol index 85587d3f6..e56967d37 100644 --- a/src/periphery/SablierMerkleLL.sol +++ b/src/periphery/SablierMerkleLL.sol @@ -9,15 +9,15 @@ import { ud } from "@prb/math/src/UD60x18.sol"; import { ISablierLockupLinear } from "../core/interfaces/ISablierLockupLinear.sol"; import { Broker, LockupLinear } from "../core/types/DataTypes.sol"; -import { SablierMerkleLockup } from "./abstracts/SablierMerkleLockup.sol"; +import { SablierMerkleBase } from "./abstracts/SablierMerkleBase.sol"; import { ISablierMerkleLL } from "./interfaces/ISablierMerkleLL.sol"; -import { MerkleLockup } from "./types/DataTypes.sol"; +import { MerkleBase } from "./types/DataTypes.sol"; /// @title SablierMerkleLL /// @notice See the documentation in {ISablierMerkleLL}. contract SablierMerkleLL is ISablierMerkleLL, // 2 inherited components - SablierMerkleLockup // 4 inherited components + SablierMerkleBase // 4 inherited components { using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; @@ -26,9 +26,15 @@ contract SablierMerkleLL is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierMerkleLL + bool public immutable override CANCELABLE; + /// @inheritdoc ISablierMerkleLL ISablierLockupLinear public immutable override LOCKUP_LINEAR; + /// @inheritdoc ISablierMerkleLL + bool public immutable override TRANSFERABLE; + /// @inheritdoc ISablierMerkleLL LockupLinear.Durations public override streamDurations; @@ -39,16 +45,20 @@ contract SablierMerkleLL is /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Lockup /// contract. constructor( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupLinear lockupLinear, + bool cancelable, + bool transferable, LockupLinear.Durations memory streamDurations_ ) - SablierMerkleLockup(baseParams) + SablierMerkleBase(baseParams) { + CANCELABLE = cancelable; LOCKUP_LINEAR = lockupLinear; + TRANSFERABLE = transferable; streamDurations = streamDurations_; - // Max approve the Lockup contract to spend funds from the MerkleLockup contract. + // Max approve the Lockup contract to spend funds from the MerkleLL contract. ASSET.forceApprove(address(LOCKUP_LINEAR), type(uint256).max); } diff --git a/src/periphery/SablierMerkleLT.sol b/src/periphery/SablierMerkleLT.sol index 0b0ecdedd..a1f41c59a 100644 --- a/src/periphery/SablierMerkleLT.sol +++ b/src/periphery/SablierMerkleLT.sol @@ -10,16 +10,16 @@ import { UD60x18, ud60x18, ZERO } from "@prb/math/src/UD60x18.sol"; import { ISablierLockupTranched } from "../core/interfaces/ISablierLockupTranched.sol"; import { Broker, LockupTranched } from "../core/types/DataTypes.sol"; -import { SablierMerkleLockup } from "./abstracts/SablierMerkleLockup.sol"; +import { SablierMerkleBase } from "./abstracts/SablierMerkleBase.sol"; import { ISablierMerkleLT } from "./interfaces/ISablierMerkleLT.sol"; import { Errors } from "./libraries/Errors.sol"; -import { MerkleLockup, MerkleLT } from "./types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "./types/DataTypes.sol"; /// @title SablierMerkleLT /// @notice See the documentation in {ISablierMerkleLT}. contract SablierMerkleLT is ISablierMerkleLT, // 2 inherited components - SablierMerkleLockup // 4 inherited components + SablierMerkleBase // 4 inherited components { using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; @@ -28,12 +28,18 @@ contract SablierMerkleLT is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierMerkleLT + bool public immutable override CANCELABLE; + /// @inheritdoc ISablierMerkleLT ISablierLockupTranched public immutable override LOCKUP_TRANCHED; /// @inheritdoc ISablierMerkleLT uint64 public immutable override TOTAL_PERCENTAGE; + /// @inheritdoc ISablierMerkleLT + bool public immutable override TRANSFERABLE; + /// @dev The tranches with their respective unlock percentages and durations. MerkleLT.TrancheWithPercentage[] internal _tranchesWithPercentages; @@ -44,13 +50,17 @@ contract SablierMerkleLT is /// @dev Constructs the contract by initializing the immutable state variables, and max approving the Lockup /// contract. constructor( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupTranched lockupTranched, + bool cancelable, + bool transferable, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages ) - SablierMerkleLockup(baseParams) + SablierMerkleBase(baseParams) { + CANCELABLE = cancelable; LOCKUP_TRANCHED = lockupTranched; + TRANSFERABLE = transferable; uint256 count = tranchesWithPercentages.length; @@ -63,7 +73,7 @@ contract SablierMerkleLT is } TOTAL_PERCENTAGE = totalPercentage; - // Max approve the Lockup contract to spend funds from the MerkleLockup contract. + // Max approve the Lockup contract to spend funds from the MerkleLT contract. ASSET.forceApprove(address(LOCKUP_TRANCHED), type(uint256).max); } diff --git a/src/periphery/abstracts/SablierMerkleLockup.sol b/src/periphery/abstracts/SablierMerkleBase.sol similarity index 76% rename from src/periphery/abstracts/SablierMerkleLockup.sol rename to src/periphery/abstracts/SablierMerkleBase.sol index 788b7944d..fcfe60722 100644 --- a/src/periphery/abstracts/SablierMerkleLockup.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -8,14 +8,14 @@ import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { Adminable } from "../../core/abstracts/Adminable.sol"; -import { ISablierMerkleLockup } from "../interfaces/ISablierMerkleLockup.sol"; -import { MerkleLockup } from "../types/DataTypes.sol"; +import { ISablierMerkleBase } from "../interfaces/ISablierMerkleBase.sol"; +import { MerkleBase } from "../types/DataTypes.sol"; import { Errors } from "../libraries/Errors.sol"; -/// @title SablierMerkleLockup -/// @notice See the documentation in {ISablierMerkleLockup}. -abstract contract SablierMerkleLockup is - ISablierMerkleLockup, // 2 inherited component +/// @title SablierMerkleBase +/// @notice See the documentation in {ISablierMerkleBase}. +abstract contract SablierMerkleBase is + ISablierMerkleBase, // 2 inherited component Adminable // 1 inherited component { using BitMaps for BitMaps.BitMap; @@ -25,25 +25,19 @@ abstract contract SablierMerkleLockup is STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase IERC20 public immutable override ASSET; - /// @inheritdoc ISablierMerkleLockup - bool public immutable override CANCELABLE; - - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase uint40 public immutable override EXPIRATION; - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase bytes32 public immutable override MERKLE_ROOT; /// @dev The name of the campaign stored as bytes32. bytes32 internal immutable NAME; - /// @inheritdoc ISablierMerkleLockup - bool public immutable override TRANSFERABLE; - - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase string public ipfsCID; /// @dev Packed booleans that record the history of claims. @@ -57,45 +51,40 @@ abstract contract SablierMerkleLockup is //////////////////////////////////////////////////////////////////////////*/ /// @dev Constructs the contract by initializing the immutable state variables. - constructor(MerkleLockup.ConstructorParams memory params) { + constructor(MerkleBase.ConstructorParams memory params) { // Check: the campaign name is not greater than 32 bytes if (bytes(params.name).length > 32) { - revert Errors.SablierMerkleLockup_CampaignNameTooLong({ - nameLength: bytes(params.name).length, - maxLength: 32 - }); + revert Errors.SablierMerkleBase_CampaignNameTooLong({ nameLength: bytes(params.name).length, maxLength: 32 }); } admin = params.initialAdmin; ASSET = params.asset; - CANCELABLE = params.cancelable; EXPIRATION = params.expiration; ipfsCID = params.ipfsCID; MERKLE_ROOT = params.merkleRoot; NAME = bytes32(abi.encodePacked(params.name)); - TRANSFERABLE = params.transferable; } /*////////////////////////////////////////////////////////////////////////// USER-FACING CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase function getFirstClaimTime() external view override returns (uint40) { return _firstClaimTime; } - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase function hasClaimed(uint256 index) public view override returns (bool) { return _claimedBitMap.get(index); } - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase function hasExpired() public view override returns (bool) { return EXPIRATION > 0 && EXPIRATION <= block.timestamp; } - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase function name() external view override returns (string memory) { return string(abi.encodePacked(NAME)); } @@ -104,11 +93,11 @@ abstract contract SablierMerkleLockup is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLockup + /// @inheritdoc ISablierMerkleBase function clawback(address to, uint128 amount) external override onlyAdmin { // Check: current timestamp is over the grace period and the campaign has not expired. if (_hasGracePeriodPassed() && !hasExpired()) { - revert Errors.SablierMerkleLockup_ClawbackNotAllowed({ + revert Errors.SablierMerkleBase_ClawbackNotAllowed({ blockTimestamp: block.timestamp, expiration: EXPIRATION, firstClaimTime: _firstClaimTime @@ -140,17 +129,17 @@ abstract contract SablierMerkleLockup is function _checkClaim(uint256 index, bytes32 leaf, bytes32[] calldata merkleProof) internal { // Check: the campaign has not expired. if (hasExpired()) { - revert Errors.SablierMerkleLockup_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); + revert Errors.SablierMerkleBase_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); } // Check: the index has not been claimed. if (_claimedBitMap.get(index)) { - revert Errors.SablierMerkleLockup_StreamClaimed(index); + revert Errors.SablierMerkleBase_StreamClaimed(index); } // Check: the input claim is included in the Merkle tree. if (!MerkleProof.verify(merkleProof, MERKLE_ROOT, leaf)) { - revert Errors.SablierMerkleLockup_InvalidProof(); + revert Errors.SablierMerkleBase_InvalidProof(); } // Effect: set the `_firstClaimTime` if its zero. diff --git a/src/periphery/interfaces/ISablierMerkleLockup.sol b/src/periphery/interfaces/ISablierMerkleBase.sol similarity index 74% rename from src/periphery/interfaces/ISablierMerkleLockup.sol rename to src/periphery/interfaces/ISablierMerkleBase.sol index 750ca3655..d2426033e 100644 --- a/src/periphery/interfaces/ISablierMerkleLockup.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -5,19 +5,13 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IAdminable } from "../../core/interfaces/IAdminable.sol"; -/// @title ISablierMerkleLockup -/// @notice A contract that lets user claim Lockup streams using Merkle proofs. A popular use case for MerkleLockup -/// is airstreams: a portmanteau of "airdrop" and "stream". This is an airdrop model where the tokens are distributed -/// over time, as opposed to all at once. -/// @dev This is the base interface for MerkleLockup. See the Sablier docs for more guidance: https://docs.sablier.com -interface ISablierMerkleLockup is IAdminable { +/// @title ISablierMerkleBase +/// @dev This is the base interface for Merkle Lockups and Merkle Instant. +interface ISablierMerkleBase is IAdminable { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Emitted when a recipient claims a stream. - event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); - /// @notice Emitted when the admin claws back the unclaimed tokens. event Clawback(address indexed admin, address indexed to, uint128 amount); @@ -29,14 +23,14 @@ interface ISablierMerkleLockup is IAdminable { /// @dev This is an immutable state variable. function ASSET() external returns (IERC20); - /// @notice A flag indicating whether the streams can be canceled. - /// @dev This is an immutable state variable. - function CANCELABLE() external returns (bool); - /// @notice The cut-off point for the campaign, as a Unix timestamp. A value of zero means there is no expiration. /// @dev This is an immutable state variable. function EXPIRATION() external returns (uint40); + /// @notice The root of the Merkle tree used to validate the proofs of inclusion. + /// @dev This is an immutable state variable. + function MERKLE_ROOT() external returns (bytes32); + /// @notice Returns the timestamp when the first claim is made. function getFirstClaimTime() external view returns (uint40); @@ -51,17 +45,9 @@ interface ISablierMerkleLockup is IAdminable { /// @notice The content identifier for indexing the campaign on IPFS. function ipfsCID() external view returns (string memory); - /// @notice The root of the Merkle tree used to validate the proofs of inclusion. - /// @dev This is an immutable state variable. - function MERKLE_ROOT() external returns (bytes32); - /// @notice Retrieves the name of the campaign. function name() external returns (string memory); - /// @notice A flag indicating whether the stream NFTs are transferable. - /// @dev This is an immutable state variable. - function TRANSFERABLE() external returns (bool); - /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/periphery/interfaces/ISablierMerkleLockupFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol similarity index 56% rename from src/periphery/interfaces/ISablierMerkleLockupFactory.sol rename to src/periphery/interfaces/ISablierMerkleFactory.sol index eb8b71e03..746d91dfa 100644 --- a/src/periphery/interfaces/ISablierMerkleLockupFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -5,22 +5,38 @@ import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; import { LockupLinear } from "../../core/types/DataTypes.sol"; +import { ISablierMerkleInstant } from "./ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "./ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "./ISablierMerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "../types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "../types/DataTypes.sol"; -/// @title ISablierMerkleLockupFactory -/// @notice Deploys MerkleLockup campaigns with CREATE2. -interface ISablierMerkleLockupFactory { +/// @title ISablierMerkleFactory +/// @notice A contract that deploys Merkle Lockups and Merkle Instant campaigns. Both of these use Merkle proofs for +/// token distribution. Merkle Lockup enable Airstreams, a portmanteau of "airdrop" and "stream". This is an airdrop +/// model where the tokens are distributed over time, as opposed to all at once. On the other hand, Merkle Instant +/// enables instant airdrops where tokens are unlocked and distributed immediately. See the Sablier docs for more +/// guidance: https://docs.sablier.com +/// @dev Deploys Merkle Lockup and Merkle Instant campaigns with CREATE2. +interface ISablierMerkleFactory { /*////////////////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Emitted when a {SablierV2MerkleInstant} campaign is created. + event CreateMerkleInstant( + ISablierMerkleInstant indexed merkleInstant, + MerkleBase.ConstructorParams baseParams, + uint256 aggregateAmount, + uint256 recipientCount + ); + /// @notice Emitted when a {SablierMerkleLL} campaign is created. event CreateMerkleLL( ISablierMerkleLL indexed merkleLL, - MerkleLockup.ConstructorParams baseParams, + MerkleBase.ConstructorParams baseParams, ISablierLockupLinear lockupLinear, + bool cancelable, + bool transferable, LockupLinear.Durations streamDurations, uint256 aggregateAmount, uint256 recipientCount @@ -29,8 +45,10 @@ interface ISablierMerkleLockupFactory { /// @notice Emitted when a {SablierMerkleLT} campaign is created. event CreateMerkleLT( ISablierMerkleLT indexed merkleLT, - MerkleLockup.ConstructorParams baseParams, + MerkleBase.ConstructorParams baseParams, ISablierLockupTranched lockupTranched, + bool cancelable, + bool transferable, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, @@ -54,18 +72,37 @@ interface ISablierMerkleLockupFactory { NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Creates a new MerkleLockup campaign with a LockupLinear distribution. + /// @notice Creates a new MerkleInstant campaign for instant distribution of assets. + /// @dev Emits a {CreateMerkleInstant} event. + /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in + /// {DataTypes}. + /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. + /// @param recipientCount The total number of recipients who are eligible to claim. + /// @return merkleInstant The address of the newly created MerkleInstant contract. + function createMerkleInstant( + MerkleBase.ConstructorParams memory baseParams, + uint256 aggregateAmount, + uint256 recipientCount + ) + external + returns (ISablierMerkleInstant merkleInstant); + + /// @notice Creates a new Merkle Lockup campaign with a LockupLinear distribution. /// @dev Emits a {CreateMerkleLL} event. - /// @param baseParams Struct encapsulating the {SablierMerkleLockup} parameters, which are documented in + /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param lockupLinear The address of the {SablierLockupLinear} contract. + /// @param cancelable Indicates if the stream will be cancelable after claiming. + /// @param transferable Indicates if the stream will be transferable after claiming. /// @param streamDurations The durations for each stream. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. /// @param recipientCount The total number of recipients who are eligible to claim. - /// @return merkleLL The address of the newly created MerkleLockup contract. + /// @return merkleLL The address of the newly created Merkle Lockup contract. function createMerkleLL( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupLinear lockupLinear, + bool cancelable, + bool transferable, LockupLinear.Durations memory streamDurations, uint256 aggregateAmount, uint256 recipientCount @@ -73,19 +110,23 @@ interface ISablierMerkleLockupFactory { external returns (ISablierMerkleLL merkleLL); - /// @notice Creates a new MerkleLockup campaign with a LockupTranched distribution. + /// @notice Creates a new Merkle Lockup campaign with a LockupTranched distribution. /// @dev Emits a {CreateMerkleLT} event. /// - /// @param baseParams Struct encapsulating the {SablierMerkleLockup} parameters, which are documented in + /// @param baseParams Struct encapsulating the {SablierMerkleBase} parameters, which are documented in /// {DataTypes}. /// @param lockupTranched The address of the {SablierLockupTranched} contract. + /// @param cancelable Indicates if the stream will be cancelable after claiming. + /// @param transferable Indicates if the stream will be transferable after claiming. /// @param tranchesWithPercentages The tranches with their respective unlock percentages. /// @param aggregateAmount The total amount of ERC-20 assets to be distributed to all recipients. /// @param recipientCount The total number of recipients who are eligible to claim. - /// @return merkleLT The address of the newly created MerkleLockup contract. + /// @return merkleLT The address of the newly created Merkle Lockup contract. function createMerkleLT( - MerkleLockup.ConstructorParams memory baseParams, + MerkleBase.ConstructorParams memory baseParams, ISablierLockupTranched lockupTranched, + bool cancelable, + bool transferable, MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages, uint256 aggregateAmount, uint256 recipientCount diff --git a/src/periphery/interfaces/ISablierMerkleInstant.sol b/src/periphery/interfaces/ISablierMerkleInstant.sol new file mode 100644 index 000000000..656f47139 --- /dev/null +++ b/src/periphery/interfaces/ISablierMerkleInstant.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22; + +import { ISablierMerkleBase } from "./ISablierMerkleBase.sol"; + +/// @title ISablierMerkleInstant +/// @notice MerkleInstant enables instant airdrop campaigns. +interface ISablierMerkleInstant is ISablierMerkleBase { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a recipient claims an instant airdrop. + event Claim(uint256 index, address indexed recipient, uint128 amount); + + /*////////////////////////////////////////////////////////////////////////// + NON-CONSTANT FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Makes the claim and transfer assets to the recipient. + /// + /// @dev Emits a {Claim} event. + /// + /// Requirements: + /// - The campaign must not have expired. + /// - The stream must not have been claimed already. + /// - The Merkle proof must be valid. + /// + /// @param index The index of the recipient in the Merkle tree. + /// @param recipient The address of the airdrop recipient. + /// @param amount The amount of ERC-20 assets to be transferred to the recipient. + /// @param merkleProof The proof of inclusion in the Merkle tree. + function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external; +} diff --git a/src/periphery/interfaces/ISablierMerkleLL.sol b/src/periphery/interfaces/ISablierMerkleLL.sol index 61ef0597a..b1a9e71a0 100644 --- a/src/periphery/interfaces/ISablierMerkleLL.sol +++ b/src/periphery/interfaces/ISablierMerkleLL.sol @@ -3,18 +3,33 @@ pragma solidity >=0.8.22; import { ISablierLockupLinear } from "../../core/interfaces/ISablierLockupLinear.sol"; -import { ISablierMerkleLockup } from "./ISablierMerkleLockup.sol"; +import { ISablierMerkleBase } from "./ISablierMerkleBase.sol"; /// @title ISablierMerkleLL -/// @notice MerkleLockup campaign that creates LockupLinear streams. -interface ISablierMerkleLL is ISablierMerkleLockup { +/// @notice Merkle Lockup campaign that creates LockupLinear streams. +interface ISablierMerkleLL is ISablierMerkleBase { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a recipient claims a stream. + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); + /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice A flag indicating whether the streams can be canceled. + /// @dev This is an immutable state variable. + function CANCELABLE() external returns (bool); + /// @notice The address of the {SablierLockupLinear} contract. function LOCKUP_LINEAR() external view returns (ISablierLockupLinear); + /// @notice A flag indicating whether the stream NFTs are transferable. + /// @dev This is an immutable state variable. + function TRANSFERABLE() external returns (bool); + /// @notice The total streaming duration of each stream. function streamDurations() external view returns (uint40 cliff, uint40 duration); diff --git a/src/periphery/interfaces/ISablierMerkleLT.sol b/src/periphery/interfaces/ISablierMerkleLT.sol index 136985752..40648f14e 100644 --- a/src/periphery/interfaces/ISablierMerkleLT.sol +++ b/src/periphery/interfaces/ISablierMerkleLT.sol @@ -3,18 +3,26 @@ pragma solidity >=0.8.22; import { ISablierLockupTranched } from "../../core/interfaces/ISablierLockupTranched.sol"; -import { ISablierMerkleLockup } from "./ISablierMerkleLockup.sol"; +import { ISablierMerkleBase } from "./ISablierMerkleBase.sol"; import { MerkleLT } from "../types/DataTypes.sol"; /// @title ISablierMerkleLT -/// @notice MerkleLockup campaign that creates LockupTranched streams. -interface ISablierMerkleLT is ISablierMerkleLockup { +/// @notice Merkle Lockup campaign that creates LockupTranched streams. +interface ISablierMerkleLT is ISablierMerkleBase { + /*////////////////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Emitted when a recipient claims a stream. + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); + /*////////////////////////////////////////////////////////////////////////// CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Retrieves the tranches with their respective unlock percentages and durations. - function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); + /// @notice A flag indicating whether the streams can be canceled. + /// @dev This is an immutable state variable. + function CANCELABLE() external returns (bool); /// @notice The address of the {SablierLockupTranched} contract. function LOCKUP_TRANCHED() external view returns (ISablierLockupTranched); @@ -22,6 +30,13 @@ interface ISablierMerkleLT is ISablierMerkleLockup { /// @notice The total percentage of the tranches. function TOTAL_PERCENTAGE() external view returns (uint64); + /// @notice A flag indicating whether the stream NFTs are transferable. + /// @dev This is an immutable state variable. + function TRANSFERABLE() external returns (bool); + + /// @notice Retrieves the tranches with their respective unlock percentages and durations. + function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); + /*////////////////////////////////////////////////////////////////////////// NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/periphery/libraries/Errors.sol b/src/periphery/libraries/Errors.sol index 79a7d8806..e5bcf24ed 100644 --- a/src/periphery/libraries/Errors.sol +++ b/src/periphery/libraries/Errors.sol @@ -11,24 +11,24 @@ library Errors { error SablierBatchLockup_BatchSizeZero(); /*////////////////////////////////////////////////////////////////////////// - SABLIER-MERKLE-LOCKUP + SABLIER-MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ /// @notice Thrown when trying to claim after the campaign has expired. - error SablierMerkleLockup_CampaignExpired(uint256 blockTimestamp, uint40 expiration); + error SablierMerkleBase_CampaignExpired(uint256 blockTimestamp, uint40 expiration); /// @notice Thrown when trying to create a campaign with a name that is too long. - error SablierMerkleLockup_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); + error SablierMerkleBase_CampaignNameTooLong(uint256 nameLength, uint256 maxLength); /// @notice Thrown when trying to clawback when the current timestamp is over the grace period and the campaign has /// not expired. - error SablierMerkleLockup_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); + error SablierMerkleBase_ClawbackNotAllowed(uint256 blockTimestamp, uint40 expiration, uint40 firstClaimTime); /// @notice Thrown when trying to claim with an invalid Merkle proof. - error SablierMerkleLockup_InvalidProof(); + error SablierMerkleBase_InvalidProof(); /// @notice Thrown when trying to claim the same stream more than once. - error SablierMerkleLockup_StreamClaimed(uint256 index); + error SablierMerkleBase_StreamClaimed(uint256 index); /*////////////////////////////////////////////////////////////////////////// SABLIER-MERKLE-LT diff --git a/src/periphery/types/DataTypes.sol b/src/periphery/types/DataTypes.sol index 2b5b0a055..7480b503e 100644 --- a/src/periphery/types/DataTypes.sol +++ b/src/periphery/types/DataTypes.sol @@ -82,25 +82,21 @@ library BatchLockup { } } -library MerkleLockup { - /// @notice Struct encapsulating the base constructor parameters of a MerkleLockup campaign. +library MerkleBase { + /// @notice Struct encapsulating the base constructor parameters of a Merkle campaign. /// @param asset The contract address of the ERC-20 asset to be distributed. - /// @param cancelable Indicates if the stream will be cancelable after claiming. /// @param expiration The expiration of the campaign, as a Unix timestamp. - /// @param initialAdmin The initial admin of the MerkleLockup campaign. + /// @param initialAdmin The initial admin of the campaign. /// @param ipfsCID The content identifier for indexing the contract on IPFS. /// @param merkleRoot The Merkle root of the claim data. /// @param name The name of the campaign. - /// @param transferable Indicates if the stream will be transferable after claiming. struct ConstructorParams { IERC20 asset; - bool cancelable; uint40 expiration; address initialAdmin; string ipfsCID; bytes32 merkleRoot; string name; - bool transferable; } } diff --git a/test/Base.t.sol b/test/Base.t.sol index 44a195ffb..eece1a36b 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -12,12 +12,13 @@ import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierMerkleLockupFactory } from "src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; +import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; +import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { SablierBatchLockup } from "src/periphery/SablierBatchLockup.sol"; -import { SablierMerkleLockupFactory } from "src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "src/periphery/SablierMerkleFactory.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; @@ -50,7 +51,8 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi ISablierLockupDynamic internal lockupDynamic; ISablierLockupLinear internal lockupLinear; ISablierLockupTranched internal lockupTranched; - ISablierMerkleLockupFactory internal merkleLockupFactory; + ISablierMerkleFactory internal merkleFactory; + ISablierMerkleInstant internal merkleInstant; ISablierMerkleLL internal merkleLL; ISablierMerkleLT internal merkleLT; ILockupNFTDescriptor internal nftDescriptor; @@ -123,12 +125,12 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); - dai.approve({ spender: address(merkleLockupFactory), value: MAX_UINT256 }); + dai.approve({ spender: address(merkleFactory), value: MAX_UINT256 }); usdt.approve({ spender: address(batchLockup), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); usdt.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); - usdt.approve({ spender: address(merkleLockupFactory), value: MAX_UINT256 }); + usdt.approve({ spender: address(merkleFactory), value: MAX_UINT256 }); } /// @dev Generates a user, labels its address, funds it with test assets, and approves the protocol contracts. @@ -153,9 +155,9 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi lockupDynamic = new SablierLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); lockupLinear = new SablierLockupLinear(users.admin, nftDescriptor); lockupTranched = new SablierLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); - merkleLockupFactory = new SablierMerkleLockupFactory(); + merkleFactory = new SablierMerkleFactory(); } else { - (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleFactory) = deployOptimizedProtocol(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); } @@ -163,7 +165,7 @@ abstract contract Base_Test is Assertions, Calculations, Constants, DeployOptimi vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); - vm.label({ account: address(merkleLockupFactory), newLabel: "MerkleLockupFactory" }); + vm.label({ account: address(merkleFactory), newLabel: "MerkleFactory" }); vm.label({ account: address(nftDescriptor), newLabel: "NFTDescriptor" }); } diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 0e2726bdb..e6049aa55 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; @@ -10,15 +11,38 @@ import { Base_Test } from "../Base.t.sol"; contract Periphery_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION + MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ - function setUp() public virtual override { - Base_Test.setUp(); - } - /*////////////////////////////////////////////////////////////////////////// - MERKLE-LOCKUP - //////////////////////////////////////////////////////////////////////////*/ + function computeMerkleInstantAddress( + address caller, + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + bytes32 salt = keccak256( + abi.encodePacked( + caller, + address(asset_), + expiration, + admin, + abi.encode(defaults.IPFS_CID()), + merkleRoot, + defaults.NAME_BYTES32() + ) + ); + bytes32 creationBytecodeHash = keccak256(getMerkleInstantBytecode(admin, asset_, merkleRoot, expiration)); + return vm.computeCreate2Address({ + salt: salt, + initCodeHash: creationBytecodeHash, + deployer: address(merkleFactory) + }); + } function computeMerkleLLAddress( address caller, @@ -35,14 +59,14 @@ contract Periphery_Test is Base_Test { abi.encodePacked( caller, address(asset_), - defaults.CANCELABLE(), expiration, admin, abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), - defaults.TRANSFERABLE(), lockupLinear, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), abi.encode(defaults.durations()) ) ); @@ -50,7 +74,7 @@ contract Periphery_Test is Base_Test { return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, - deployer: address(merkleLockupFactory) + deployer: address(merkleFactory) }); } @@ -69,14 +93,14 @@ contract Periphery_Test is Base_Test { abi.encodePacked( caller, address(asset_), - defaults.CANCELABLE(), expiration, admin, abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), - defaults.TRANSFERABLE(), lockupTranched, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), abi.encode(defaults.tranchesWithPercentages()) ) ); @@ -84,10 +108,30 @@ contract Periphery_Test is Base_Test { return vm.computeCreate2Address({ salt: salt, initCodeHash: creationBytecodeHash, - deployer: address(merkleLockupFactory) + deployer: address(merkleFactory) }); } + function getMerkleInstantBytecode( + address admin, + IERC20 asset_, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (bytes memory) + { + bytes memory constructorArgs = abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot)); + if (!isTestOptimizedProfile()) { + return bytes.concat(type(SablierMerkleInstant).creationCode, constructorArgs); + } else { + return bytes.concat( + vm.getCode("out-optimized/SablierMerkleInstant.sol/SablierMerkleInstant.json"), constructorArgs + ); + } + } + function getMerkleLLBytecode( address admin, IERC20 asset_, @@ -98,8 +142,13 @@ contract Periphery_Test is Base_Test { view returns (bytes memory) { - bytes memory constructorArgs = - abi.encode(defaults.baseParams(admin, asset_, expiration, merkleRoot), lockupLinear, defaults.durations()); + bytes memory constructorArgs = abi.encode( + defaults.baseParams(admin, asset_, expiration, merkleRoot), + lockupLinear, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), + defaults.durations() + ); if (!isTestOptimizedProfile()) { return bytes.concat(type(SablierMerkleLL).creationCode, constructorArgs); } else { @@ -120,6 +169,8 @@ contract Periphery_Test is Base_Test { bytes memory constructorArgs = abi.encode( defaults.baseParams(admin, asset_, expiration, merkleRoot), lockupTranched, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), defaults.tranchesWithPercentages() ); if (!isTestOptimizedProfile()) { diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index c4592c91d..9a821184d 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -35,7 +35,7 @@ abstract contract Fork_Test is Periphery_Test, Merkle { vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); // Set up the parent test contract. - Periphery_Test.setUp(); + super.setUp(); // Load the external dependencies. loadDependencies(); @@ -62,7 +62,7 @@ abstract contract Fork_Test is Periphery_Test, Merkle { } /// @dev Loads all dependencies pre-deployed on Mainnet. - // TODO: Update address once deployed. + // TODO: Update addresses once deployed. function loadDependencies() private { lockupDynamic = ISablierLockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); diff --git a/test/periphery/fork/assets/USDC.t.sol b/test/periphery/fork/assets/USDC.t.sol index ca1467e07..868229bc5 100644 --- a/test/periphery/fork/assets/USDC.t.sol +++ b/test/periphery/fork/assets/USDC.t.sol @@ -6,8 +6,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; -import { MerkleLL_Fork_Test } from "../merkle-lockup/MerkleLL.t.sol"; -import { MerkleLT_Fork_Test } from "../merkle-lockup/MerkleLT.t.sol"; +import { MerkleInstant_Fork_Test } from "../merkle-campaign/MerkleInstant.t.sol"; +import { MerkleLL_Fork_Test } from "../merkle-campaign/MerkleLL.t.sol"; +import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); @@ -24,6 +25,8 @@ contract USDC_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdc) { } +contract USDC_MerkleInstant_Fork_Test is MerkleInstant_Fork_Test(usdc) { } + contract USDC_MerkleLL_Fork_Test is MerkleLL_Fork_Test(usdc) { } contract USDC_MerkleLT_Fork_Test is MerkleLT_Fork_Test(usdc) { } diff --git a/test/periphery/fork/assets/USDT.t.sol b/test/periphery/fork/assets/USDT.t.sol index bdc5ed85d..e5ada0ce0 100644 --- a/test/periphery/fork/assets/USDT.t.sol +++ b/test/periphery/fork/assets/USDT.t.sol @@ -6,8 +6,9 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; -import { MerkleLL_Fork_Test } from "../merkle-lockup/MerkleLL.t.sol"; -import { MerkleLT_Fork_Test } from "../merkle-lockup/MerkleLT.t.sol"; +import { MerkleInstant_Fork_Test } from "../merkle-campaign/MerkleInstant.t.sol"; +import { MerkleLL_Fork_Test } from "../merkle-campaign/MerkleLL.t.sol"; +import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); @@ -24,6 +25,8 @@ contract USDT_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdt) { } +contract USDT_MerkleInstant_Fork_Test is MerkleInstant_Fork_Test(usdt) { } + contract USDT_MerkleLL_Fork_Test is MerkleLL_Fork_Test(usdt) { } contract USDT_MerkleLT_Fork_Test is MerkleLT_Fork_Test(usdt) { } diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol index 969f0e600..8658ed66d 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol @@ -14,10 +14,6 @@ import { Fork_Test } from "../Fork.t.sol"; abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } - function setUp() public virtual override { - Fork_Test.setUp(); - } - struct CreateWithTimestampsParams { uint128 batchSize; address sender; diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol index d2ff4e673..919e4447b 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol @@ -14,10 +14,6 @@ import { Fork_Test } from "../Fork.t.sol"; abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } - function setUp() public virtual override { - Fork_Test.setUp(); - } - struct CreateWithTimestampsParams { uint128 batchSize; LockupLinear.Timestamps timestamps; diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol index 7f4c97c80..0f9849a22 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol @@ -14,10 +14,6 @@ import { Fork_Test } from "../Fork.t.sol"; abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } - function setUp() public virtual override { - Fork_Test.setUp(); - } - struct CreateWithTimestampsParams { uint128 batchSize; address sender; diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol new file mode 100644 index 000000000..f899935e6 --- /dev/null +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; +import { MerkleBase } from "src/periphery/types/DataTypes.sol"; + +import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +abstract contract MerkleInstant_Fork_Test is Fork_Test { + using MerkleBuilder for uint256[]; + + constructor(IERC20 asset_) Fork_Test(asset_) { } + + /// @dev Encapsulates the data needed to compute a Merkle tree leaf. + struct LeafData { + uint256 index; + uint256 recipientSeed; + uint128 amount; + } + + struct Params { + address admin; + uint40 expiration; + LeafData[] leafData; + uint256 posBeforeSort; + } + + struct Vars { + uint256 aggregateAmount; + uint128[] amounts; + MerkleBase.ConstructorParams baseParams; + uint128 clawbackAmount; + address expectedMerkleInstant; + uint256[] indexes; + uint256 leafPos; + uint256 leafToClaim; + ISablierMerkleInstant merkleInstant; + bytes32[] merkleProof; + bytes32 merkleRoot; + address[] recipients; + uint256 recipientCount; + } + + // We need the leaves as a storage variable so that we can use OpenZeppelin's {Arrays.findUpperBound}. + uint256[] public leaves; + + function testForkFuzz_MerkleInstant(Params memory params) external { + vm.assume(params.admin != address(0) && params.admin != users.admin); + vm.assume(params.leafData.length > 0); + assumeNoBlacklisted({ token: address(FORK_ASSET), addr: params.admin }); + params.posBeforeSort = _bound(params.posBeforeSort, 0, params.leafData.length - 1); + + // The expiration must be either zero or greater than the block timestamp. + if (params.expiration != 0) { + params.expiration = boundUint40(params.expiration, getBlockTimestamp() + 1 seconds, MAX_UNIX_TIMESTAMP); + } + + /*////////////////////////////////////////////////////////////////////////// + CREATE + //////////////////////////////////////////////////////////////////////////*/ + + Vars memory vars; + vars.recipientCount = params.leafData.length; + vars.amounts = new uint128[](vars.recipientCount); + vars.indexes = new uint256[](vars.recipientCount); + vars.recipients = new address[](vars.recipientCount); + for (uint256 i = 0; i < vars.recipientCount; ++i) { + vars.indexes[i] = params.leafData[i].index; + + // Bound each leaf amount so that `aggregateAmount` does not overflow. + vars.amounts[i] = boundUint128(params.leafData[i].amount, 1, uint128(MAX_UINT128 / vars.recipientCount - 1)); + vars.aggregateAmount += vars.amounts[i]; + + // Avoid zero recipient addresses. + uint256 boundedRecipientSeed = _bound(params.leafData[i].recipientSeed, 1, type(uint160).max); + vars.recipients[i] = address(uint160(boundedRecipientSeed)); + } + + leaves = new uint256[](vars.recipientCount); + leaves = MerkleBuilder.computeLeaves(vars.indexes, vars.recipients, vars.amounts); + + // Sort the leaves in ascending order to match the production environment. + MerkleBuilder.sortLeaves(leaves); + + // Compute the Merkle root. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle root is the hash of the leaf itself. + vars.merkleRoot = bytes32(leaves[0]); + } else { + vars.merkleRoot = getRoot(leaves.toBytes32()); + } + + // Make the caller the admin. + resetPrank({ msgSender: params.admin }); + + vars.expectedMerkleInstant = + computeMerkleInstantAddress(params.admin, params.admin, FORK_ASSET, vars.merkleRoot, params.expiration); + + vars.baseParams = defaults.baseParams({ + admin: params.admin, + asset_: FORK_ASSET, + merkleRoot: vars.merkleRoot, + expiration: params.expiration + }); + + vm.expectEmit({ emitter: address(merkleFactory) }); + emit CreateMerkleInstant({ + merkleInstant: ISablierMerkleInstant(vars.expectedMerkleInstant), + baseParams: vars.baseParams, + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + vars.merkleInstant = merkleFactory.createMerkleInstant({ + baseParams: vars.baseParams, + aggregateAmount: vars.aggregateAmount, + recipientCount: vars.recipientCount + }); + + // Fund the MerkleInstant contract. + deal({ token: address(FORK_ASSET), to: address(vars.merkleInstant), give: vars.aggregateAmount }); + + assertGt(address(vars.merkleInstant).code.length, 0, "MerkleInstant contract not created"); + assertEq( + address(vars.merkleInstant), + vars.expectedMerkleInstant, + "MerkleInstant contract does not match computed address" + ); + + /*////////////////////////////////////////////////////////////////////////// + CLAIM + //////////////////////////////////////////////////////////////////////////*/ + + assertFalse(vars.merkleInstant.hasClaimed(vars.indexes[params.posBeforeSort])); + + vars.leafToClaim = MerkleBuilder.computeLeaf( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort] + ); + vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); + + vm.expectEmit({ emitter: address(vars.merkleInstant) }); + emit Claim( + vars.indexes[params.posBeforeSort], + vars.recipients[params.posBeforeSort], + vars.amounts[params.posBeforeSort] + ); + + // Compute the Merkle proof. + if (leaves.length == 1) { + // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the + // leaf is the root. + } else { + vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); + } + + expectCallToTransfer({ + asset: FORK_ASSET, + to: vars.recipients[params.posBeforeSort], + value: vars.amounts[params.posBeforeSort] + }); + + vars.merkleInstant.claim({ + index: vars.indexes[params.posBeforeSort], + recipient: vars.recipients[params.posBeforeSort], + amount: vars.amounts[params.posBeforeSort], + merkleProof: vars.merkleProof + }); + + assertTrue(vars.merkleInstant.hasClaimed(vars.indexes[params.posBeforeSort])); + + /*////////////////////////////////////////////////////////////////////////// + CLAWBACK + //////////////////////////////////////////////////////////////////////////*/ + + if (params.expiration > 0) { + vars.clawbackAmount = uint128(FORK_ASSET.balanceOf(address(vars.merkleInstant))); + vm.warp({ newTimestamp: uint256(params.expiration) + 1 seconds }); + + expectCallToTransfer({ asset: FORK_ASSET, to: params.admin, value: vars.clawbackAmount }); + vm.expectEmit({ emitter: address(vars.merkleInstant) }); + emit Clawback({ to: params.admin, admin: params.admin, amount: vars.clawbackAmount }); + vars.merkleInstant.clawback({ to: params.admin, amount: vars.clawbackAmount }); + } + } +} diff --git a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol similarity index 94% rename from test/periphery/fork/merkle-lockup/MerkleLL.t.sol rename to test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 9f470a51d..4ea124560 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -6,7 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; -import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; +import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; @@ -16,10 +16,6 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } - function setUp() public virtual override { - Fork_Test.setUp(); - } - /// @dev Encapsulates the data needed to compute a Merkle tree leaf. struct LeafData { uint256 index; @@ -39,7 +35,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { uint256 actualStreamId; uint256 aggregateAmount; uint128[] amounts; - MerkleLockup.ConstructorParams baseParams; + MerkleBase.ConstructorParams baseParams; uint128 clawbackAmount; address expectedLL; LockupLinear.StreamLL expectedStream; @@ -116,25 +112,29 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { expiration: params.expiration }); - vm.expectEmit({ emitter: address(merkleLockupFactory) }); + vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleLL({ merkleLL: ISablierMerkleLL(vars.expectedLL), baseParams: vars.baseParams, lockupLinear: lockupLinear, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), streamDurations: defaults.durations(), aggregateAmount: vars.aggregateAmount, recipientCount: vars.recipientCount }); - vars.merkleLL = merkleLockupFactory.createMerkleLL({ + vars.merkleLL = merkleFactory.createMerkleLL({ baseParams: vars.baseParams, lockupLinear: lockupLinear, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), streamDurations: defaults.durations(), aggregateAmount: vars.aggregateAmount, recipientCount: vars.recipientCount }); - // Fund the MerkleLockup contract. + // Fund the MerkleLL contract. deal({ token: address(FORK_ASSET), to: address(vars.merkleLL), give: vars.aggregateAmount }); assertGt(address(vars.merkleLL).code.length, 0, "MerkleLL contract not created"); @@ -154,6 +154,8 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); vars.expectedStreamId = lockupLinear.nextStreamId(); + + vm.expectEmit({ emitter: address(vars.merkleLL) }); emit Claim( vars.indexes[params.posBeforeSort], vars.recipients[params.posBeforeSort], diff --git a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol similarity index 93% rename from test/periphery/fork/merkle-lockup/MerkleLT.t.sol rename to test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 1fa90b38d..0283d5965 100644 --- a/test/periphery/fork/merkle-lockup/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -6,7 +6,7 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; -import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; +import { MerkleBase } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "../../../utils/MerkleBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; @@ -16,10 +16,6 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } - function setUp() public virtual override { - Fork_Test.setUp(); - } - /// @dev Encapsulates the data needed to compute a Merkle tree leaf. struct LeafData { uint256 index; @@ -40,7 +36,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { LockupTranched.Tranche[] actualTranches; uint256 aggregateAmount; uint128[] amounts; - MerkleLockup.ConstructorParams baseParams; + MerkleBase.ConstructorParams baseParams; uint128 clawbackAmount; address expectedLT; LockupTranched.StreamLT expectedStream; @@ -117,26 +113,30 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { expiration: params.expiration }); - vm.expectEmit({ emitter: address(merkleLockupFactory) }); + vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleLT({ merkleLT: ISablierMerkleLT(vars.expectedLT), baseParams: vars.baseParams, lockupTranched: lockupTranched, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), tranchesWithPercentages: defaults.tranchesWithPercentages(), totalDuration: defaults.TOTAL_DURATION(), aggregateAmount: vars.aggregateAmount, recipientCount: vars.recipientCount }); - vars.merkleLT = merkleLockupFactory.createMerkleLT({ + vars.merkleLT = merkleFactory.createMerkleLT({ baseParams: vars.baseParams, lockupTranched: lockupTranched, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), tranchesWithPercentages: defaults.tranchesWithPercentages(), aggregateAmount: vars.aggregateAmount, recipientCount: vars.recipientCount }); - // Fund the MerkleLockup contract. + // Fund the MerkleLT contract. deal({ token: address(FORK_ASSET), to: address(vars.merkleLT), give: vars.aggregateAmount }); assertGt(address(vars.merkleLT).code.length, 0, "MerkleLT contract not created"); @@ -156,6 +156,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); vars.expectedStreamId = lockupTranched.nextStreamId(); + vm.expectEmit({ emitter: address(vars.merkleLT) }); emit Claim( vars.indexes[params.posBeforeSort], vars.recipients[params.posBeforeSort], @@ -190,7 +191,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { recipient: vars.recipients[params.posBeforeSort], sender: params.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranchesMerkleLockup({ totalAmount: vars.amounts[params.posBeforeSort] }), + tranches: defaults.tranchesMerkleLT({ totalAmount: vars.amounts[params.posBeforeSort] }), wasCanceled: false }); diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 19472c0ce..6013113ab 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index 40748e402..6029463c0 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index 5939ad99d..0deafcad4 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index 9af9272e5..eca730f65 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index 3c56008a6..1bcc4b8f6 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index 2de773919..9844b7cc4 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol similarity index 63% rename from test/periphery/integration/merkle-lockup/MerkleLockup.t.sol rename to test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 1110f26e9..633a06b5a 100644 --- a/test/periphery/integration/merkle-lockup/MerkleLockup.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -1,27 +1,91 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; +import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Periphery_Test } from "../../Periphery.t.sol"; -abstract contract MerkleLockup_Integration_Test is Periphery_Test { +abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function setUp() public virtual override { - Periphery_Test.setUp(); + super.setUp(); // Make Alice the caller. resetPrank(users.alice); - // Create the default MerkleLockup contracts. + // Create the default Merkle contracts. + merkleInstant = createMerkleInstant(); merkleLL = createMerkleLL(); merkleLT = createMerkleLT(); - // Fund the MerkleLockup contracts. + // Fund the contracts. + deal({ token: address(dai), to: address(merkleInstant), give: defaults.AGGREGATE_AMOUNT() }); deal({ token: address(dai), to: address(merkleLL), give: defaults.AGGREGATE_AMOUNT() }); deal({ token: address(dai), to: address(merkleLT), give: defaults.AGGREGATE_AMOUNT() }); } + /*////////////////////////////////////////////////////////////////////////// + MERKLE-INSTANT + //////////////////////////////////////////////////////////////////////////*/ + + function claimInstant() internal { + return merkleInstant.claim({ + index: defaults.INDEX1(), + recipient: users.recipient1, + amount: defaults.CLAIM_AMOUNT(), + merkleProof: defaults.index1Proof() + }); + } + + function computeMerkleInstantAddress() internal view returns (address) { + return computeMerkleInstantAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleInstantAddress(address admin) internal view returns (address) { + return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); + } + + function computeMerkleInstantAddress(address admin, uint40 expiration) internal view returns (address) { + return computeMerkleInstantAddress(admin, defaults.MERKLE_ROOT(), expiration); + } + + function computeMerkleInstantAddress(address admin, bytes32 merkleRoot) internal view returns (address) { + return computeMerkleInstantAddress(admin, merkleRoot, defaults.EXPIRATION()); + } + + function computeMerkleInstantAddress( + address admin, + bytes32 merkleRoot, + uint40 expiration + ) + internal + view + returns (address) + { + return computeMerkleInstantAddress(users.alice, admin, dai, merkleRoot, expiration); + } + + function createMerkleInstant() internal returns (ISablierMerkleInstant) { + return createMerkleInstant(users.admin, defaults.EXPIRATION()); + } + + function createMerkleInstant(address admin) internal returns (ISablierMerkleInstant) { + return createMerkleInstant(admin, defaults.EXPIRATION()); + } + + function createMerkleInstant(uint40 expiration) internal returns (ISablierMerkleInstant) { + return createMerkleInstant(users.admin, expiration); + } + + function createMerkleInstant(address admin, uint40 expiration) internal returns (ISablierMerkleInstant) { + return merkleFactory.createMerkleInstant({ + baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + } + /*////////////////////////////////////////////////////////////////////////// MERKLE-LL //////////////////////////////////////////////////////////////////////////*/ @@ -76,9 +140,11 @@ abstract contract MerkleLockup_Integration_Test is Periphery_Test { } function createMerkleLL(address admin, uint40 expiration) internal returns (ISablierMerkleLL) { - return merkleLockupFactory.createMerkleLL({ + return merkleFactory.createMerkleLL({ baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), lockupLinear: lockupLinear, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), streamDurations: defaults.durations(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientCount: defaults.RECIPIENT_COUNT() @@ -139,9 +205,11 @@ abstract contract MerkleLockup_Integration_Test is Periphery_Test { } function createMerkleLT(address admin, uint40 expiration) internal returns (ISablierMerkleLT) { - return merkleLockupFactory.createMerkleLT({ + return merkleFactory.createMerkleLT({ baseParams: defaults.baseParams(admin, dai, expiration, defaults.MERKLE_ROOT()), lockupTranched: lockupTranched, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), tranchesWithPercentages: defaults.tranchesWithPercentages(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientCount: defaults.RECIPIENT_COUNT() diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol new file mode 100644 index 000000000..d855b6fb5 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.t.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { MerkleBase } from "src/periphery/types/DataTypes.sol"; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract CreateMerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { + function test_RevertWhen_CampaignNameTooLong() external { + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + baseParams.name = "this string is longer than 32 characters"; + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierMerkleBase_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + ) + ); + + merkleFactory.createMerkleInstant({ + baseParams: baseParams, + aggregateAmount: aggregateAmount, + recipientCount: recipientCount + }); + } + + modifier whenCampaignNameNotTooLong() { + _; + } + + /// @dev This test works because a default MerkleInstant contract is deployed in {Integration_Test.setUp} + function test_RevertGiven_CreatedAlready() external whenCampaignNameNotTooLong { + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); + uint256 recipientCount = defaults.RECIPIENT_COUNT(); + + // Expect a revert due to CREATE2. + vm.expectRevert(); + merkleFactory.createMerkleInstant({ + baseParams: baseParams, + aggregateAmount: aggregateAmount, + recipientCount: recipientCount + }); + } + + modifier givenNotCreatedAlready() { + _; + } + + function testFuzz_CreateMerkleInstant( + address admin, + uint40 expiration + ) + external + whenCampaignNameNotTooLong + givenNotCreatedAlready + { + vm.assume(admin != users.admin); + address expectedMerkleInstant = computeMerkleInstantAddress(admin, expiration); + + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ + admin: admin, + asset_: dai, + merkleRoot: defaults.MERKLE_ROOT(), + expiration: expiration + }); + + vm.expectEmit({ emitter: address(merkleFactory) }); + emit CreateMerkleInstant({ + merkleInstant: ISablierMerkleInstant(expectedMerkleInstant), + baseParams: baseParams, + aggregateAmount: defaults.AGGREGATE_AMOUNT(), + recipientCount: defaults.RECIPIENT_COUNT() + }); + + address actualInstant = address(createMerkleInstant(admin, expiration)); + assertGt(actualInstant.code.length, 0, "MerkleInstant contract not created"); + assertEq(actualInstant, expectedMerkleInstant, "MerkleInstant contract does not match computed address"); + } +} diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree new file mode 100644 index 000000000..a72f8c222 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-instant/createMerkleInstant.tree @@ -0,0 +1,9 @@ +createMerkleInstant.t.sol +├── when the campaign name is too long +│ └── it should revert +└── when the campaign name is not too long + ├── given the campaign has been created already + │ └── it should revert + └── given the campaign has not been created already + ├── it should create the campaign + └── it should emit a {CreateMerkleInstant} event diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol similarity index 67% rename from test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol rename to test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index 5cab524aa..b7477da8d 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -2,15 +2,17 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; -import { MerkleLockup } from "src/periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { MerkleBase } from "src/periphery/types/DataTypes.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { +contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CampaignNameTooLong() external { - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); LockupLinear.Durations memory streamDurations = defaults.durations(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); @@ -19,13 +21,15 @@ contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierMerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + Errors.SablierMerkleBase_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 ) ); - merkleLockupFactory.createMerkleLL({ + merkleFactory.createMerkleLL({ baseParams: baseParams, lockupLinear: lockupLinear, + cancelable: cancelable, + transferable: transferable, streamDurations: streamDurations, aggregateAmount: aggregateAmount, recipientCount: recipientCount @@ -36,18 +40,22 @@ contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { _; } - /// @dev This test works because a default MerkleLockup contract is deployed in {Integration_Test.setUp} + /// @dev This test works because a default MerkleLL contract is deployed in {Integration_Test.setUp} function test_RevertGiven_CreatedAlready() external whenCampaignNameNotTooLong { - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); LockupLinear.Durations memory streamDurations = defaults.durations(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); // Expect a revert due to CREATE2. vm.expectRevert(); - merkleLockupFactory.createMerkleLL({ + merkleFactory.createMerkleLL({ baseParams: baseParams, lockupLinear: lockupLinear, + cancelable: cancelable, + transferable: transferable, streamDurations: streamDurations, aggregateAmount: aggregateAmount, recipientCount: recipientCount @@ -69,18 +77,20 @@ contract CreateMerkleLL_Integration_Test is MerkleLockup_Integration_Test { vm.assume(admin != users.admin); address expectedLL = computeMerkleLLAddress(admin, expiration); - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams({ + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ admin: admin, asset_: dai, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration }); - vm.expectEmit({ emitter: address(merkleLockupFactory) }); + vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleLL({ merkleLL: ISablierMerkleLL(expectedLL), baseParams: baseParams, lockupLinear: lockupLinear, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), streamDurations: defaults.durations(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), recipientCount: defaults.RECIPIENT_COUNT() diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/factory/create-merkle-ll/createMerkleLL.tree rename to test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.tree diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol similarity index 60% rename from test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol rename to test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol index fa03eb990..8000c4178 100644 --- a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol @@ -1,15 +1,17 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/periphery/libraries/Errors.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; +import { MerkleBase, MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { +contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CampaignNameTooLong() external { - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); @@ -18,12 +20,18 @@ contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierMerkleLockup_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 + Errors.SablierMerkleBase_CampaignNameTooLong.selector, bytes(baseParams.name).length, 32 ) ); - merkleLockupFactory.createMerkleLT( - baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + merkleFactory.createMerkleLT( + baseParams, + lockupTranched, + cancelable, + transferable, + tranchesWithPercentages, + aggregateAmount, + recipientCount ); } @@ -31,17 +39,25 @@ contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { _; } - /// @dev This test works because a default MerkleLockup contract is deployed in {Integration_Test.setUp} + /// @dev This test works because a default MerkleLT contract is deployed in {Integration_Test.setUp} function test_RevertGiven_CreatedAlready() external whenCampaignNameNotTooLong { - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); // Expect a revert due to CREATE2. vm.expectRevert(); - merkleLockupFactory.createMerkleLT( - baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + merkleFactory.createMerkleLT( + baseParams, + lockupTranched, + cancelable, + transferable, + tranchesWithPercentages, + aggregateAmount, + recipientCount ); } @@ -60,18 +76,20 @@ contract CreateMerkleLT_Integration_Test is MerkleLockup_Integration_Test { vm.assume(admin != users.admin); address expectedLT = computeMerkleLTAddress(admin, expiration); - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams({ + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams({ admin: admin, asset_: dai, merkleRoot: defaults.MERKLE_ROOT(), expiration: expiration }); - vm.expectEmit({ emitter: address(merkleLockupFactory) }); + vm.expectEmit({ emitter: address(merkleFactory) }); emit CreateMerkleLT({ merkleLT: ISablierMerkleLT(expectedLT), baseParams: baseParams, lockupTranched: lockupTranched, + cancelable: defaults.CANCELABLE(), + transferable: defaults.TRANSFERABLE(), tranchesWithPercentages: defaults.tranchesWithPercentages(), totalDuration: defaults.TOTAL_DURATION(), aggregateAmount: defaults.AGGREGATE_AMOUNT(), diff --git a/test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/factory/create-merkle-lt/createMerkleLT.tree rename to test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.tree diff --git a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol b/test/periphery/integration/merkle-campaign/factory/is-percentages-sum-100/isPercentagesSum100.t.sol similarity index 74% rename from test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol rename to test/periphery/integration/merkle-campaign/factory/is-percentages-sum-100/isPercentagesSum100.t.sol index 60f753642..1fc8163f5 100644 --- a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/is-percentages-sum-100/isPercentagesSum100.t.sol @@ -5,15 +5,15 @@ import { MAX_UD2x18, ud2x18 } from "@prb/math/src/UD2x18.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract IsPercentagesSum100_Integration_Test is MerkleLockup_Integration_Test { +contract IsPercentagesSum100_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_SumOverflow() public { MerkleLT.TrancheWithPercentage[] memory tranches = defaults.tranchesWithPercentages(); tranches[0].unlockPercentage = MAX_UD2x18; vm.expectRevert(); - merkleLockupFactory.isPercentagesSum100(tranches); + merkleFactory.isPercentagesSum100(tranches); } modifier whenSumDoesNotOverflow() { @@ -34,7 +34,7 @@ contract IsPercentagesSum100_Integration_Test is MerkleLockup_Integration_Test { tranchesWithPercentages[0].unlockPercentage = ud2x18(0.05e18); tranchesWithPercentages[1].unlockPercentage = ud2x18(0.2e18); - assertFalse(merkleLockupFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); + assertFalse(merkleFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); } function test_TotalPercentageGreaterThanOneHundred() @@ -47,7 +47,7 @@ contract IsPercentagesSum100_Integration_Test is MerkleLockup_Integration_Test { tranchesWithPercentages[0].unlockPercentage = ud2x18(0.5e18); tranchesWithPercentages[1].unlockPercentage = ud2x18(0.6e18); - assertFalse(merkleLockupFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); + assertFalse(merkleFactory.isPercentagesSum100(tranchesWithPercentages), "isPercentagesSum100"); } modifier whenTotalPercentageOneHundred() { @@ -55,6 +55,6 @@ contract IsPercentagesSum100_Integration_Test is MerkleLockup_Integration_Test { } function test_IsPercentagesSum100() external view whenSumDoesNotOverflow whenTotalPercentageOneHundred { - assertTrue(merkleLockupFactory.isPercentagesSum100(defaults.tranchesWithPercentages()), "isPercentagesSum100"); + assertTrue(merkleFactory.isPercentagesSum100(defaults.tranchesWithPercentages()), "isPercentagesSum100"); } } diff --git a/test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree b/test/periphery/integration/merkle-campaign/factory/is-percentages-sum-100/isPercentagesSum100.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/factory/is-percentages-sum-100/isPercentagesSum100.tree rename to test/periphery/integration/merkle-campaign/factory/is-percentages-sum-100/isPercentagesSum100.tree diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol new file mode 100644 index 000000000..14b356092 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract Claim_Integration_Test is MerkleCampaign_Integration_Test { + function test_RevertGiven_CampaignExpired() external { + uint40 expiration = defaults.EXPIRATION(); + uint256 warpTime = expiration + 1 seconds; + bytes32[] memory merkleProof; + vm.warp({ newTimestamp: warpTime }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); + merkleInstant.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + modifier givenCampaignNotExpired() { + _; + } + + function test_RevertGiven_AlreadyClaimed() external givenCampaignNotExpired { + claimInstant(); + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); + merkleInstant.claim(index1, users.recipient1, amount, merkleProof); + } + + modifier givenNotClaimed() { + _; + } + + modifier givenNotIncludedInMerkleTree() { + _; + } + + function test_RevertWhen_InvalidIndex() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 invalidIndex = 1337; + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleInstant.claim(invalidIndex, users.recipient1, amount, merkleProof); + } + + function test_RevertWhen_InvalidRecipient() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + address invalidRecipient = address(1337); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleInstant.claim(index1, invalidRecipient, amount, merkleProof); + } + + function test_RevertWhen_InvalidAmount() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 invalidAmount = 1337; + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleInstant.claim(index1, users.recipient1, invalidAmount, merkleProof); + } + + function test_RevertWhen_InvalidMerkleProof() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory invalidMerkleProof = defaults.index2Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleInstant.claim(index1, users.recipient1, amount, invalidMerkleProof); + } + + modifier givenIncludedInMerkleTree() { + _; + } + + function test_Claim() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { + vm.expectEmit({ emitter: address(merkleInstant) }); + emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT()); + + expectCallToTransfer({ to: users.recipient1, value: defaults.CLAIM_AMOUNT() }); + + claimInstant(); + + assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.tree b/test/periphery/integration/merkle-campaign/instant/claim/claim.tree new file mode 100644 index 000000000..4085d6cc5 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.tree @@ -0,0 +1,20 @@ +claim.t.sol +├── given the campaign has expired +│ └── it should revert +└── given the campaign has not expired + ├── given the recipient has claimed + │ └── it should revert + └── given the recipient has not claimed + ├── given the claim is not included in the Merkle tree + │ ├── when the index is not valid + │ │ └── it should revert + │ ├── when the recipient address is not valid + │ │ └── it should revert + │ ├── when the amount is not valid + │ │ └── it should revert + │ └── when the Merkle proof is not valid + │ └── it should revert + └── given the claim is included in the Merkle tree + ├── it should mark the index as claimed + ├── it should transfer the claim amount to the recipient + └── it should emit a {Claim} event diff --git a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol new file mode 100644 index 000000000..b448c7148 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { + function test_RevertWhen_CallerNotAdmin() external { + resetPrank({ msgSender: users.eve }); + vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); + merkleInstant.clawback({ to: users.eve, amount: 1 }); + } + + modifier whenCallerAdmin() { + resetPrank({ msgSender: users.admin }); + _; + } + + function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { + test_Clawback(users.admin); + } + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { + vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); + test_Clawback(users.admin); + } + + modifier postGracePeriod() { + vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); + _; + } + + function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierMerkleBase_ClawbackNotAllowed.selector, + getBlockTimestamp(), + defaults.EXPIRATION(), + defaults.FIRST_CLAIM_TIME() + ) + ); + merkleInstant.clawback({ to: users.admin, amount: 1 }); + } + + modifier givenCampaignExpired() { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + _; + } + + function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { + test_Clawback(users.admin); + } + + function testFuzz_Clawback(address to) + external + whenCallerAdmin + afterFirstClaim + postGracePeriod + givenCampaignExpired + { + vm.assume(to != address(0)); + test_Clawback(to); + } + + function test_Clawback(address to) internal { + uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleInstant))); + expectCallToTransfer({ to: to, value: clawbackAmount }); + vm.expectEmit({ emitter: address(merkleInstant) }); + emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); + merkleInstant.clawback({ to: to, amount: clawbackAmount }); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/ll/clawback/clawback.tree rename to test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree diff --git a/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol new file mode 100644 index 000000000..83cbc61ac --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { + /// @dev Needed to prevent "Stack too deep" error + struct Vars { + address actualAdmin; + address actualAsset; + string actualIpfsCID; + string actualName; + uint40 actualExpiration; + bytes32 actualMerkleRoot; + address expectedAdmin; + address expectedAsset; + uint40 expectedExpiration; + string expectedIpfsCID; + bytes32 expectedMerkleRoot; + bytes32 expectedName; + } + + function test_Constructor() external { + SablierMerkleInstant constructedInstant = new SablierMerkleInstant(defaults.baseParams()); + + Vars memory vars; + + vars.actualAdmin = constructedInstant.admin(); + vars.expectedAdmin = users.admin; + assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); + + vars.actualAsset = address(constructedInstant.ASSET()); + vars.expectedAsset = address(dai); + assertEq(vars.actualAsset, vars.expectedAsset, "asset"); + + vars.actualExpiration = constructedInstant.EXPIRATION(); + vars.expectedExpiration = defaults.EXPIRATION(); + assertEq(vars.actualExpiration, vars.expectedExpiration, "expiration"); + + vars.actualIpfsCID = constructedInstant.ipfsCID(); + vars.expectedIpfsCID = defaults.IPFS_CID(); + assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); + + vars.actualMerkleRoot = constructedInstant.MERKLE_ROOT(); + vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); + assertEq(vars.actualMerkleRoot, vars.expectedMerkleRoot, "merkleRoot"); + + vars.actualName = constructedInstant.name(); + vars.expectedName = defaults.NAME_BYTES32(); + assertEq(bytes32(abi.encodePacked(vars.actualName)), vars.expectedName, "name"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol new file mode 100644 index 000000000..e595feeda --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { + function test_GetFirstClaimTime_BeforeFirstClaim() external view { + uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); + assertEq(firstClaimTime, 0); + } + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function test_GetFirstClaimTime() external afterFirstClaim { + uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); + assertEq(firstClaimTime, getBlockTimestamp()); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.tree rename to test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree diff --git a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol new file mode 100644 index 000000000..a6174e239 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { + function test_HasClaimed_IndexNotInTree() external { + uint256 indexNotInTree = 1337e18; + assertFalse(merkleInstant.hasClaimed(indexNotInTree), "claimed"); + } + + modifier whenIndexInTree() { + _; + } + + function test_HasClaimed_NotClaimed() external whenIndexInTree { + assertFalse(merkleInstant.hasClaimed(defaults.INDEX1()), "claimed"); + } + + modifier givenRecipientHasClaimed() { + claimInstant(); + _; + } + + function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { + assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.tree rename to test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree diff --git a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol new file mode 100644 index 000000000..1e36520f9 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; + +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; + +contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { + function test_HasExpired_ExpirationZero() external { + ISablierMerkleInstant testLockup = createMerkleInstant({ expiration: 0 }); + assertFalse(testLockup.hasExpired(), "campaign expired"); + } + + modifier givenExpirationNotZero() { + _; + } + + function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { + assertFalse(merkleInstant.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() }); + assertTrue(merkleInstant.hasExpired(), "campaign not expired"); + } + + function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + assertTrue(merkleInstant.hasExpired(), "campaign not expired"); + } +} diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.tree rename to test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol similarity index 88% rename from test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol rename to test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index 44b234cd4..dd5af7b2d 100644 --- a/test/periphery/integration/merkle-lockup/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -4,21 +4,15 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract Claim_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract Claim_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); uint256 warpTime = expiration + 1 seconds; bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierMerkleLockup_CampaignExpired.selector, warpTime, expiration) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); merkleLL.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); } @@ -31,7 +25,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_StreamClaimed.selector, index1)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); merkleLL.claim(index1, users.recipient1, amount, merkleProof); } @@ -52,7 +46,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLL.claim(invalidIndex, users.recipient1, amount, merkleProof); } @@ -66,7 +60,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLL.claim(index1, invalidRecipient, amount, merkleProof); } @@ -79,7 +73,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLL.claim(index1, users.recipient1, invalidAmount, merkleProof); } @@ -92,7 +86,7 @@ contract Claim_Integration_Test is MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLL.claim(index1, users.recipient1, amount, invalidMerkleProof); } diff --git a/test/periphery/integration/merkle-lockup/ll/claim/claim.tree b/test/periphery/integration/merkle-campaign/ll/claim/claim.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/ll/claim/claim.tree rename to test/periphery/integration/merkle-campaign/ll/claim/claim.tree diff --git a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol similarity index 88% rename from test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol rename to test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol index 0256e4d6b..4bca20011 100644 --- a/test/periphery/integration/merkle-lockup/ll/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol @@ -4,13 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract Clawback_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); @@ -45,7 +41,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierMerkleLockup_ClawbackNotAllowed.selector, + Errors.SablierMerkleBase_ClawbackNotAllowed.selector, getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/lt/clawback/clawback.tree rename to test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree diff --git a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol similarity index 90% rename from test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol index 612adfadf..f6398616d 100644 --- a/test/periphery/integration/merkle-lockup/ll/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Constructor_MerkleLL_Integration_Test is MerkleLockup_Integration_Test { +contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error struct Vars { address actualAdmin; @@ -34,7 +34,9 @@ contract Constructor_MerkleLL_Integration_Test is MerkleLockup_Integration_Test } function test_Constructor() external { - SablierMerkleLL constructedLL = new SablierMerkleLL(defaults.baseParams(), lockupLinear, defaults.durations()); + SablierMerkleLL constructedLL = new SablierMerkleLL( + defaults.baseParams(), lockupLinear, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.durations() + ); Vars memory vars; diff --git a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol similarity index 69% rename from test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol rename to test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol index 75351bf69..b62284e2d 100644 --- a/test/periphery/integration/merkle-lockup/ll/get-first-claim-time/getFirstClaimTime.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol @@ -1,13 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { function test_GetFirstClaimTime_BeforeFirstClaim() external view { uint256 firstClaimTime = merkleLL.getFirstClaimTime(); assertEq(firstClaimTime, 0); diff --git a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.tree rename to test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree diff --git a/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol similarity index 73% rename from test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol rename to test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol index 0b07e9166..31d2edca2 100644 --- a/test/periphery/integration/merkle-lockup/ll/has-claimed/hasClaimed.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol @@ -1,13 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract HasClaimed_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { function test_HasClaimed_IndexNotInTree() external { uint256 indexNotInTree = 1337e18; assertFalse(merkleLL.hasClaimed(indexNotInTree), "claimed"); diff --git a/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.tree rename to test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree diff --git a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol similarity index 81% rename from test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol rename to test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol index 943cc0a39..c336351dd 100644 --- a/test/periphery/integration/merkle-lockup/ll/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol @@ -3,13 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { function test_HasExpired_ExpirationZero() external { ISablierMerkleLL testLockup = createMerkleLL({ expiration: 0 }); assertFalse(testLockup.hasExpired(), "campaign expired"); diff --git a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree new file mode 100644 index 000000000..5fd22925e --- /dev/null +++ b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree @@ -0,0 +1,10 @@ +hasExpired.t.sol +├── when the expiration is zero +│ └── it should return false +└── when the expiration is not zero + ├── when the expiration is less than the block timestamp + │ └── it should return false + ├── when the expiration is equal to the block timestamp + │ └── it should return true + └── when the expiration is greater than the block timestamp + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol similarity index 85% rename from test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol rename to test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index 81aea9d28..bdf326a35 100644 --- a/test/periphery/integration/merkle-lockup/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -7,27 +7,25 @@ import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleLockup, MerkleLT } from "src/periphery/types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "src/periphery/types/DataTypes.sol"; import { MerkleBuilder } from "test/utils/MerkleBuilder.sol"; import { Merkle } from "test/utils/Murky.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { +contract Claim_Integration_Test is Merkle, MerkleCampaign_Integration_Test { using MerkleBuilder for uint256[]; - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } - modifier whenTotalPercentageNotOneHundred() { _; } function test_RevertWhen_TotalPercentageLessThanOneHundred() external whenTotalPercentageNotOneHundred { // Create a MerkleLT campaign with a total percentage less than 100. - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); @@ -38,8 +36,14 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint64 totalPercentage = tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); - merkleLT = merkleLockupFactory.createMerkleLT( - baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + merkleLT = merkleFactory.createMerkleLT( + baseParams, + lockupTranched, + cancelable, + transferable, + tranchesWithPercentages, + aggregateAmount, + recipientCount ); // Claim an airstream. @@ -54,7 +58,9 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { function test_RevertWhen_TotalPercentageGreaterThanOneHundred() external whenTotalPercentageNotOneHundred { // Create a MerkleLT campaign with a total percentage less than 100. - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); + bool cancelable = defaults.CANCELABLE(); + bool transferable = defaults.TRANSFERABLE(); uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); uint256 recipientCount = defaults.RECIPIENT_COUNT(); @@ -65,8 +71,14 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint64 totalPercentage = tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); - merkleLT = merkleLockupFactory.createMerkleLT( - baseParams, lockupTranched, tranchesWithPercentages, aggregateAmount, recipientCount + merkleLT = merkleFactory.createMerkleLT( + baseParams, + lockupTranched, + cancelable, + transferable, + tranchesWithPercentages, + aggregateAmount, + recipientCount ); // Claim an airstream. @@ -88,9 +100,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 warpTime = expiration + 1 seconds; bytes32[] memory merkleProof; vm.warp({ newTimestamp: warpTime }); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierMerkleLockup_CampaignExpired.selector, warpTime, expiration) - ); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); } @@ -103,7 +113,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_StreamClaimed.selector, index1)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); merkleLT.claim(index1, users.recipient1, amount, merkleProof); } @@ -125,7 +135,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 invalidIndex = 1337; uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLT.claim(invalidIndex, users.recipient1, amount, merkleProof); } @@ -140,7 +150,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { address invalidRecipient = address(1337); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLT.claim(index1, invalidRecipient, amount, merkleProof); } @@ -154,7 +164,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 invalidAmount = 1337; bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLT.claim(index1, users.recipient1, invalidAmount, merkleProof); } @@ -168,7 +178,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { uint256 index1 = defaults.INDEX1(); uint128 amount = defaults.CLAIM_AMOUNT(); bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleLockup_InvalidProof.selector)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); merkleLT.claim(index1, users.recipient1, amount, invalidMerkleProof); } @@ -200,13 +210,15 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { bytes32[] memory proof = getProof(leaves.toBytes32(), pos); /// Declare the constructor params. - MerkleLockup.ConstructorParams memory baseParams = defaults.baseParams(); + MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); baseParams.merkleRoot = getRoot(leaves.toBytes32()); // Deploy a test MerkleLT contract. - ISablierMerkleLT testMerkleLT = merkleLockupFactory.createMerkleLT( + ISablierMerkleLT testMerkleLT = merkleFactory.createMerkleLT( baseParams, lockupTranched, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), defaults.tranchesWithPercentages(), defaults.AGGREGATE_AMOUNT(), defaults.RECIPIENT_COUNT() @@ -232,7 +244,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { recipient: users.recipient1, sender: users.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranchesMerkleLockup(claimAmount), + tranches: defaults.tranchesMerkleLT(claimAmount), wasCanceled: false }); @@ -270,7 +282,7 @@ contract Claim_Integration_Test is Merkle, MerkleLockup_Integration_Test { recipient: users.recipient1, sender: users.admin, startTime: getBlockTimestamp(), - tranches: defaults.tranchesMerkleLockup(), + tranches: defaults.tranchesMerkleLT(), wasCanceled: false }); diff --git a/test/periphery/integration/merkle-lockup/lt/claim/claim.tree b/test/periphery/integration/merkle-campaign/lt/claim/claim.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/lt/claim/claim.tree rename to test/periphery/integration/merkle-campaign/lt/claim/claim.tree diff --git a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol similarity index 88% rename from test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol rename to test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol index 23ee08233..0e9a7eae6 100644 --- a/test/periphery/integration/merkle-lockup/lt/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol @@ -4,13 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract Clawback_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); @@ -44,7 +40,7 @@ contract Clawback_Integration_Test is MerkleLockup_Integration_Test { function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( - Errors.SablierMerkleLockup_ClawbackNotAllowed.selector, + Errors.SablierMerkleBase_ClawbackNotAllowed.selector, getBlockTimestamp(), defaults.EXPIRATION(), defaults.FIRST_CLAIM_TIME() diff --git a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree new file mode 100644 index 000000000..b961e8883 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree @@ -0,0 +1,17 @@ +clawback.t.sol +├── when the caller is not the admin +│ └── it should revert +└── when the caller is the admin + ├── when the first claim has not been made + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── when the first claim has been made + ├── given the current time is not more than 7 days after the first claim + │ ├── it should perform the ERC-20 transfer + │ └── it should emit a {Clawback} event + └── given the current time is more than 7 days after the first claim + ├── given the campaign has not expired + │ └── it should revert + └── given the campaign has expired + ├── it should perform the ERC-20 transfer + └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol similarity index 89% rename from test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol index 5d7ca85cb..f53c915b5 100644 --- a/test/periphery/integration/merkle-lockup/lt/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Constructor_MerkleLT_Integration_Test is MerkleLockup_Integration_Test { +contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error struct Vars { address actualAdmin; @@ -36,8 +36,13 @@ contract Constructor_MerkleLT_Integration_Test is MerkleLockup_Integration_Test } function test_Constructor() external { - SablierMerkleLT constructedLT = - new SablierMerkleLT(defaults.baseParams(), lockupTranched, defaults.tranchesWithPercentages()); + SablierMerkleLT constructedLT = new SablierMerkleLT( + defaults.baseParams(), + lockupTranched, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), + defaults.tranchesWithPercentages() + ); Vars memory vars; diff --git a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol similarity index 69% rename from test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol rename to test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol index bcc624434..440ae386e 100644 --- a/test/periphery/integration/merkle-lockup/lt/get-first-claim-time/getFirstClaimTime.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol @@ -1,13 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { function test_GetFirstClaimTime_BeforeFirstClaim() external view { uint256 firstClaimTime = merkleLT.getFirstClaimTime(); assertEq(firstClaimTime, 0); diff --git a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree new file mode 100644 index 000000000..cab778426 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree @@ -0,0 +1,5 @@ +getFirstClaimTime.t.sol +├── when the first claim has not been made +│ └── it should return 0 +└── when the first claim has been made + └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol similarity index 73% rename from test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol rename to test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol index 54b13ac60..fae6f42cf 100644 --- a/test/periphery/integration/merkle-lockup/lt/has-claimed/hasClaimed.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol @@ -1,13 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract HasClaimed_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { function test_HasClaimed_IndexNotInTree() external { uint256 indexNotInTree = 1337e18; assertFalse(merkleLT.hasClaimed(indexNotInTree), "claimed"); diff --git a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree new file mode 100644 index 000000000..dcbcafe7a --- /dev/null +++ b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree @@ -0,0 +1,8 @@ +hasClaimed.t.sol +├── when the index is not in the Merkle tree +│ └── it should return false +└── when the index is in the Merkle tree + ├── given the recipient has not claimed + │ └── it should return false + └── given the recipient has claimed + └── it should return true diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol similarity index 81% rename from test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol rename to test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol index 16368ac7f..51896c39f 100644 --- a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol @@ -3,13 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; -import { MerkleLockup_Integration_Test } from "../../MerkleLockup.t.sol"; - -contract HasExpired_Integration_Test is MerkleLockup_Integration_Test { - function setUp() public virtual override { - MerkleLockup_Integration_Test.setUp(); - } +import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { function test_HasExpired_ExpirationZero() external { ISablierMerkleLT testLockup = createMerkleLT({ expiration: 0 }); assertFalse(testLockup.hasExpired(), "campaign expired"); diff --git a/test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree similarity index 100% rename from test/periphery/integration/merkle-lockup/lt/has-expired/hasExpired.tree rename to test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 5d569d589..6eab6972f 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -7,7 +7,7 @@ import { ud2x18, uUNIT } from "@prb/math/src/UD2x18.sol"; import { UD60x18, ud, ZERO } from "@prb/math/src/UD60x18.sol"; import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; -import { BatchLockup, MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; +import { BatchLockup, MerkleBase, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; import { ArrayBuilder } from "./ArrayBuilder.sol"; import { Constants } from "./Constants.sol"; @@ -443,7 +443,7 @@ contract Defaults is Constants, Merkle { MERKLE-LOCKUP //////////////////////////////////////////////////////////////////////////*/ - function baseParams() public view returns (MerkleLockup.ConstructorParams memory) { + function baseParams() public view returns (MerkleBase.ConstructorParams memory) { return baseParams(users.admin, asset, EXPIRATION, MERKLE_ROOT); } @@ -455,17 +455,15 @@ contract Defaults is Constants, Merkle { ) public pure - returns (MerkleLockup.ConstructorParams memory) + returns (MerkleBase.ConstructorParams memory) { - return MerkleLockup.ConstructorParams({ + return MerkleBase.ConstructorParams({ asset: asset_, - cancelable: CANCELABLE, expiration: expiration, initialAdmin: admin, ipfsCID: IPFS_CID, merkleRoot: merkleRoot, - name: NAME, - transferable: TRANSFERABLE + name: NAME }); } @@ -497,19 +495,15 @@ contract Defaults is Constants, Merkle { return LEAVES; } - function tranchesMerkleLockup() public view returns (LockupTranched.Tranche[] memory tranches_) { + function tranchesMerkleLT() public view returns (LockupTranched.Tranche[] memory tranches_) { tranches_ = new LockupTranched.Tranche[](2); tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: uint40(block.timestamp) + CLIFF_DURATION }); tranches_[1] = LockupTranched.Tranche({ amount: 7500e18, timestamp: uint40(block.timestamp) + TOTAL_DURATION }); } /// @dev Mirros the logic from {SablierMerkleLT._calculateTranches}. - function tranchesMerkleLockup(uint128 totalAmount) - public - view - returns (LockupTranched.Tranche[] memory tranches_) - { - tranches_ = tranchesMerkleLockup(); + function tranchesMerkleLT(uint128 totalAmount) public view returns (LockupTranched.Tranche[] memory tranches_) { + tranches_ = tranchesMerkleLT(); uint128 amount0 = ud(totalAmount).mul(tranchesWithPercentages()[0].unlockPercentage.intoUD60x18()).intoUint128(); uint128 amount1 = ud(totalAmount).mul(tranchesWithPercentages()[1].unlockPercentage.intoUD60x18()).intoUint128(); diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index d430d8c0b..5d50392ec 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -8,7 +8,7 @@ import { ISablierLockupDynamic } from "../../src/core/interfaces/ISablierLockupD import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; import { ISablierBatchLockup } from "../../src/periphery/interfaces/ISablierBatchLockup.sol"; -import { ISablierMerkleLockupFactory } from "../../src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleFactory } from "../../src/periphery/interfaces/ISablierMerkleFactory.sol"; abstract contract DeployOptimized is StdCheats { /*////////////////////////////////////////////////////////////////////////// @@ -104,19 +104,17 @@ abstract contract DeployOptimized is StdCheats { return ISablierBatchLockup(deployCode("out-optimized/SablierBatchLockup.sol/SablierBatchLockup.json")); } - /// @dev Deploys {SablierMerkleLockupFactory} from an optimized source compiled with `--via-ir`. - function deployOptimizedMerkleLockupFactory() internal returns (ISablierMerkleLockupFactory) { - return ISablierMerkleLockupFactory( - deployCode("out-optimized/SablierMerkleLockupFactory.sol/SablierMerkleLockupFactory.json") - ); + /// @dev Deploys {SablierMerkleFactory} from an optimized source compiled with `--via-ir`. + function deployOptimizedMerkleFactory() internal returns (ISablierMerkleFactory) { + return ISablierMerkleFactory(deployCode("out-optimized/SablierMerkleFactory.sol/SablierMerkleFactory.json")); } /// @notice Deploys all Periphery contracts from an optimized source in the following order: /// /// 1. {SablierBatchLockup} - /// 2. {SablierMerkleLockupFactory} - function deployOptimizedPeriphery() internal returns (ISablierBatchLockup, ISablierMerkleLockupFactory) { - return (deployOptimizedBatchLockup(), deployOptimizedMerkleLockupFactory()); + /// 2. {SablierMerkleFactory} + function deployOptimizedPeriphery() internal returns (ISablierBatchLockup, ISablierMerkleFactory) { + return (deployOptimizedBatchLockup(), deployOptimizedMerkleFactory()); } /*////////////////////////////////////////////////////////////////////////// @@ -130,7 +128,7 @@ abstract contract DeployOptimized is StdCheats { /// 3. {SablierLockupLinear} /// 4. {SablierLockupTranched} /// 5. {SablierBatchLockup} - /// 6. {SablierMerkleLockupFactory} + /// 6. {SablierMerkleFactory} function deployOptimizedProtocol( address initialAdmin, uint256 maxSegmentCount, @@ -143,11 +141,11 @@ abstract contract DeployOptimized is StdCheats { ISablierLockupLinear lockupLinear_, ISablierLockupTranched lockupTranched_, ISablierBatchLockup batchLockup_, - ISablierMerkleLockupFactory merkleLockupFactory_ + ISablierMerkleFactory merkleFactory_ ) { (nftDescriptor_, lockupDynamic_, lockupLinear_, lockupTranched_) = deployOptimizedCore(initialAdmin, maxSegmentCount, maxTrancheCount); - (batchLockup_, merkleLockupFactory_) = deployOptimizedPeriphery(); + (batchLockup_, merkleFactory_) = deployOptimizedPeriphery(); } } diff --git a/test/utils/Events.sol b/test/utils/Events.sol index 31ff07d3e..333f5e58b 100644 --- a/test/utils/Events.sol +++ b/test/utils/Events.sol @@ -7,9 +7,10 @@ import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescri import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { ISablierMerkleInstant } from "../../src/periphery/interfaces/ISablierMerkleInstant.sol"; import { ISablierMerkleLL } from "../../src/periphery/interfaces/ISablierMerkleLL.sol"; import { ISablierMerkleLT } from "../../src/periphery/interfaces/ISablierMerkleLT.sol"; -import { MerkleLockup, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; +import { MerkleBase, MerkleLT } from "../../src/periphery/types/DataTypes.sol"; /// @notice Abstract contract containing all the events emitted by the protocol. abstract contract Events { @@ -100,14 +101,25 @@ abstract contract Events { PERIPHERY //////////////////////////////////////////////////////////////////////////*/ + event Claim(uint256 index, address indexed recipient, uint128 amount); + event Claim(uint256 index, address indexed recipient, uint128 amount, uint256 indexed streamId); event Clawback(address indexed admin, address indexed to, uint128 amount); + event CreateMerkleInstant( + ISablierMerkleInstant indexed merkleInstant, + MerkleBase.ConstructorParams baseParams, + uint256 aggregateAmount, + uint256 recipientCount + ); + event CreateMerkleLL( ISablierMerkleLL indexed merkleLL, - MerkleLockup.ConstructorParams baseParams, + MerkleBase.ConstructorParams baseParams, ISablierLockupLinear lockupLinear, + bool cancelable, + bool transferable, LockupLinear.Durations streamDurations, uint256 aggregateAmount, uint256 recipientCount @@ -115,8 +127,10 @@ abstract contract Events { event CreateMerkleLT( ISablierMerkleLT indexed merkleLT, - MerkleLockup.ConstructorParams baseParams, + MerkleBase.ConstructorParams baseParams, ISablierLockupTranched lockupTranched, + bool cancelable, + bool transferable, MerkleLT.TrancheWithPercentage[] tranchesWithPercentages, uint256 totalDuration, uint256 aggregateAmount, diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 29a424058..f30771a19 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -9,7 +9,7 @@ import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; -import { ISablierMerkleLockupFactory } from "src/periphery/interfaces/ISablierMerkleLockupFactory.sol"; +import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { Base_Test } from "../Base.t.sol"; @@ -103,23 +103,21 @@ contract Precompiles_Test is Base_Test { assertEq(actualBatchLockup.code, expectedBatchLockup.code, "bytecodes mismatch"); } - function test_DeployMerkleLockupFactory() external onlyTestOptimizedProfile { - address actualFactory = address(precompiles.deployMerkleLockupFactory()); - address expectedFactory = address(deployOptimizedMerkleLockupFactory()); + function test_DeployMerkleFactory() external onlyTestOptimizedProfile { + address actualFactory = address(precompiles.deployMerkleFactory()); + address expectedFactory = address(deployOptimizedMerkleFactory()); assertEq(actualFactory.code, expectedFactory.code, "bytecodes mismatch"); } function test_DeployPeriphery() external onlyTestOptimizedProfile { - (ISablierBatchLockup actualBatchLockup, ISablierMerkleLockupFactory actualMerkleLockupFactory) = + (ISablierBatchLockup actualBatchLockup, ISablierMerkleFactory actualMerkleFactory) = precompiles.deployPeriphery(); - (ISablierBatchLockup expectedBatchLockup, ISablierMerkleLockupFactory expectedMerkleLockupFactory) = + (ISablierBatchLockup expectedBatchLockup, ISablierMerkleFactory expectedMerkleFactory) = deployOptimizedPeriphery(); assertEq(address(actualBatchLockup).code, address(expectedBatchLockup).code, "bytecodes mismatch"); - assertEq( - address(actualMerkleLockupFactory).code, address(expectedMerkleLockupFactory).code, "bytecodes mismatch" - ); + assertEq(address(actualMerkleFactory).code, address(expectedMerkleFactory).code, "bytecodes mismatch"); } /*////////////////////////////////////////////////////////////////////////// From 9c8ff1ff1af90f08f488ddb048aaaef89bf35c1e Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 12 Aug 2024 16:13:36 +0530 Subject: [PATCH 15/34] test: dry-ify the merkle tests (#1009) test: polish shared tests --- test/periphery/Periphery.t.sol | 4 + test/periphery/fork/Fork.t.sol | 2 +- .../createWithDurationsLD.t.sol | 2 +- .../createWithDurationsLL.t.sol | 2 +- .../createWithDurationsLT.t.sol | 2 +- .../createWithTimestampsLD.t.sol | 2 +- .../createWithTimestamps.t.sol | 2 +- .../createWithTimestampsLT.t.sol | 2 +- .../merkle-campaign/MerkleCampaign.t.sol | 6 +- .../instant/MerkleInstant.t.sol | 90 +++++++++++++++++++ .../merkle-campaign/instant/claim/claim.t.sol | 2 +- .../instant/clawback/clawback.t.sol | 80 ----------------- .../{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../instant/has-claimed/hasClaimed.t.sol | 28 ------ .../instant/has-expired/hasExpired.t.sol | 31 ------- .../merkle-campaign/ll/MerkleLL.t.sol | 81 +++++++++++++++++ .../merkle-campaign/ll/claim/claim.t.sol | 2 +- .../ll/clawback/clawback.t.sol | 80 ----------------- .../merkle-campaign/ll/clawback/clawback.tree | 17 ---- .../ll/{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../getFirstClaimTime.tree | 5 -- .../ll/has-claimed/hasClaimed.t.sol | 28 ------ .../ll/has-claimed/hasClaimed.tree | 8 -- .../ll/has-expired/hasExpired.t.sol | 31 ------- .../ll/has-expired/hasExpired.tree | 10 --- .../merkle-campaign/lt/MerkleLT.t.sol | 81 +++++++++++++++++ .../merkle-campaign/lt/claim/claim.t.sol | 2 +- .../merkle-campaign/lt/clawback/clawback.tree | 17 ---- .../lt/{constructor => }/constructor.t.sol | 2 +- .../getFirstClaimTime.t.sol | 22 ----- .../getFirstClaimTime.tree | 5 -- .../lt/has-claimed/hasClaimed.t.sol | 28 ------ .../lt/has-claimed/hasClaimed.tree | 8 -- .../lt/has-expired/hasExpired.t.sol | 31 ------- .../lt/has-expired/hasExpired.tree | 10 --- .../shared/MerkleCampaign.t.sol | 56 ++++++++++++ .../{lt => shared}/clawback/clawback.t.sol | 38 +++----- .../clawback/clawback.tree | 0 .../getFirstClaimTime.t.sol | 20 +++++ .../getFirstClaimTime.tree | 0 .../shared/has-claimed/hasClaimed.t.sol | 23 +++++ .../has-claimed/hasClaimed.tree | 0 .../shared/has-expired/hasExpired.t.sol | 32 +++++++ .../has-expired/hasExpired.tree | 0 46 files changed, 416 insertions(+), 524 deletions(-) create mode 100644 test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol rename test/periphery/integration/merkle-campaign/instant/{constructor => }/constructor.t.sol (96%) delete mode 100644 test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol create mode 100644 test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree rename test/periphery/integration/merkle-campaign/ll/{constructor => }/constructor.t.sol (97%) delete mode 100644 test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree create mode 100644 test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree rename test/periphery/integration/merkle-campaign/lt/{constructor => }/constructor.t.sol (98%) delete mode 100644 test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol delete mode 100644 test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree create mode 100644 test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol rename test/periphery/integration/merkle-campaign/{lt => shared}/clawback/clawback.t.sol (69%) rename test/periphery/integration/merkle-campaign/{instant => shared}/clawback/clawback.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/get-first-claim-time/getFirstClaimTime.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/has-claimed/hasClaimed.tree (100%) create mode 100644 test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol rename test/periphery/integration/merkle-campaign/{instant => shared}/has-expired/hasExpired.tree (100%) diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index e6049aa55..b2845469a 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -10,6 +10,10 @@ import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { Base_Test } from "../Base.t.sol"; contract Periphery_Test is Base_Test { + function setUp() public virtual override { + Base_Test.setUp(); + } + /*////////////////////////////////////////////////////////////////////////// MERKLE-BASE //////////////////////////////////////////////////////////////////////////*/ diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index 9a821184d..437a3d6d9 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -35,7 +35,7 @@ abstract contract Fork_Test is Periphery_Test, Merkle { vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); // Set up the parent test contract. - super.setUp(); + Periphery_Test.setUp(); // Load the external dependencies. loadDependencies(); diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 6013113ab..19472c0ce 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index 6029463c0..40748e402 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index 0deafcad4..5939ad99d 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index eca730f65..9af9272e5 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index 1bcc4b8f6..3c56008a6 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index 9844b7cc4..2de773919 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -8,7 +8,7 @@ import { Periphery_Test } from "../../../Periphery.t.sol"; contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); resetPrank({ msgSender: users.sender }); } diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 633a06b5a..52f66f022 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -8,8 +8,12 @@ import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol" import { Periphery_Test } from "../../Periphery.t.sol"; abstract contract MerkleCampaign_Integration_Test is Periphery_Test { + /*////////////////////////////////////////////////////////////////////////// + SET-UP FUNCTION + //////////////////////////////////////////////////////////////////////////*/ + function setUp() public virtual override { - super.setUp(); + Periphery_Test.setUp(); // Make Alice the caller. resetPrank(users.alice); diff --git a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol new file mode 100644 index 000000000..51e1fcd73 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleInstant_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {merkleInstant} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleInstant); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLInstant_Integration_Test is + Clawback_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLInstant_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleInstant_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLInstant_Integration_Test is + HasClaimed_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimInstant(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleInstant_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLInstant_Integration_Test is + HasExpired_Integration_Test, + MerkleInstant_Integration_Shared_Test +{ + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleInstant({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleInstant_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleInstant_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol index 14b356092..d4d1202d9 100644 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -5,7 +5,7 @@ import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is MerkleCampaign_Integration_Test { +contract Claim_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); uint256 warpTime = expiration + 1 seconds; diff --git a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol deleted file mode 100644 index b448c7148..000000000 --- a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.t.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleInstant.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; - } - - function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { - test_Clawback(users.admin); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); - test_Clawback(users.admin); - } - - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierMerkleBase_ClawbackNotAllowed.selector, - getBlockTimestamp(), - defaults.EXPIRATION(), - defaults.FIRST_CLAIM_TIME() - ) - ); - merkleInstant.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; - } - - function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { - test_Clawback(users.admin); - } - - function testFuzz_Clawback(address to) - external - whenCallerAdmin - afterFirstClaim - postGracePeriod - givenCampaignExpired - { - vm.assume(to != address(0)); - test_Clawback(to); - } - - function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleInstant))); - expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleInstant) }); - emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleInstant.clawback({ to: to, amount: clawbackAmount }); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol similarity index 96% rename from test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/instant/constructor.t.sol index 83cbc61ac..535dba4c0 100644 --- a/test/periphery/integration/merkle-campaign/instant/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/constructor.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index e595feeda..000000000 --- a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleInstant.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol deleted file mode 100644 index a6174e239..000000000 --- a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleInstant.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleInstant.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimInstant(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol deleted file mode 100644 index 1e36520f9..000000000 --- a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleInstant testLockup = createMerkleInstant({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleInstant.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleInstant.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleInstant.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol new file mode 100644 index 000000000..7a06ee63c --- /dev/null +++ b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleLL_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {MerkleLL} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleLL); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLL_Integration_Test is Clawback_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleLL_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLL_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleLL_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLL_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLL_Integration_Test is HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimLL(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLL_Integration_Test is HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test { + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLL({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleLL_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index dd5af7b2d..26d7d5b13 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -6,7 +6,7 @@ import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is MerkleCampaign_Integration_Test { +contract Claim_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertGiven_CampaignExpired() external { uint40 expiration = defaults.EXPIRATION(); uint256 warpTime = expiration + 1 seconds; diff --git a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol deleted file mode 100644 index 4bca20011..000000000 --- a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.t.sol +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertWhen_CallerNotAdmin() external { - resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleLL.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; - } - - function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { - test_Clawback(users.admin); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { - vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); - test_Clawback(users.admin); - } - - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierMerkleBase_ClawbackNotAllowed.selector, - getBlockTimestamp(), - defaults.EXPIRATION(), - defaults.FIRST_CLAIM_TIME() - ) - ); - merkleLL.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; - } - - function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { - test_Clawback(users.admin); - } - - function testFuzz_Clawback(address to) - external - whenCallerAdmin - afterFirstClaim - postGracePeriod - givenCampaignExpired - { - vm.assume(to != address(0)); - test_Clawback(to); - } - - function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLL))); - expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleLL) }); - emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleLL.clawback({ to: to, amount: clawbackAmount }); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree deleted file mode 100644 index b961e8883..000000000 --- a/test/periphery/integration/merkle-campaign/ll/clawback/clawback.tree +++ /dev/null @@ -1,17 +0,0 @@ -clawback.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the first claim has not been made - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── when the first claim has been made - ├── given the current time is not more than 7 days after the first claim - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── given the current time is more than 7 days after the first claim - ├── given the campaign has not expired - │ └── it should revert - └── given the campaign has expired - ├── it should perform the ERC-20 transfer - └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol similarity index 97% rename from test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/ll/constructor.t.sol index f6398616d..ef83d82f8 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupLinear } from "src/core/types/DataTypes.sol"; import { SablierMerkleLL } from "src/periphery/SablierMerkleLL.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index b62284e2d..000000000 --- a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleLL.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleLL.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree deleted file mode 100644 index cab778426..000000000 --- a/test/periphery/integration/merkle-campaign/ll/get-first-claim-time/getFirstClaimTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -getFirstClaimTime.t.sol -├── when the first claim has not been made -│ └── it should return 0 -└── when the first claim has been made - └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol deleted file mode 100644 index 31d2edca2..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleLL.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleLL.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimLL(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree deleted file mode 100644 index dcbcafe7a..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-claimed/hasClaimed.tree +++ /dev/null @@ -1,8 +0,0 @@ -hasClaimed.t.sol -├── when the index is not in the Merkle tree -│ └── it should return false -└── when the index is in the Merkle tree - ├── given the recipient has not claimed - │ └── it should return false - └── given the recipient has claimed - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol deleted file mode 100644 index c336351dd..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleLL testLockup = createMerkleLL({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleLL.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleLL.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleLL.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree deleted file mode 100644 index 5fd22925e..000000000 --- a/test/periphery/integration/merkle-campaign/ll/has-expired/hasExpired.tree +++ /dev/null @@ -1,10 +0,0 @@ -hasExpired.t.sol -├── when the expiration is zero -│ └── it should return false -└── when the expiration is not zero - ├── when the expiration is less than the block timestamp - │ └── it should return false - ├── when the expiration is equal to the block timestamp - │ └── it should return true - └── when the expiration is greater than the block timestamp - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol new file mode 100644 index 000000000..92181fe9b --- /dev/null +++ b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { Clawback_Integration_Test } from "../shared/clawback/clawback.t.sol"; +import { GetFirstClaimTime_Integration_Test } from "../shared/get-first-claim-time/getFirstClaimTime.t.sol"; +import { HasClaimed_Integration_Test } from "../shared/has-claimed/hasClaimed.t.sol"; +import { HasExpired_Integration_Test } from "../shared/has-expired/hasExpired.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../shared/MerkleCampaign.t.sol"; + +/*////////////////////////////////////////////////////////////////////////// + NON-SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +abstract contract MerkleLT_Integration_Shared_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + + // Cast the {MerkleLT} contract as {ISablierMerkleBase} + merkleBase = ISablierMerkleBase(merkleLT); + } +} + +/*////////////////////////////////////////////////////////////////////////// + SHARED TESTS +//////////////////////////////////////////////////////////////////////////*/ + +contract Clawback_MerkleLT_Integration_Test is Clawback_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(Clawback_Integration_Test, MerkleLT_Integration_Shared_Test) { + Clawback_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract GetFirstClaimTime_MerkleLT_Integration_Test is + GetFirstClaimTime_Integration_Test, + MerkleLT_Integration_Shared_Test +{ + modifier afterFirstClaim() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLT_Integration_Shared_Test) { + GetFirstClaimTime_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract HasClaimed_MerkleLT_Integration_Test is HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier givenRecipientHasClaimed() override { + // Make the first claim to set `_firstClaimTime`. + claimLT(); + _; + } + + function setUp() public override(HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test) { + HasClaimed_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} + +contract HasExpired_MerkleLT_Integration_Test is HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test { + modifier createMerkleCampaignWithZeroExpiry() override { + campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLT({ expiration: 0 })); + _; + } + + function setUp() public override(HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test) { + HasExpired_Integration_Test.setUp(); + MerkleLT_Integration_Shared_Test.setUp(); + } +} diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index bdf326a35..05285864a 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -14,7 +14,7 @@ import { Merkle } from "test/utils/Murky.sol"; import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; -contract Claim_Integration_Test is Merkle, MerkleCampaign_Integration_Test { +contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_Test { using MerkleBuilder for uint256[]; modifier whenTotalPercentageNotOneHundred() { diff --git a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree deleted file mode 100644 index b961e8883..000000000 --- a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.tree +++ /dev/null @@ -1,17 +0,0 @@ -clawback.t.sol -├── when the caller is not the admin -│ └── it should revert -└── when the caller is the admin - ├── when the first claim has not been made - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── when the first claim has been made - ├── given the current time is not more than 7 days after the first claim - │ ├── it should perform the ERC-20 transfer - │ └── it should emit a {Clawback} event - └── given the current time is more than 7 days after the first claim - ├── given the campaign has not expired - │ └── it should revert - └── given the campaign has expired - ├── it should perform the ERC-20 transfer - └── it should emit a {Clawback} event diff --git a/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol similarity index 98% rename from test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol rename to test/periphery/integration/merkle-campaign/lt/constructor.t.sol index f53c915b5..01c5a0ee5 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { SablierMerkleLT } from "src/periphery/SablierMerkleLT.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Test { /// @dev Needed to prevent "Stack too deep" error diff --git a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol deleted file mode 100644 index 440ae386e..000000000 --- a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.t.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Test { - function test_GetFirstClaimTime_BeforeFirstClaim() external view { - uint256 firstClaimTime = merkleLT.getFirstClaimTime(); - assertEq(firstClaimTime, 0); - } - - modifier afterFirstClaim() { - // Make the first claim to set `_firstClaimTime`. - claimLT(); - _; - } - - function test_GetFirstClaimTime() external afterFirstClaim { - uint256 firstClaimTime = merkleLT.getFirstClaimTime(); - assertEq(firstClaimTime, getBlockTimestamp()); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree deleted file mode 100644 index cab778426..000000000 --- a/test/periphery/integration/merkle-campaign/lt/get-first-claim-time/getFirstClaimTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -getFirstClaimTime.t.sol -├── when the first claim has not been made -│ └── it should return 0 -└── when the first claim has been made - └── it should return the time of the first claim diff --git a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol deleted file mode 100644 index fae6f42cf..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.t.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasClaimed_IndexNotInTree() external { - uint256 indexNotInTree = 1337e18; - assertFalse(merkleLT.hasClaimed(indexNotInTree), "claimed"); - } - - modifier whenIndexInTree() { - _; - } - - function test_HasClaimed_NotClaimed() external whenIndexInTree { - assertFalse(merkleLT.hasClaimed(defaults.INDEX1()), "claimed"); - } - - modifier givenRecipientHasClaimed() { - claimLT(); - _; - } - - function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { - assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree deleted file mode 100644 index dcbcafe7a..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-claimed/hasClaimed.tree +++ /dev/null @@ -1,8 +0,0 @@ -hasClaimed.t.sol -├── when the index is not in the Merkle tree -│ └── it should return false -└── when the index is in the Merkle tree - ├── given the recipient has not claimed - │ └── it should return false - └── given the recipient has claimed - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol deleted file mode 100644 index 51896c39f..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.t.sol +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; - -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract HasExpired_Integration_Test is MerkleCampaign_Integration_Test { - function test_HasExpired_ExpirationZero() external { - ISablierMerkleLT testLockup = createMerkleLT({ expiration: 0 }); - assertFalse(testLockup.hasExpired(), "campaign expired"); - } - - modifier givenExpirationNotZero() { - _; - } - - function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { - assertFalse(merkleLT.hasExpired(), "campaign expired"); - } - - function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() }); - assertTrue(merkleLT.hasExpired(), "campaign not expired"); - } - - function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - assertTrue(merkleLT.hasExpired(), "campaign not expired"); - } -} diff --git a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree deleted file mode 100644 index 2a359a81e..000000000 --- a/test/periphery/integration/merkle-campaign/lt/has-expired/hasExpired.tree +++ /dev/null @@ -1,10 +0,0 @@ -hasExpired.t.sol -├── given the expiration is zero -│ └── it should return false -└── given the expiration is not zero - ├── given the expiration is less than the block timestamp - │ └── it should return false - ├── given the expiration is equal to the block timestamp - │ └── it should return true - └── given the expiration is greater than the block timestamp - └── it should return true diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol new file mode 100644 index 000000000..24684a6e8 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { MerkleCampaign_Integration_Test } from "../MerkleCampaign.t.sol"; + +abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integration_Test { + /// @dev A test contract meant to be overridden by the implementing contract, which will be either + /// {SablierMerkleLL}, {SablierMerkleLT} or {SablierMerkleInstant}. + ISablierMerkleBase internal merkleBase; + + function setUp() public virtual override { + MerkleCampaign_Integration_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev A shared modifier meant to be overridden by the implementing test contracts. + modifier afterFirstClaim() virtual { + _; + } + + modifier createMerkleCampaignWithZeroExpiry() virtual { + _; + } + + modifier givenCampaignExpired() { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + _; + } + + modifier givenExpirationNotZero() { + _; + } + + modifier givenRecipientHasClaimed() virtual { + _; + } + + modifier postGracePeriod() { + vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); + _; + } + + modifier whenCallerAdmin() { + resetPrank({ msgSender: users.admin }); + _; + } + + modifier whenIndexInTree() { + _; + } +} diff --git a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol similarity index 69% rename from test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol rename to test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol index 0e9a7eae6..64d4ba322 100644 --- a/test/periphery/integration/merkle-campaign/lt/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol @@ -4,39 +4,28 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors as CoreErrors } from "src/core/libraries/Errors.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } -contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { function test_RevertWhen_CallerNotAdmin() external { resetPrank({ msgSender: users.eve }); vm.expectRevert(abi.encodeWithSelector(CoreErrors.CallerNotAdmin.selector, users.admin, users.eve)); - merkleLT.clawback({ to: users.eve, amount: 1 }); - } - - modifier whenCallerAdmin() { - resetPrank({ msgSender: users.admin }); - _; + merkleBase.clawback({ to: users.eve, amount: 1 }); } function test_Clawback_BeforeFirstClaim() external whenCallerAdmin { test_Clawback(users.admin); } - modifier afterFirstClaim() { - claimLT(); - _; - } - function test_Clawback_GracePeriod() external whenCallerAdmin afterFirstClaim { vm.warp({ newTimestamp: getBlockTimestamp() + 6 days }); test_Clawback(users.admin); } - modifier postGracePeriod() { - vm.warp({ newTimestamp: getBlockTimestamp() + 8 days }); - _; - } - function test_RevertGiven_CampaignNotExpired() external whenCallerAdmin afterFirstClaim postGracePeriod { vm.expectRevert( abi.encodeWithSelector( @@ -46,12 +35,7 @@ contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { defaults.FIRST_CLAIM_TIME() ) ); - merkleLT.clawback({ to: users.admin, amount: 1 }); - } - - modifier givenCampaignExpired() { - vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); - _; + merkleBase.clawback({ to: users.admin, amount: 1 }); } function test_Clawback() external whenCallerAdmin afterFirstClaim postGracePeriod givenCampaignExpired { @@ -70,10 +54,10 @@ contract Clawback_Integration_Test is MerkleCampaign_Integration_Test { } function test_Clawback(address to) internal { - uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleLT))); + uint128 clawbackAmount = uint128(dai.balanceOf(address(merkleBase))); expectCallToTransfer({ to: to, value: clawbackAmount }); - vm.expectEmit({ emitter: address(merkleLT) }); + vm.expectEmit({ emitter: address(merkleBase) }); emit Clawback({ admin: users.admin, to: to, amount: clawbackAmount }); - merkleLT.clawback({ to: to, amount: clawbackAmount }); + merkleBase.clawback({ to: to, amount: clawbackAmount }); } } diff --git a/test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/clawback/clawback.tree rename to test/periphery/integration/merkle-campaign/shared/clawback/clawback.tree diff --git a/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol new file mode 100644 index 000000000..332eeaced --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_GetFirstClaimTime_BeforeFirstClaim() external view { + uint256 firstClaimTime = merkleBase.getFirstClaimTime(); + assertEq(firstClaimTime, 0); + } + + function test_GetFirstClaimTime() external view afterFirstClaim { + uint256 firstClaimTime = merkleBase.getFirstClaimTime(); + assertEq(firstClaimTime, getBlockTimestamp()); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/get-first-claim-time/getFirstClaimTime.tree rename to test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.tree diff --git a/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol new file mode 100644 index 000000000..3719ed9e9 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.t.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract HasClaimed_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_HasClaimed_IndexNotInTree() external { + uint256 indexNotInTree = 1337e18; + assertFalse(merkleBase.hasClaimed(indexNotInTree), "claimed"); + } + + function test_HasClaimed_NotClaimed() external whenIndexInTree { + assertFalse(merkleBase.hasClaimed(defaults.INDEX1()), "claimed"); + } + + function test_HasClaimed() external whenIndexInTree givenRecipientHasClaimed { + assertTrue(merkleBase.hasClaimed(defaults.INDEX1()), "not claimed"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree b/test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/has-claimed/hasClaimed.tree rename to test/periphery/integration/merkle-campaign/shared/has-claimed/hasClaimed.tree diff --git a/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol new file mode 100644 index 000000000..c7480442b --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../../shared/MerkleCampaign.t.sol"; + +abstract contract HasExpired_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + ISablierMerkleBase internal campaignWithZeroExpiry; + + function test_HasExpired_ExpirationZero() external view createMerkleCampaignWithZeroExpiry { + assertFalse(campaignWithZeroExpiry.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationLessThanBlockTimestamp() external view givenExpirationNotZero { + assertFalse(merkleBase.hasExpired(), "campaign expired"); + } + + function test_HasExpired_ExpirationEqualToBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() }); + assertTrue(merkleBase.hasExpired(), "campaign not expired"); + } + + function test_HasExpired_ExpirationGreaterThanBlockTimestamp() external givenExpirationNotZero { + vm.warp({ newTimestamp: defaults.EXPIRATION() + 1 seconds }); + assertTrue(merkleBase.hasExpired(), "campaign not expired"); + } +} diff --git a/test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.tree similarity index 100% rename from test/periphery/integration/merkle-campaign/instant/has-expired/hasExpired.tree rename to test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.tree From cb43e66025ac6572475e24e117dfc61f2dfe063b Mon Sep 17 00:00:00 2001 From: Paul Razvan Berg Date: Wed, 14 Aug 2024 14:49:02 +0200 Subject: [PATCH 16/34] docs: polish wording in NatSpec (#1014) * docs: polish wording in NatSpec * docs: fixes --- src/core/interfaces/ISablierLockup.sol | 6 +- src/core/interfaces/ISablierLockupDynamic.sol | 10 +-- src/core/interfaces/ISablierLockupLinear.sol | 10 +-- .../interfaces/ISablierLockupTranched.sol | 10 +-- src/core/types/DataTypes.sol | 66 +++++++++---------- .../interfaces/ISablierMerkleFactory.sol | 2 +- 6 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/core/interfaces/ISablierLockup.sol b/src/core/interfaces/ISablierLockup.sol index f3ccd1dfd..5c2471161 100644 --- a/src/core/interfaces/ISablierLockup.sol +++ b/src/core/interfaces/ISablierLockup.sol @@ -30,7 +30,7 @@ interface ISablierLockup is /// @param streamId The ID of the stream. /// @param sender The address of the stream's sender. /// @param recipient The address of the stream's recipient. - /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param asset The contract address of the ERC-20 asset that has been distributed. /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's /// decimals. /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the @@ -59,7 +59,7 @@ interface ISablierLockup is /// @notice Emitted when assets are withdrawn from a stream. /// @param streamId The ID of the stream. /// @param to The address that has received the withdrawn assets. - /// @param asset The contract address of the ERC-20 asset to be distributed. + /// @param asset The contract address of the ERC-20 asset that has been withdrawn. /// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals. event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount); @@ -72,7 +72,7 @@ interface ISablierLockup is /// @dev This value is hard coded as a constant. function MAX_BROKER_FEE() external view returns (UD60x18); - /// @notice Retrieves the address of the ERC-20 asset to be distributed. + /// @notice Retrieves the address of the ERC-20 asset being distributed. /// @dev Reverts if `streamId` references a null stream. /// @param streamId The stream ID for the query. function getAsset(uint256 streamId) external view returns (IERC20 asset); diff --git a/src/core/interfaces/ISablierLockupDynamic.sol b/src/core/interfaces/ISablierLockupDynamic.sol index d6b4604af..98899d658 100644 --- a/src/core/interfaces/ISablierLockupDynamic.sol +++ b/src/core/interfaces/ISablierLockupDynamic.sol @@ -16,15 +16,15 @@ interface ISablierLockupDynamic is ISablierLockup { /// @notice Emitted when a stream is created. /// @param streamId The ID of the newly created stream. /// @param funder The address which has funded the stream. - /// @param sender The address distributing the assets, which will have the ability to cancel the stream. - /// @param recipient The address toward which to stream the assets. - /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// @param sender The address distributing the assets, which is able to cancel the stream. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param amounts Struct encapsulating (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. - /// @param cancelable Boolean indicating whether the stream will be cancelable or not. + /// @param cancelable Boolean indicating whether the stream is cancelable or not. /// @param transferable Boolean indicating whether the stream NFT is transferable or not. /// @param segments The segments the protocol uses to compose the dynamic distribution function. - /// @param timestamps Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps. + /// @param timestamps Struct encapsulating (i) the stream's start time and (ii) end time, both as Unix timestamps. /// @param broker The address of the broker who has helped create the stream, e.g. a front-end website. event CreateLockupDynamicStream( uint256 streamId, diff --git a/src/core/interfaces/ISablierLockupLinear.sol b/src/core/interfaces/ISablierLockupLinear.sol index 213e92f87..81f4a5bfe 100644 --- a/src/core/interfaces/ISablierLockupLinear.sol +++ b/src/core/interfaces/ISablierLockupLinear.sol @@ -16,14 +16,14 @@ interface ISablierLockupLinear is ISablierLockup { /// @notice Emitted when a stream is created. /// @param streamId The ID of the newly created stream. /// @param funder The address which funded the stream. - /// @param sender The address distributing the assets, which will have the ability to cancel the stream. - /// @param recipient The address receiving the assets. - /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// @param sender The address distributing the assets, which is able to to cancel the stream. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param amounts Struct encapsulating (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. - /// @param cancelable Boolean indicating whether the stream will be cancelable or not. + /// @param cancelable Boolean indicating whether the stream is cancelable or not. /// @param transferable Boolean indicating whether the stream NFT is transferable or not. - /// @param timestamps Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as + /// @param timestamps Struct encapsulating (i) the stream's start time, (ii) cliff time, and (iii) end time, all as /// Unix timestamps. /// @param broker The address of the broker who has helped create the stream, e.g. a front-end website. event CreateLockupLinearStream( diff --git a/src/core/interfaces/ISablierLockupTranched.sol b/src/core/interfaces/ISablierLockupTranched.sol index a1d147255..fb0fb4425 100644 --- a/src/core/interfaces/ISablierLockupTranched.sol +++ b/src/core/interfaces/ISablierLockupTranched.sol @@ -16,15 +16,15 @@ interface ISablierLockupTranched is ISablierLockup { /// @notice Emitted when a stream is created. /// @param streamId The ID of the newly created stream. /// @param funder The address which has funded the stream. - /// @param sender The address distributing the assets, which will have the ability to cancel the stream. - /// @param recipient The address toward which to stream the assets. - /// @param amounts Struct containing (i) the deposit amount, and (ii) the broker fee amount, both denoted + /// @param sender The address distributing the assets, which is able to cancel the stream. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param amounts Struct encapsulating (i) the deposit amount, and (ii) the broker fee amount, both denoted /// in units of the asset's decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. - /// @param cancelable Boolean indicating whether the stream will be cancelable or not. + /// @param cancelable Boolean indicating whether the stream is cancelable or not. /// @param transferable Boolean indicating whether the stream NFT is transferable or not. /// @param tranches The tranches the protocol uses to compose the tranched distribution function. - /// @param timestamps Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps. + /// @param timestamps Struct encapsulating (i) the stream's start time and (ii) end time, both as Unix timestamps. /// @param broker The address of the broker who has helped create the stream, e.g. a front-end website. event CreateLockupTranchedStream( uint256 streamId, diff --git a/src/core/types/DataTypes.sol b/src/core/types/DataTypes.sol index f665bb17b..ebe5c4820 100644 --- a/src/core/types/DataTypes.sol +++ b/src/core/types/DataTypes.sol @@ -82,7 +82,7 @@ library Lockup { /// @param isDepleted Boolean indicating if the stream is depleted. /// @param isStream Boolean indicating if the struct entity exists. /// @param isTransferable Boolean indicating if the stream NFT is transferable. - /// @param amounts Struct containing the deposit, withdrawn, and refunded amounts, both denoted in units of the + /// @param amounts Struct encapsulating the deposit, withdrawn, and refunded amounts, both denoted in units of the /// asset's decimals. struct Stream { // slot 0 @@ -104,17 +104,17 @@ library Lockup { /// @notice Namespace for the structs used in {SablierLockupDynamic}. library LockupDynamic { /// @notice Struct encapsulating the parameters of the {SablierLockupDynamic.createWithDurations} function. - /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be - /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param sender The address distributing the assets, which is able to cancel the stream. It doesn't have to be the + /// same as `msg.sender`. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param segments Segments with durations used to compose the dynamic distribution function. Timestamps are /// calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { address sender; @@ -128,17 +128,17 @@ library LockupDynamic { } /// @notice Struct encapsulating the parameters of the {SablierLockupDynamic.createWithTimestamps} function. - /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be - /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param sender The address distributing the assets, which is able to cancel the stream. It doesn't have to be the + /// same as `msg.sender`. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param startTime The Unix timestamp indicating the stream's start. /// @param segments Segments used to compose the dynamic distribution function. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { address sender; @@ -153,7 +153,7 @@ library LockupDynamic { } /// @notice Segment struct used in the Lockup Dynamic stream. - /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. + /// @param amount The amount of assets streamed in the segment, denoted in units of the asset's decimals. /// @param exponent The exponent of the segment, denoted as a fixed-point number. /// @param timestamp The Unix timestamp indicating the segment's end. struct Segment { @@ -164,7 +164,7 @@ library LockupDynamic { } /// @notice Segment struct used at runtime in {SablierLockupDynamic.createWithDurations}. - /// @param amount The amount of assets to be streamed in the segment, denoted in units of the asset's decimals. + /// @param amount The amount of assets streamed in the segment, denoted in units of the asset's decimals. /// @param exponent The exponent of the segment, denoted as a fixed-point number. /// @param duration The time difference in seconds between the segment and the previous one. struct SegmentWithDuration { @@ -204,14 +204,14 @@ library LockupLinear { /// @notice Struct encapsulating the parameters of the {SablierLockupLinear.createWithDurations} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param durations Struct containing (i) cliff period duration and (ii) total stream duration, both in seconds. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param durations Struct encapsulating (i) cliff period duration and (ii) total stream duration, both in seconds. + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { address sender; @@ -227,15 +227,15 @@ library LockupLinear { /// @notice Struct encapsulating the parameters of the {SablierLockupLinear.createWithTimestamps} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. - /// @param timestamps Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as + /// @param timestamps Struct encapsulating (i) the stream's start time, (ii) cliff time, and (iii) end time, all as /// Unix timestamps. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { address sender; @@ -289,15 +289,15 @@ library LockupTranched { /// @notice Struct encapsulating the parameters of the {SablierLockupTranched.createWithDurations} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param tranches Tranches with durations used to compose the tranched distribution function. Timestamps are /// calculated by starting from `block.timestamp` and adding each duration to the previous timestamp. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithDurations { address sender; @@ -313,15 +313,15 @@ library LockupTranched { /// @notice Struct encapsulating the parameters of the {SablierLockupTranched.createWithTimestamps} function. /// @param sender The address distributing the assets, with the ability to cancel the stream. It doesn't have to be /// the same as `msg.sender`. - /// @param recipient The address receiving the assets. - /// @param totalAmount The total amount of ERC-20 assets to be distributed, including the stream deposit and any - /// broker fee, both denoted in units of the asset's decimals. + /// @param recipient The address receiving the assets, as well as the NFT owner. + /// @param totalAmount The total amount, including the deposit and any broker fee, denoted in units of the asset's + /// decimals. /// @param asset The contract address of the ERC-20 asset to be distributed. /// @param cancelable Indicates if the stream is cancelable. /// @param transferable Indicates if the stream NFT is transferable. /// @param startTime The Unix timestamp indicating the stream's start. /// @param tranches Tranches used to compose the tranched distribution function. - /// @param broker Struct containing (i) the address of the broker assisting in creating the stream, and (ii) the + /// @param broker Struct encapsulating (i) the address of the broker assisting in creating the stream, and (ii) the /// percentage fee paid to the broker from `totalAmount`, denoted as a fixed-point number. Both can be set to zero. struct CreateWithTimestamps { address sender; diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 746d91dfa..7a3c71d71 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -22,7 +22,7 @@ interface ISablierMerkleFactory { EVENTS //////////////////////////////////////////////////////////////////////////*/ - /// @notice Emitted when a {SablierV2MerkleInstant} campaign is created. + /// @notice Emitted when a {SablierMerkleInstant} campaign is created. event CreateMerkleInstant( ISablierMerkleInstant indexed merkleInstant, MerkleBase.ConstructorParams baseParams, From 690add88a42e86dbb203b72dbb0e6cbd1aa87979 Mon Sep 17 00:00:00 2001 From: Andrei Vlad Birgaoanu <99738872+andreivladbrg@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:55:52 +0300 Subject: [PATCH 17/34] Refactor/dry fy claim (#1011) * refactor: dry-fy claim function test: update tests accordingly test: dry fy claim tests test: finish claim tests test: fixes and polishes refactor: remove unneeded bitmap import test: move helper claim function build: include benchmark dir in lint:sol chore: remove unused imports test: move base merkle contract * style: format using forge formatter * Address Shub's feedback * test: make the shared claim virtual * test: inherit the campaign shared test contract in claim * test: claim polishes Co-authored-by: smol-ninja --------- Co-authored-by: smol-ninja --- benchmark/BatchLockup.Gas.t.sol | 2 +- benchmark/LockupDynamic.Gas.t.sol | 2 +- benchmark/LockupTranched.Gas.t.sol | 2 +- bun.lockb | Bin 43089 -> 43717 bytes package.json | 4 +- script/DeployDeterministicProtocol.s.sol | 4 +- script/DeployProtocol.s.sol | 4 +- script/core/DeployCore.s.sol | 4 +- script/core/DeployDeterministicCore.s.sol | 4 +- src/core/SablierLockupDynamic.sol | 20 +- src/core/SablierLockupLinear.sol | 16 +- src/core/SablierLockupTranched.sol | 20 +- src/core/abstracts/SablierLockup.sol | 24 +- src/core/interfaces/ISablierLockupDynamic.sol | 8 +- src/core/interfaces/ISablierLockupLinear.sol | 8 +- .../interfaces/ISablierLockupTranched.sol | 8 +- src/core/libraries/Helpers.sol | 8 +- src/periphery/SablierMerkleFactory.sol | 4 +- src/periphery/SablierMerkleInstant.sol | 26 +- src/periphery/SablierMerkleLL.sol | 27 +- src/periphery/SablierMerkleLT.sol | 33 +-- src/periphery/abstracts/SablierMerkleBase.sol | 65 +++-- .../interfaces/ISablierMerkleBase.sol | 16 ++ .../interfaces/ISablierMerkleFactory.sol | 4 +- .../interfaces/ISablierMerkleInstant.sol | 19 -- src/periphery/interfaces/ISablierMerkleLL.sol | 28 --- src/periphery/interfaces/ISablierMerkleLT.sol | 29 --- .../lockup-dynamic/createWithDurations.t.sol | 4 +- .../lockup-dynamic/createWithTimestamps.t.sol | 16 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 4 +- .../lockup-linear/createWithDurations.t.sol | 8 +- .../lockup-linear/createWithTimestamps.t.sol | 8 +- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 4 +- .../lockup-linear/withdrawableAmountOf.t.sol | 4 +- .../lockup-tranched/createWithDurations.t.sol | 4 +- .../createWithTimestamps.t.sol | 16 +- .../fuzz/lockup-tranched/withdraw.t.sol | 4 +- .../core/integration/fuzz/lockup/cancel.t.sol | 4 +- .../integration/fuzz/lockup/withdraw.t.sol | 8 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 12 +- .../shared/lockup-linear/LockupLinear.t.sol | 8 +- .../lockup-tranched/LockupTranched.t.sol | 12 +- .../fork/merkle-campaign/MerkleInstant.t.sol | 3 +- .../fork/merkle-campaign/MerkleLL.t.sol | 9 +- .../fork/merkle-campaign/MerkleLT.t.sol | 9 +- .../merkle-campaign/MerkleCampaign.t.sol | 27 -- .../instant/MerkleInstant.t.sol | 23 -- .../merkle-campaign/instant/claim/claim.t.sol | 103 +------- .../merkle-campaign/instant/claim/claim.tree | 20 -- .../merkle-campaign/ll/MerkleLL.t.sol | 23 -- .../merkle-campaign/ll/claim/claim.t.sol | 102 +------- .../merkle-campaign/lt/MerkleLT.t.sol | 23 -- .../merkle-campaign/lt/claim/claim.t.sol | 230 +++--------------- .../merkle-campaign/lt/claim/claim.tree | 28 +-- .../shared/MerkleCampaign.t.sol | 40 ++- .../merkle-campaign/shared/claim/claim.t.sol | 90 +++++++ .../{ll => shared}/claim/claim.tree | 5 +- .../shared/clawback/clawback.t.sol | 4 +- .../getFirstClaimTime.t.sol | 2 +- .../shared/has-expired/hasExpired.t.sol | 5 +- test/utils/Defaults.sol | 12 +- test/utils/Utils.sol | 8 +- 62 files changed, 470 insertions(+), 801 deletions(-) delete mode 100644 test/periphery/integration/merkle-campaign/instant/claim/claim.tree create mode 100644 test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol rename test/periphery/integration/merkle-campaign/{ll => shared}/claim/claim.tree (83%) diff --git a/benchmark/BatchLockup.Gas.t.sol b/benchmark/BatchLockup.Gas.t.sol index aafd0da24..8a655d755 100644 --- a/benchmark/BatchLockup.Gas.t.sol +++ b/benchmark/BatchLockup.Gas.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { LockupDynamic, LockupLinear, LockupTranched } from "../src/core/types/DataTypes.sol"; +import { LockupDynamic, LockupTranched } from "../src/core/types/DataTypes.sol"; import { BatchLockup } from "../src/periphery/types/DataTypes.sol"; import { BatchLockupBuilder } from "../test/utils/BatchLockupBuilder.sol"; diff --git a/benchmark/LockupDynamic.Gas.t.sol b/benchmark/LockupDynamic.Gas.t.sol index 315dd7786..021fbe9d1 100644 --- a/benchmark/LockupDynamic.Gas.t.sol +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupDynamic } from "../src/core/types/DataTypes.sol"; +import { LockupDynamic } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol index e802d3516..665bf9def 100644 --- a/benchmark/LockupTranched.Gas.t.sol +++ b/benchmark/LockupTranched.Gas.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "../src/core/types/DataTypes.sol"; +import { LockupTranched } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; diff --git a/bun.lockb b/bun.lockb index c7900ccb45dfcb6ae6b0c8eddd7490a173f6331d..50714ba61be90989f507d79fdc274ae11e21609d 100755 GIT binary patch delta 4201 zcmeHKdr*|u6~Eud0=pYtim)J&mxv&+2+J-YxVxx@iij>QP#++VNKgTJuAn@81Y8wS zJXT}VIyyE~5ea4+%Cr`Yw!V@W`v__q9UUJrPHHqWwbmK2=iJ>*mYMvMnf{qO^ZT89 ze)svEdw1vDzg!jn{F%5%87a7)y#4!#jd1XZ&ye(TX~v7UE0V`n#Ttv$^3|n-F16}j z#*3*tKS&I0=x#h*!dw{hW^B_}&Wue$TUK0GAJb5~`X>6G=+~{PG_9&-3!UX7^7zJm1WK#UHY}|=&+Fc&bq7PVI@l~toR3q>i76MJ3ZvWHf78^w9l zlSE-A%=grZyQOg1T`T(-zn}W!1h|e1hC+j$gglGcQ{pXClZz|3!vqz)>Q8S)yp!s^WeGj@|~ri zVEIn4PO!)-GqQBS6JO~mgcWytc^Eeg~x22ts_|)SZDLeQfy5K8n_-o#nF=9h#=d9 zpyFt0!yCD3wbZYf&9y4cwg$4)u@ylbtlRs3OB>uu{U9bn1^NgtD2n(cAMiu&Bu>EZ zFs=6E-Td)x@;mzfzngoba|H%@(fP>z(fLd1-m)>zF0A&{uaFd}?MtN&EEKnSCP-mAlW>oPV#o@A!>hn4Ay) zweN%cg$xQ~XpKS69!f>pxwSzfpG@zQnvCI(GWN*-c{=*T#x*sUG@{}Qb=8Z?dy4nd z4t`c(3XqJv3inyNetpYFXLkImE5~$BR1d<&m(2{ylr-ZoXWv+=S8+biIdCQ^CeBwl zhsTl9%6XKtGG3A8`dk>go}4+=yYIi^bNAtz$_bX#xRTW`ay!$;BJVp#eSQ7#gIi6m47yYbcsYIrh2siG@_((%m;ZM6maLQuOE(*oT)8p(t+G!R86PsxCMcjlt;f9Q z+t2fd<7)c6$Jpeq8P^m5OEuJVNUea}gmFz%;79^BWos1Rtkz?#M?>c@#yKyM>iwKu zlBizDd62V5GAU)8hdKMsBBhG+dCq|;q?kBg;T)byN-O74&dS-Oba1}KS)(PTi}M4{ zS{*6-IX~u{t|#RX=VzR=(@5#zJjOY14k`VdUFK4~knCIG^Vn zm`;j`^A*nF8Kksw9_6h3DJdPCZ*kVlC#8$?1J2q^QucFx%sG7lDTg>eF4Z{P4z;~gPc7Uky6Han6vLtHg1jxP=og`iW&Mqrc!c*rTOrKnOm zTTXtlsL>Q39D5ZD8CjKYq^%WSD_d{g4D!h^KEuausU8(!LO8v`m&SGh63fW(IkOUT(IzF})UJ zN1h<4EGM?b2tvH&hPlDXDNz{*hR$4=xa+6~KJ8;;V(oi?O>a+wfn9Gx=(b?XKv$3e hPF*K0pYDF(10kI=;EQ*4(9>A~MZ2OcIX$n0{{ag2G7bO$ delta 3827 zcmeHKdr(y8760yKVcC^e+?1ELKfG8lW=0SP+N)SQ?1Mz#>5#$?S$AiVi_N8(`u90A!u7h(}|frf<5Q#GTrTD`gi}xnfd+B zJ-_pP-~H~n-@>`?-IgbQE%$2|Jv{Wm&juSte)UuF$Zh`E^~%BrSwSa0dhN-dkA7J5 z$$=G(SB3;z^MENrj%gaOybe=teoKXi5dK1R{KZ{}0Q7g!`=W2!xXrwArx0%_g-~JK zT3uhiwW%45QiyuOQwT5Al2p(pY2`4L?TloQRkKU9f~0sKjw=0vpAUV1#F94i@ORy@ zGlu88RUy{~RChbizXg8o!SF~CX^VGnlx?S#eiB?%CBc+uKU|m_Z+l&JOP0LgV`Tz- z6sYpV9j4;l6fhjUjDlqt$nZE=ud-rP%+U@{z3MtfYcY~wSgn`Cl<<;K2f;3L@+q5}=FLtL|g;0xlrK@LauQ zgheqXsT20Z#K}L5gflS)`Fo3MaHMk-yQ)6v zYL_5fOZPA{k83r#wVhv%pSjw8J4*NQles@A&0q22y0@&ySJfO$Io4S9^owD2Z-8<6 zjc1BWJVZcG>djXV4`mmmrrHlCk3 zmeO~7dQtH&tFq#@PPKOa{Cr>H+Kb1pWI0vLA972JaPh$u4g91u$IB@d2qh_$Do)kF z+bJ$74QxoI)C{It(p^#^a3!5m=h8H=Q16lo1yvfQD$_NvEzKnr2JdjnN3Vgf^c)o@6#;lX8T4nmNxv z${_O-=3*l$r8J28*2XM_1^BY z6V<2wF{P@r{J1AE-Pbz!`TBgHrr&>{tvIZI;O_nI;%9E}{B-$mqAN`Q8a(>hjT5_! zA-BGKdiA6P_exC8hjkk~=5yRzs)6z{m$S7UepE)s&QKNvUgf#YvvxqqI!aAr>cTpg zR1-+$MX8qfTMA zlc;xSG!O7%#NouaI@THP>#9|S`Ry4VMff3M=gT7Q2z5y6Y!IO2Ua=y zlO<-zGcTa6!DjQus1Cf?gV>AsHiDXqc0?Uw6Jj$wHv3yE@oEDi2|-P4Bw{`y3=xh< zM8qMe6`?-n6$I6WDnU<9Pg;wpLQwOH-LXhPP{W&mScr&4L?Pl4)bdc3wj;12vZ#hV zyArI07-k@-@1+9Jv#m$0MU*12aT4ng<%rdYVg$9iS%_=|^~rh!evpV~5iJN4A_qaO z@H_;)u*C=}K6MFHHYzZ-Z~olVQQx+n6tpcC$g{+T(Gj7&&>Y$qRhM2Ez6`M)dMpXv zR46JKtsV?lEQN_0yb3}DBK#2nh!6zrfl9grL1n=cCxUHhtxKhOG=-`{XN0C4ooy+* zYVhs@2(6$C=5^<&EspS=AzNK{g(T^0mwFP(J=ovk=9a8Yg6iIK(4MY`k=~Oq&{qR_ j1K+p#_eV&!KMqU=dg>DGpI6X76a|w*`L<)H6XbsbA|cG! diff --git a/package.json b/package.json index c0f23ed57..d6165fad3 100644 --- a/package.json +++ b/package.json @@ -66,12 +66,14 @@ "build:smt": "FOUNDRY_PROFILE=smt forge build", "clean": "rm -rf artifacts broadcast cache docs out out-optimized out-svg", "lint": "bun run lint:sol && bun run prettier:check", - "lint:sol": "forge fmt --check && bun solhint \"{precompiles,script,src,test}/**/*.sol\"", + "lint:sol": "forge fmt --check && bun solhint \"{benchmark,precompiles,script,src,test}/**/*.sol\"", "prepack": "bun install && bash ./shell/prepare-artifacts.sh", "prettier:check": "prettier --check \"**/*.{json,md,svg,yml}\"", "prettier:write": "prettier --write \"**/*.{json,md,svg,yml}\"", "test": "forge test", + "test:core": "FOUNDRY_PROFILE=lite forge test --match-path \"test/core/**/*.sol\" --nmt \"testFork\"", "test:lite": "FOUNDRY_PROFILE=lite forge test", + "test:periphery": "FOUNDRY_PROFILE=lite forge test --match-path \"test/periphery/**/*.sol\" --nmt \"testFork\"", "test:optimized": "bun run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" } } diff --git a/script/DeployDeterministicProtocol.s.sol b/script/DeployDeterministicProtocol.s.sol index ca753bd5c..aad615212 100644 --- a/script/DeployDeterministicProtocol.s.sol +++ b/script/DeployDeterministicProtocol.s.sol @@ -13,7 +13,9 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys the Lockup Protocol at deterministic addresses across chains. contract DeployDeterministicProtocol is BaseScript { /// @dev Deploy via Forge. - function run(address initialAdmin) + function run( + address initialAdmin + ) public virtual broadcast diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol index 07fd2ad46..dbb1ba098 100644 --- a/script/DeployProtocol.s.sol +++ b/script/DeployProtocol.s.sol @@ -13,7 +13,9 @@ import { BaseScript } from "./Base.s.sol"; /// @notice Deploys the Lockup Protocol. contract DeployProtocol is BaseScript { /// @dev Deploy via Forge. - function run(address initialAdmin) + function run( + address initialAdmin + ) public virtual broadcast diff --git a/script/core/DeployCore.s.sol b/script/core/DeployCore.s.sol index b1a803176..6113cec39 100644 --- a/script/core/DeployCore.s.sol +++ b/script/core/DeployCore.s.sol @@ -10,7 +10,9 @@ import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all Core contracts. contract DeployCore is BaseScript { - function run(address initialAdmin) + function run( + address initialAdmin + ) public virtual broadcast diff --git a/script/core/DeployDeterministicCore.s.sol b/script/core/DeployDeterministicCore.s.sol index 13964749b..2494e311e 100644 --- a/script/core/DeployDeterministicCore.s.sol +++ b/script/core/DeployDeterministicCore.s.sol @@ -11,7 +11,9 @@ import { BaseScript } from "../Base.s.sol"; /// @notice Deploys all Core contracts at deterministic addresses across chains. /// @dev Reverts if any contract has already been deployed. contract DeployDeterministicCore is BaseScript { - function run(address initialAdmin) + function run( + address initialAdmin + ) public virtual broadcast diff --git a/src/core/SablierLockupDynamic.sol b/src/core/SablierLockupDynamic.sol index f43622933..b3cd92cc2 100644 --- a/src/core/SablierLockupDynamic.sol +++ b/src/core/SablierLockupDynamic.sol @@ -77,7 +77,9 @@ contract SablierLockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierLockupDynamic - function getSegments(uint256 streamId) + function getSegments( + uint256 streamId + ) external view override @@ -88,7 +90,9 @@ contract SablierLockupDynamic is } /// @inheritdoc ISablierLockupDynamic - function getStream(uint256 streamId) + function getStream( + uint256 streamId + ) external view override @@ -120,7 +124,9 @@ contract SablierLockupDynamic is } /// @inheritdoc ISablierLockupDynamic - function getTimestamps(uint256 streamId) + function getTimestamps( + uint256 streamId + ) external view override @@ -135,7 +141,9 @@ contract SablierLockupDynamic is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierLockupDynamic - function createWithDurations(LockupDynamic.CreateWithDurations calldata params) + function createWithDurations( + LockupDynamic.CreateWithDurations calldata params + ) external override noDelegateCall @@ -161,7 +169,9 @@ contract SablierLockupDynamic is } /// @inheritdoc ISablierLockupDynamic - function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupDynamic.CreateWithTimestamps calldata params + ) external override noDelegateCall diff --git a/src/core/SablierLockupLinear.sol b/src/core/SablierLockupLinear.sol index 7f5822023..642737d76 100644 --- a/src/core/SablierLockupLinear.sol +++ b/src/core/SablierLockupLinear.sol @@ -73,7 +73,9 @@ contract SablierLockupLinear is } /// @inheritdoc ISablierLockupLinear - function getStream(uint256 streamId) + function getStream( + uint256 streamId + ) external view override @@ -105,7 +107,9 @@ contract SablierLockupLinear is } /// @inheritdoc ISablierLockupLinear - function getTimestamps(uint256 streamId) + function getTimestamps( + uint256 streamId + ) external view override @@ -124,7 +128,9 @@ contract SablierLockupLinear is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierLockupLinear - function createWithDurations(LockupLinear.CreateWithDurations calldata params) + function createWithDurations( + LockupLinear.CreateWithDurations calldata params + ) external override noDelegateCall @@ -160,7 +166,9 @@ contract SablierLockupLinear is } /// @inheritdoc ISablierLockupLinear - function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupLinear.CreateWithTimestamps calldata params + ) external override noDelegateCall diff --git a/src/core/SablierLockupTranched.sol b/src/core/SablierLockupTranched.sol index d80a79791..16c08a391 100644 --- a/src/core/SablierLockupTranched.sol +++ b/src/core/SablierLockupTranched.sol @@ -72,7 +72,9 @@ contract SablierLockupTranched is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierLockupTranched - function getStream(uint256 streamId) + function getStream( + uint256 streamId + ) external view override @@ -104,7 +106,9 @@ contract SablierLockupTranched is } /// @inheritdoc ISablierLockupTranched - function getTimestamps(uint256 streamId) + function getTimestamps( + uint256 streamId + ) external view override @@ -115,7 +119,9 @@ contract SablierLockupTranched is } /// @inheritdoc ISablierLockupTranched - function getTranches(uint256 streamId) + function getTranches( + uint256 streamId + ) external view override @@ -130,7 +136,9 @@ contract SablierLockupTranched is //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierLockupTranched - function createWithDurations(LockupTranched.CreateWithDurations calldata params) + function createWithDurations( + LockupTranched.CreateWithDurations calldata params + ) external override noDelegateCall @@ -156,7 +164,9 @@ contract SablierLockupTranched is } /// @inheritdoc ISablierLockupTranched - function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupTranched.CreateWithTimestamps calldata params + ) external override noDelegateCall diff --git a/src/core/abstracts/SablierLockup.sol b/src/core/abstracts/SablierLockup.sol index 9deecb6f9..41b8706d7 100644 --- a/src/core/abstracts/SablierLockup.sol +++ b/src/core/abstracts/SablierLockup.sol @@ -80,7 +80,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function getDepositedAmount(uint256 streamId) + function getDepositedAmount( + uint256 streamId + ) external view override @@ -102,7 +104,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function getRefundedAmount(uint256 streamId) + function getRefundedAmount( + uint256 streamId + ) external view override @@ -123,7 +127,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function getWithdrawnAmount(uint256 streamId) + function getWithdrawnAmount( + uint256 streamId + ) external view override @@ -173,7 +179,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function refundableAmountOf(uint256 streamId) + function refundableAmountOf( + uint256 streamId + ) external view override @@ -195,7 +203,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function streamedAmountOf(uint256 streamId) + function streamedAmountOf( + uint256 streamId + ) public view override @@ -226,7 +236,9 @@ abstract contract SablierLockup is } /// @inheritdoc ISablierLockup - function withdrawableAmountOf(uint256 streamId) + function withdrawableAmountOf( + uint256 streamId + ) external view override diff --git a/src/core/interfaces/ISablierLockupDynamic.sol b/src/core/interfaces/ISablierLockupDynamic.sol index 98899d658..1ad989e45 100644 --- a/src/core/interfaces/ISablierLockupDynamic.sol +++ b/src/core/interfaces/ISablierLockupDynamic.sol @@ -80,7 +80,9 @@ interface ISablierLockupDynamic is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithDurations(LockupDynamic.CreateWithDurations calldata params) + function createWithDurations( + LockupDynamic.CreateWithDurations calldata params + ) external returns (uint256 streamId); @@ -107,7 +109,9 @@ interface ISablierLockupDynamic is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithTimestamps(LockupDynamic.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupDynamic.CreateWithTimestamps calldata params + ) external returns (uint256 streamId); } diff --git a/src/core/interfaces/ISablierLockupLinear.sol b/src/core/interfaces/ISablierLockupLinear.sol index 81f4a5bfe..978de2de9 100644 --- a/src/core/interfaces/ISablierLockupLinear.sol +++ b/src/core/interfaces/ISablierLockupLinear.sol @@ -76,7 +76,9 @@ interface ISablierLockupLinear is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithDurations(LockupLinear.CreateWithDurations calldata params) + function createWithDurations( + LockupLinear.CreateWithDurations calldata params + ) external returns (uint256 streamId); @@ -102,7 +104,9 @@ interface ISablierLockupLinear is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithTimestamps(LockupLinear.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupLinear.CreateWithTimestamps calldata params + ) external returns (uint256 streamId); } diff --git a/src/core/interfaces/ISablierLockupTranched.sol b/src/core/interfaces/ISablierLockupTranched.sol index fb0fb4425..b9f58a5e8 100644 --- a/src/core/interfaces/ISablierLockupTranched.sol +++ b/src/core/interfaces/ISablierLockupTranched.sol @@ -80,7 +80,9 @@ interface ISablierLockupTranched is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithDurations(LockupTranched.CreateWithDurations calldata params) + function createWithDurations( + LockupTranched.CreateWithDurations calldata params + ) external returns (uint256 streamId); @@ -107,7 +109,9 @@ interface ISablierLockupTranched is ISablierLockup { /// /// @param params Struct encapsulating the function parameters, which are documented in {DataTypes}. /// @return streamId The ID of the newly created stream. - function createWithTimestamps(LockupTranched.CreateWithTimestamps calldata params) + function createWithTimestamps( + LockupTranched.CreateWithTimestamps calldata params + ) external returns (uint256 streamId); } diff --git a/src/core/libraries/Helpers.sol b/src/core/libraries/Helpers.sol index e0202c081..33899e984 100644 --- a/src/core/libraries/Helpers.sol +++ b/src/core/libraries/Helpers.sol @@ -14,7 +14,9 @@ library Helpers { //////////////////////////////////////////////////////////////////////////*/ /// @dev Calculate the timestamps and return the segments. - function calculateSegmentTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) + function calculateSegmentTimestamps( + LockupDynamic.SegmentWithDuration[] memory segments + ) internal view returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) @@ -47,7 +49,9 @@ library Helpers { } /// @dev Calculate the timestamps and return the tranches. - function calculateTrancheTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + function calculateTrancheTimestamps( + LockupTranched.TrancheWithDuration[] memory tranches + ) internal view returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) diff --git a/src/periphery/SablierMerkleFactory.sol b/src/periphery/SablierMerkleFactory.sol index 3cb2260fb..f970b4603 100644 --- a/src/periphery/SablierMerkleFactory.sol +++ b/src/periphery/SablierMerkleFactory.sol @@ -24,7 +24,9 @@ contract SablierMerkleFactory is ISablierMerkleFactory { //////////////////////////////////////////////////////////////////////////*/ /// @inheritdoc ISablierMerkleFactory - function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) + function isPercentagesSum100( + MerkleLT.TrancheWithPercentage[] calldata tranches + ) external pure override diff --git a/src/periphery/SablierMerkleInstant.sol b/src/periphery/SablierMerkleInstant.sol index 62c3450d1..c6bccb328 100644 --- a/src/periphery/SablierMerkleInstant.sol +++ b/src/periphery/SablierMerkleInstant.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -15,7 +14,6 @@ contract SablierMerkleInstant is ISablierMerkleInstant, // 2 inherited components SablierMerkleBase // 4 inherited components { - using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// @@ -26,29 +24,11 @@ contract SablierMerkleInstant is constructor(MerkleBase.ConstructorParams memory baseParams) SablierMerkleBase(baseParams) { } /*////////////////////////////////////////////////////////////////////////// - USER-FACING NON-CONSTANT FUNCTIONS + INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleInstant - function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof - ) - external - override - { - // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second - // preimage attacks. - bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); - - // Check: validate the function. - _checkClaim(index, leaf, merkleProof); - - // Effect: mark the index as claimed. - _claimedBitMap.set(index); - + /// @inheritdoc SablierMerkleBase + function _claim(uint256 index, address recipient, uint128 amount) internal override { // Interaction: withdraw the assets to the recipient. ASSET.safeTransfer(recipient, amount); diff --git a/src/periphery/SablierMerkleLL.sol b/src/periphery/SablierMerkleLL.sol index e56967d37..2f847c561 100644 --- a/src/periphery/SablierMerkleLL.sol +++ b/src/periphery/SablierMerkleLL.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ud } from "@prb/math/src/UD60x18.sol"; @@ -19,7 +18,6 @@ contract SablierMerkleLL is ISablierMerkleLL, // 2 inherited components SablierMerkleBase // 4 inherited components { - using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// @@ -66,29 +64,10 @@ contract SablierMerkleLL is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLL - function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof - ) - external - override - returns (uint256 streamId) - { - // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second - // preimage attacks. - bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); - - // Check: validate the function. - _checkClaim(index, leaf, merkleProof); - - // Effect: mark the index as claimed. - _claimedBitMap.set(index); - + /// @inheritdoc SablierMerkleBase + function _claim(uint256 index, address recipient, uint128 amount) internal override { // Interaction: create the stream via {SablierLockupLinear}. - streamId = LOCKUP_LINEAR.createWithDurations( + uint256 streamId = LOCKUP_LINEAR.createWithDurations( LockupLinear.CreateWithDurations({ sender: admin, recipient: recipient, diff --git a/src/periphery/SablierMerkleLT.sol b/src/periphery/SablierMerkleLT.sol index a1f41c59a..f2f567626 100644 --- a/src/periphery/SablierMerkleLT.sol +++ b/src/periphery/SablierMerkleLT.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { BitMaps } from "@openzeppelin/contracts/utils/structs/BitMaps.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { uUNIT } from "@prb/math/src/UD2x18.sol"; @@ -21,7 +20,6 @@ contract SablierMerkleLT is ISablierMerkleLT, // 2 inherited components SablierMerkleBase // 4 inherited components { - using BitMaps for BitMaps.BitMap; using SafeERC20 for IERC20; /*////////////////////////////////////////////////////////////////////////// @@ -87,40 +85,21 @@ contract SablierMerkleLT is } /*////////////////////////////////////////////////////////////////////////// - USER-FACING NON-CONSTANT FUNCTIONS + INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @inheritdoc ISablierMerkleLT - function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof - ) - external - override - returns (uint256 streamId) - { + /// @inheritdoc SablierMerkleBase + function _claim(uint256 index, address recipient, uint128 amount) internal override { // Check: the sum of percentages equals 100%. if (TOTAL_PERCENTAGE != uUNIT) { revert Errors.SablierMerkleLT_TotalPercentageNotOneHundred(TOTAL_PERCENTAGE); } - // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second - // preimage attacks. - bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); - - // Check: validate the function. - _checkClaim(index, leaf, merkleProof); - // Calculate the tranches based on the unlock percentages. LockupTranched.TrancheWithDuration[] memory tranches = _calculateTranches(amount); - // Effect: mark the index as claimed. - _claimedBitMap.set(index); - // Interaction: create the stream via {SablierLockupTranched}. - streamId = LOCKUP_TRANCHED.createWithDurations( + uint256 streamId = LOCKUP_TRANCHED.createWithDurations( LockupTranched.CreateWithDurations({ sender: admin, recipient: recipient, @@ -142,7 +121,9 @@ contract SablierMerkleLT is //////////////////////////////////////////////////////////////////////////*/ /// @dev Calculates the tranches based on the claim amount and the unlock percentages for each tranche. - function _calculateTranches(uint128 claimAmount) + function _calculateTranches( + uint128 claimAmount + ) internal view returns (LockupTranched.TrancheWithDuration[] memory tranches) diff --git a/src/periphery/abstracts/SablierMerkleBase.sol b/src/periphery/abstracts/SablierMerkleBase.sol index fcfe60722..a469d5fee 100644 --- a/src/periphery/abstracts/SablierMerkleBase.sol +++ b/src/periphery/abstracts/SablierMerkleBase.sol @@ -93,6 +93,47 @@ abstract contract SablierMerkleBase is USER-FACING NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @inheritdoc ISablierMerkleBase + function claim( + uint256 index, + address recipient, + uint128 amount, + bytes32[] calldata merkleProof + ) + external + override + { + // Check: the campaign has not expired. + if (hasExpired()) { + revert Errors.SablierMerkleBase_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); + } + + // Check: the index has not been claimed. + if (_claimedBitMap.get(index)) { + revert Errors.SablierMerkleBase_StreamClaimed(index); + } + + // Generate the Merkle tree leaf by hashing the corresponding parameters. Hashing twice prevents second + // preimage attacks. + bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(index, recipient, amount)))); + + // Check: the input claim is included in the Merkle tree. + if (!MerkleProof.verify(merkleProof, MERKLE_ROOT, leaf)) { + revert Errors.SablierMerkleBase_InvalidProof(); + } + + // Effect: set the `_firstClaimTime` if its zero. + if (_firstClaimTime == 0) { + _firstClaimTime = uint40(block.timestamp); + } + + // Effect: mark the index as claimed. + _claimedBitMap.set(index); + + // Call the internal virtual function. + _claim(index, recipient, amount); + } + /// @inheritdoc ISablierMerkleBase function clawback(address to, uint128 amount) external override onlyAdmin { // Check: current timestamp is over the grace period and the campaign has not expired. @@ -125,26 +166,6 @@ abstract contract SablierMerkleBase is INTERNAL NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Validates the parameters of the `claim` function, which is implemented by child contracts. - function _checkClaim(uint256 index, bytes32 leaf, bytes32[] calldata merkleProof) internal { - // Check: the campaign has not expired. - if (hasExpired()) { - revert Errors.SablierMerkleBase_CampaignExpired({ blockTimestamp: block.timestamp, expiration: EXPIRATION }); - } - - // Check: the index has not been claimed. - if (_claimedBitMap.get(index)) { - revert Errors.SablierMerkleBase_StreamClaimed(index); - } - - // Check: the input claim is included in the Merkle tree. - if (!MerkleProof.verify(merkleProof, MERKLE_ROOT, leaf)) { - revert Errors.SablierMerkleBase_InvalidProof(); - } - - // Effect: set the `_firstClaimTime` if its zero. - if (_firstClaimTime == 0) { - _firstClaimTime = uint40(block.timestamp); - } - } + /// @dev This function is implemented by child contracts, so the logic varies depending on the model. + function _claim(uint256 index, address recipient, uint128 amount) internal virtual; } diff --git a/src/periphery/interfaces/ISablierMerkleBase.sol b/src/periphery/interfaces/ISablierMerkleBase.sol index d2426033e..4e76d8e8c 100644 --- a/src/periphery/interfaces/ISablierMerkleBase.sol +++ b/src/periphery/interfaces/ISablierMerkleBase.sol @@ -52,6 +52,22 @@ interface ISablierMerkleBase is IAdminable { NON-CONSTANT FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ + /// @notice Makes the claim. + /// + /// @dev Depending on the Merkle campaign, it either transfers assets to the recipient or creates a Lockup stream + /// with an NFT minted to the recipient. + /// + /// Requirements: + /// - The campaign must not have expired. + /// - The stream must not have been claimed already. + /// - The Merkle proof must be valid. + /// + /// @param index The index of the recipient in the Merkle tree. + /// @param recipient The address of the airdrop recipient. + /// @param amount The amount of ERC-20 assets to be transferred to the recipient. + /// @param merkleProof The proof of inclusion in the Merkle tree. + function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external; + /// @notice Claws back the unclaimed tokens from the campaign. /// /// @dev Emits a {Clawback} event. diff --git a/src/periphery/interfaces/ISablierMerkleFactory.sol b/src/periphery/interfaces/ISablierMerkleFactory.sol index 7a3c71d71..9845b8de7 100644 --- a/src/periphery/interfaces/ISablierMerkleFactory.sol +++ b/src/periphery/interfaces/ISablierMerkleFactory.sol @@ -63,7 +63,9 @@ interface ISablierMerkleFactory { /// @dev Reverts if the sum of percentages overflows. /// @param tranches The tranches with their respective unlock percentages. /// @return result True if the sum of percentages equals 100%, otherwise false. - function isPercentagesSum100(MerkleLT.TrancheWithPercentage[] calldata tranches) + function isPercentagesSum100( + MerkleLT.TrancheWithPercentage[] calldata tranches + ) external pure returns (bool result); diff --git a/src/periphery/interfaces/ISablierMerkleInstant.sol b/src/periphery/interfaces/ISablierMerkleInstant.sol index 656f47139..002aa2aeb 100644 --- a/src/periphery/interfaces/ISablierMerkleInstant.sol +++ b/src/periphery/interfaces/ISablierMerkleInstant.sol @@ -12,23 +12,4 @@ interface ISablierMerkleInstant is ISablierMerkleBase { /// @notice Emitted when a recipient claims an instant airdrop. event Claim(uint256 index, address indexed recipient, uint128 amount); - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Makes the claim and transfer assets to the recipient. - /// - /// @dev Emits a {Claim} event. - /// - /// Requirements: - /// - The campaign must not have expired. - /// - The stream must not have been claimed already. - /// - The Merkle proof must be valid. - /// - /// @param index The index of the recipient in the Merkle tree. - /// @param recipient The address of the airdrop recipient. - /// @param amount The amount of ERC-20 assets to be transferred to the recipient. - /// @param merkleProof The proof of inclusion in the Merkle tree. - function claim(uint256 index, address recipient, uint128 amount, bytes32[] calldata merkleProof) external; } diff --git a/src/periphery/interfaces/ISablierMerkleLL.sol b/src/periphery/interfaces/ISablierMerkleLL.sol index b1a9e71a0..7058f487c 100644 --- a/src/periphery/interfaces/ISablierMerkleLL.sol +++ b/src/periphery/interfaces/ISablierMerkleLL.sol @@ -32,32 +32,4 @@ interface ISablierMerkleLL is ISablierMerkleBase { /// @notice The total streaming duration of each stream. function streamDurations() external view returns (uint40 cliff, uint40 duration); - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Makes the claim by creating a LockupLinear stream to the recipient. A stream NFT is minted to the - /// recipient. - /// - /// @dev Emits a {Claim} event. - /// - /// Requirements: - /// - The campaign must not have expired. - /// - The stream must not have been claimed already. - /// - The Merkle proof must be valid. - /// - /// @param index The index of the recipient in the Merkle tree. - /// @param recipient The address of the stream holder. - /// @param amount The amount of ERC-20 assets to be distributed via the claimed stream. - /// @param merkleProof The proof of inclusion in the Merkle tree. - /// @return streamId The id of the newly created stream. - function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof - ) - external - returns (uint256 streamId); } diff --git a/src/periphery/interfaces/ISablierMerkleLT.sol b/src/periphery/interfaces/ISablierMerkleLT.sol index 40648f14e..efb827cee 100644 --- a/src/periphery/interfaces/ISablierMerkleLT.sol +++ b/src/periphery/interfaces/ISablierMerkleLT.sol @@ -36,33 +36,4 @@ interface ISablierMerkleLT is ISablierMerkleBase { /// @notice Retrieves the tranches with their respective unlock percentages and durations. function getTranchesWithPercentages() external view returns (MerkleLT.TrancheWithPercentage[] memory); - - /*////////////////////////////////////////////////////////////////////////// - NON-CONSTANT FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - /// @notice Makes the claim by creating a LockupTranched stream to the recipient. A stream NFT is minted to the - /// recipient. - /// - /// @dev Emits a {Claim} event. - /// - /// Requirements: - /// - The campaign must not have expired. - /// - The stream must not have been claimed already. - /// - The Merkle proof must be valid. - /// - TOTAL_PERCENTAGE must be equal to 100%. - /// - /// @param index The index of the recipient in the Merkle tree. - /// @param recipient The address of the stream holder. - /// @param amount The amount of ERC-20 assets to be distributed via the claimed stream. - /// @param merkleProof The proof of inclusion in the Merkle tree. - /// @return streamId The id of the newly created stream. - function claim( - uint256 index, - address recipient, - uint128 amount, - bytes32[] calldata merkleProof - ) - external - returns (uint256 streamId); } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol index d0c784587..f4a8844e0 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol @@ -34,7 +34,9 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is uint128 totalAmount; } - function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) + function testFuzz_CreateWithDurations( + LockupDynamic.SegmentWithDuration[] memory segments + ) external whenNotDelegateCalled whenSegmentCountNotTooHigh diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index a02b469d4..9ca14875b 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -23,7 +23,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is CreateWithTimestamps_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_SegmentCountTooHigh(uint256 segmentCount) + function testFuzz_RevertWhen_SegmentCountTooHigh( + uint256 segmentCount + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -57,7 +59,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is createDefaultStreamWithSegments(segments); } - function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentTimestamp(uint40 firstTimestamp) + function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentTimestamp( + uint40 firstTimestamp + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -85,7 +89,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is createDefaultStreamWithSegments(segments); } - function testFuzz_RevertWhen_DepositAmountNotEqualToSegmentAmountsSum(uint128 depositDiff) + function testFuzz_RevertWhen_DepositAmountNotEqualToSegmentAmountsSum( + uint128 depositDiff + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -122,7 +128,9 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is lockupDynamic.createWithTimestamps(params); } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) + function testFuzz_RevertWhen_BrokerFeeTooHigh( + Broker memory broker + ) external whenNotDelegateCalled whenRecipientNonZeroAddress diff --git a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index b4c241bd3..14500ad29 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -40,7 +40,9 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is uint128 withdrawableAmount; } - function testFuzz_Withdraw_SegmentFuzing(Params memory params) + function testFuzz_Withdraw_SegmentFuzing( + Params memory params + ) external whenNotDelegateCalled givenNotNull diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol index e0235e110..6348dee1f 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol @@ -20,7 +20,9 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is CreateWithDurations_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_TotalDurationCalculationOverflows(LockupLinear.Durations memory durations) + function testFuzz_RevertWhen_TotalDurationCalculationOverflows( + LockupLinear.Durations memory durations + ) external whenNotDelegateCalled whenCliffDurationCalculationDoesNotOverflow @@ -46,7 +48,9 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is createDefaultStreamWithDurations(durations); } - function testFuzz_CreateWithDurations(LockupLinear.Durations memory durations) + function testFuzz_CreateWithDurations( + LockupLinear.Durations memory durations + ) external whenNotDelegateCalled whenCliffDurationCalculationDoesNotOverflow diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index 1e9aa108b..ac455fab8 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -22,7 +22,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is CreateWithTimestamps_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) + function testFuzz_RevertWhen_BrokerFeeTooHigh( + Broker memory broker + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -36,7 +38,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is createDefaultStreamWithBroker(broker); } - function testFuzz_RevertWhen_StartTimeNotLessThanCliffTime(uint40 startTime) + function testFuzz_RevertWhen_StartTimeNotLessThanCliffTime( + uint40 startTime + ) external whenNotDelegateCalled whenRecipientNonZeroAddress diff --git a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 40a02712d..836693a1f 100644 --- a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -22,7 +22,9 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is resetPrank({ msgSender: users.sender }); } - function testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40 timeJump) + function testFuzz_StreamedAmountOf_CliffTimeInTheFuture( + uint40 timeJump + ) external givenNotNull givenStreamHasNotBeenCanceled diff --git a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 68f2469bf..b1eca1701 100644 --- a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -19,7 +19,9 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is WithdrawableAmountOf_Integration_Shared_Test.setUp(); } - function testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40 timeJump) + function testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture( + uint40 timeJump + ) external givenNotNull givenStreamHasNotBeenCanceled diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol index a94710783..882221eaf 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol @@ -34,7 +34,9 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is uint128 totalAmount; } - function testFuzz_CreateWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) + function testFuzz_CreateWithDurations( + LockupTranched.TrancheWithDuration[] memory tranches + ) external whenNotDelegateCalled whenTrancheCountNotTooHigh diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index c4c8162c7..69329b70d 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -23,7 +23,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is CreateWithTimestamps_Integration_Shared_Test.setUp(); } - function testFuzz_RevertWhen_TrancheCountTooHigh(uint256 trancheCount) + function testFuzz_RevertWhen_TrancheCountTooHigh( + uint256 trancheCount + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -57,7 +59,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is createDefaultStreamWithTranches(tranches); } - function testFuzz_RevertWhen_StartTimeNotLessThanFirstTrancheTimestamp(uint40 firstTimestamp) + function testFuzz_RevertWhen_StartTimeNotLessThanFirstTrancheTimestamp( + uint40 firstTimestamp + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -85,7 +89,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is createDefaultStreamWithTranches(tranches); } - function testFuzz_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum(uint128 depositDiff) + function testFuzz_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum( + uint128 depositDiff + ) external whenNotDelegateCalled whenRecipientNonZeroAddress @@ -122,7 +128,9 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is lockupTranched.createWithTimestamps(params); } - function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) + function testFuzz_RevertWhen_BrokerFeeTooHigh( + Broker memory broker + ) external whenNotDelegateCalled whenRecipientNonZeroAddress diff --git a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 153062f3b..690ac522f 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -40,7 +40,9 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is uint128 withdrawableAmount; } - function testFuzz_Withdraw_TrancheFuzzing(Params memory params) + function testFuzz_Withdraw_TrancheFuzzing( + Params memory params + ) external whenNotDelegateCalled givenNotNull diff --git a/test/core/integration/fuzz/lockup/cancel.t.sol b/test/core/integration/fuzz/lockup/cancel.t.sol index 1208bcdbc..56955d408 100644 --- a/test/core/integration/fuzz/lockup/cancel.t.sol +++ b/test/core/integration/fuzz/lockup/cancel.t.sol @@ -11,7 +11,9 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test, Cancel_Integ Cancel_Integration_Shared_Test.setUp(); } - function testFuzz_Cancel_StatusPending(uint256 timeJump) + function testFuzz_Cancel_StatusPending( + uint256 timeJump + ) external whenNotDelegateCalled givenNotNull diff --git a/test/core/integration/fuzz/lockup/withdraw.t.sol b/test/core/integration/fuzz/lockup/withdraw.t.sol index 14835faff..6c7309bf7 100644 --- a/test/core/integration/fuzz/lockup/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup/withdraw.t.sol @@ -14,7 +14,9 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - Multiple caller addresses. - function testFuzz_Withdraw_UnknownCaller(address caller) + function testFuzz_Withdraw_UnknownCaller( + address caller + ) external whenNotDelegateCalled givenNotNull @@ -47,7 +49,9 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test, Withdraw_I /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - Multiple values for the withdrawal address. - function testFuzz_Withdraw_CallerApprovedOperator(address to) + function testFuzz_Withdraw_CallerApprovedOperator( + address to + ) external whenNotDelegateCalled givenNotNull diff --git a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol index 7df0dd617..12011fbd7 100644 --- a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol @@ -72,7 +72,9 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh } /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) + function createDefaultStreamWithDurations( + LockupDynamic.SegmentWithDuration[] memory segments + ) internal returns (uint256 streamId) { @@ -110,7 +112,9 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh } /// @dev Creates the default stream with the provided segments. - function createDefaultStreamWithSegments(LockupDynamic.Segment[] memory segments) + function createDefaultStreamWithSegments( + LockupDynamic.Segment[] memory segments + ) internal returns (uint256 streamId) { @@ -134,7 +138,9 @@ abstract contract LockupDynamic_Integration_Shared_Test is Lockup_Integration_Sh } /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupDynamic.Timestamps memory timestamps) + function createDefaultStreamWithTimestamps( + LockupDynamic.Timestamps memory timestamps + ) internal returns (uint256 streamId) { diff --git a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol index 8daeccb39..dd85e45fd 100644 --- a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol @@ -49,7 +49,9 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha } /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupLinear.Durations memory durations) + function createDefaultStreamWithDurations( + LockupLinear.Durations memory durations + ) internal returns (uint256 streamId) { @@ -101,7 +103,9 @@ abstract contract LockupLinear_Integration_Shared_Test is Lockup_Integration_Sha } /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupLinear.Timestamps memory timestamps) + function createDefaultStreamWithTimestamps( + LockupLinear.Timestamps memory timestamps + ) internal returns (uint256 streamId) { diff --git a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol index 5f18265c7..40c98197d 100644 --- a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol @@ -72,7 +72,9 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S } /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) + function createDefaultStreamWithDurations( + LockupTranched.TrancheWithDuration[] memory tranches + ) internal returns (uint256 streamId) { @@ -112,7 +114,9 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S } /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupTranched.Timestamps memory timestamps) + function createDefaultStreamWithTimestamps( + LockupTranched.Timestamps memory timestamps + ) internal returns (uint256 streamId) { @@ -130,7 +134,9 @@ abstract contract LockupTranched_Integration_Shared_Test is Lockup_Integration_S } /// @dev Creates the default stream with the provided tranches. - function createDefaultStreamWithTranches(LockupTranched.Tranche[] memory tranches) + function createDefaultStreamWithTranches( + LockupTranched.Tranche[] memory tranches + ) internal returns (uint256 streamId) { diff --git a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol index f899935e6..5344b628f 100644 --- a/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleInstant.t.sol @@ -155,9 +155,8 @@ abstract contract MerkleInstant_Fork_Test is Fork_Test { if (leaves.length == 1) { // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the // leaf is the root. - } else { - vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + else vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); expectCallToTransfer({ asset: FORK_ASSET, diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index 4ea124560..14ff7a764 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -32,7 +32,6 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { struct Vars { LockupLinear.StreamLL actualStream; - uint256 actualStreamId; uint256 aggregateAmount; uint128[] amounts; MerkleBase.ConstructorParams baseParams; @@ -167,18 +166,17 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { if (leaves.length == 1) { // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the // leaf is the root. - } else { - vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + else vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); - vars.actualStreamId = vars.merkleLL.claim({ + vars.merkleLL.claim({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], merkleProof: vars.merkleProof }); - vars.actualStream = lockupLinear.getStream(vars.actualStreamId); + vars.actualStream = lockupLinear.getStream(vars.expectedStreamId); vars.expectedStream = LockupLinear.StreamLL({ amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), asset: FORK_ASSET, @@ -195,7 +193,6 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { }); assertTrue(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort])); - assertEq(vars.actualStreamId, vars.expectedStreamId); assertEq(vars.actualStream, vars.expectedStream); /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 0283d5965..84c228825 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -32,7 +32,6 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { struct Vars { LockupTranched.StreamLT actualStream; - uint256 actualStreamId; LockupTranched.Tranche[] actualTranches; uint256 aggregateAmount; uint128[] amounts; @@ -168,18 +167,17 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { if (leaves.length == 1) { // If there is only one leaf, the Merkle proof should be an empty array as no proof is needed because the // leaf is the root. - } else { - vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); } + else vars.merkleProof = getProof(leaves.toBytes32(), vars.leafPos); - vars.actualStreamId = vars.merkleLT.claim({ + vars.merkleLT.claim({ index: vars.indexes[params.posBeforeSort], recipient: vars.recipients[params.posBeforeSort], amount: vars.amounts[params.posBeforeSort], merkleProof: vars.merkleProof }); - vars.actualStream = lockupTranched.getStream(vars.actualStreamId); + vars.actualStream = lockupTranched.getStream(vars.expectedStreamId); vars.expectedStream = LockupTranched.StreamLT({ amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), asset: FORK_ASSET, @@ -196,7 +194,6 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { }); assertTrue(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort])); - assertEq(vars.actualStreamId, vars.expectedStreamId); assertEq(vars.actualStream, vars.expectedStream); /*////////////////////////////////////////////////////////////////////////// diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 52f66f022..6a575f1a6 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -33,15 +33,6 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { MERKLE-INSTANT //////////////////////////////////////////////////////////////////////////*/ - function claimInstant() internal { - return merkleInstant.claim({ - index: defaults.INDEX1(), - recipient: users.recipient1, - amount: defaults.CLAIM_AMOUNT(), - merkleProof: defaults.index1Proof() - }); - } - function computeMerkleInstantAddress() internal view returns (address) { return computeMerkleInstantAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); } @@ -94,15 +85,6 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { MERKLE-LL //////////////////////////////////////////////////////////////////////////*/ - function claimLL() internal returns (uint256) { - return merkleLL.claim({ - index: defaults.INDEX1(), - recipient: users.recipient1, - amount: defaults.CLAIM_AMOUNT(), - merkleProof: defaults.index1Proof() - }); - } - function computeMerkleLLAddress() internal view returns (address) { return computeMerkleLLAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); } @@ -159,15 +141,6 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { MERKLE-LT //////////////////////////////////////////////////////////////////////////*/ - function claimLT() internal returns (uint256) { - return merkleLT.claim({ - index: defaults.INDEX1(), - recipient: users.recipient1, - amount: defaults.CLAIM_AMOUNT(), - merkleProof: defaults.index1Proof() - }); - } - function computeMerkleLTAddress() internal view returns (address) { return computeMerkleLTAddress(users.admin, defaults.MERKLE_ROOT(), defaults.EXPIRATION()); } diff --git a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol index 51e1fcd73..617617aff 100644 --- a/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/MerkleInstant.t.sol @@ -30,12 +30,6 @@ contract Clawback_MerkleLInstant_Integration_Test is Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - function setUp() public override(Clawback_Integration_Test, MerkleInstant_Integration_Shared_Test) { Clawback_Integration_Test.setUp(); MerkleInstant_Integration_Shared_Test.setUp(); @@ -46,12 +40,6 @@ contract GetFirstClaimTime_MerkleLInstant_Integration_Test is GetFirstClaimTime_Integration_Test, MerkleInstant_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleInstant_Integration_Shared_Test) { GetFirstClaimTime_Integration_Test.setUp(); MerkleInstant_Integration_Shared_Test.setUp(); @@ -62,12 +50,6 @@ contract HasClaimed_MerkleLInstant_Integration_Test is HasClaimed_Integration_Test, MerkleInstant_Integration_Shared_Test { - modifier givenRecipientHasClaimed() override { - // Make the first claim to set `_firstClaimTime`. - claimInstant(); - _; - } - function setUp() public override(HasClaimed_Integration_Test, MerkleInstant_Integration_Shared_Test) { HasClaimed_Integration_Test.setUp(); MerkleInstant_Integration_Shared_Test.setUp(); @@ -78,11 +60,6 @@ contract HasExpired_MerkleLInstant_Integration_Test is HasExpired_Integration_Test, MerkleInstant_Integration_Shared_Test { - modifier createMerkleCampaignWithZeroExpiry() override { - campaignWithZeroExpiry = ISablierMerkleBase(createMerkleInstant({ expiration: 0 })); - _; - } - function setUp() public override(HasExpired_Integration_Test, MerkleInstant_Integration_Shared_Test) { HasExpired_Integration_Test.setUp(); MerkleInstant_Integration_Shared_Test.setUp(); diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol index d4d1202d9..be0c04521 100644 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/instant/claim/claim.t.sol @@ -1,106 +1,21 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/periphery/libraries/Errors.sol"; +import { MerkleInstant_Integration_Shared_Test } from "../MerkleInstant.t.sol"; +import { Claim_Integration_Test } from "../../shared/claim/claim.t.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Claim_MerkleInstant_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertGiven_CampaignExpired() external { - uint40 expiration = defaults.EXPIRATION(); - uint256 warpTime = expiration + 1 seconds; - bytes32[] memory merkleProof; - vm.warp({ newTimestamp: warpTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); - merkleInstant.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); - } - - modifier givenCampaignNotExpired() { - _; - } - - function test_RevertGiven_AlreadyClaimed() external givenCampaignNotExpired { - claimInstant(); - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); - merkleInstant.claim(index1, users.recipient1, amount, merkleProof); - } - - modifier givenNotClaimed() { - _; - } - - modifier givenNotIncludedInMerkleTree() { - _; - } - - function test_RevertWhen_InvalidIndex() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 invalidIndex = 1337; - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleInstant.claim(invalidIndex, users.recipient1, amount, merkleProof); - } - - function test_RevertWhen_InvalidRecipient() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - address invalidRecipient = address(1337); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleInstant.claim(index1, invalidRecipient, amount, merkleProof); - } - - function test_RevertWhen_InvalidAmount() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 invalidAmount = 1337; - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleInstant.claim(index1, users.recipient1, invalidAmount, merkleProof); +contract Claim_MerkleInstant_Integration_Test is Claim_Integration_Test, MerkleInstant_Integration_Shared_Test { + function setUp() public override(Claim_Integration_Test, MerkleInstant_Integration_Shared_Test) { + super.setUp(); } - function test_RevertWhen_InvalidMerkleProof() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleInstant.claim(index1, users.recipient1, amount, invalidMerkleProof); - } - - modifier givenIncludedInMerkleTree() { - _; - } - - function test_Claim() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { - vm.expectEmit({ emitter: address(merkleInstant) }); + function test_ClaimInstant() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { + vm.expectEmit({ emitter: address(merkleBase) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT()); expectCallToTransfer({ to: users.recipient1, value: defaults.CLAIM_AMOUNT() }); + claim(); - claimInstant(); - - assertTrue(merkleInstant.hasClaimed(defaults.INDEX1()), "not claimed"); + assertTrue(merkleBase.hasClaimed(defaults.INDEX1()), "not claimed"); } } diff --git a/test/periphery/integration/merkle-campaign/instant/claim/claim.tree b/test/periphery/integration/merkle-campaign/instant/claim/claim.tree deleted file mode 100644 index 4085d6cc5..000000000 --- a/test/periphery/integration/merkle-campaign/instant/claim/claim.tree +++ /dev/null @@ -1,20 +0,0 @@ -claim.t.sol -├── given the campaign has expired -│ └── it should revert -└── given the campaign has not expired - ├── given the recipient has claimed - │ └── it should revert - └── given the recipient has not claimed - ├── given the claim is not included in the Merkle tree - │ ├── when the index is not valid - │ │ └── it should revert - │ ├── when the recipient address is not valid - │ │ └── it should revert - │ ├── when the amount is not valid - │ │ └── it should revert - │ └── when the Merkle proof is not valid - │ └── it should revert - └── given the claim is included in the Merkle tree - ├── it should mark the index as claimed - ├── it should transfer the claim amount to the recipient - └── it should emit a {Claim} event diff --git a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol index 7a06ee63c..24b5fac7a 100644 --- a/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/MerkleLL.t.sol @@ -27,12 +27,6 @@ abstract contract MerkleLL_Integration_Shared_Test is MerkleCampaign_Integration //////////////////////////////////////////////////////////////////////////*/ contract Clawback_MerkleLL_Integration_Test is Clawback_Integration_Test, MerkleLL_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - function setUp() public override(Clawback_Integration_Test, MerkleLL_Integration_Shared_Test) { Clawback_Integration_Test.setUp(); MerkleLL_Integration_Shared_Test.setUp(); @@ -43,12 +37,6 @@ contract GetFirstClaimTime_MerkleLL_Integration_Test is GetFirstClaimTime_Integration_Test, MerkleLL_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLL_Integration_Shared_Test) { GetFirstClaimTime_Integration_Test.setUp(); MerkleLL_Integration_Shared_Test.setUp(); @@ -56,12 +44,6 @@ contract GetFirstClaimTime_MerkleLL_Integration_Test is } contract HasClaimed_MerkleLL_Integration_Test is HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test { - modifier givenRecipientHasClaimed() override { - // Make the first claim to set `_firstClaimTime`. - claimLL(); - _; - } - function setUp() public override(HasClaimed_Integration_Test, MerkleLL_Integration_Shared_Test) { HasClaimed_Integration_Test.setUp(); MerkleLL_Integration_Shared_Test.setUp(); @@ -69,11 +51,6 @@ contract HasClaimed_MerkleLL_Integration_Test is HasClaimed_Integration_Test, Me } contract HasExpired_MerkleLL_Integration_Test is HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test { - modifier createMerkleCampaignWithZeroExpiry() override { - campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLL({ expiration: 0 })); - _; - } - function setUp() public override(HasExpired_Integration_Test, MerkleLL_Integration_Shared_Test) { HasExpired_Integration_Test.setUp(); MerkleLL_Integration_Shared_Test.setUp(); diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index 26d7d5b13..233b94f55 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -2,106 +2,23 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; +import { MerkleLL_Integration_Shared_Test } from "../MerkleLL.t.sol"; +import { Claim_Integration_Test } from "../../shared/claim/claim.t.sol"; -contract Claim_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { - function test_RevertGiven_CampaignExpired() external { - uint40 expiration = defaults.EXPIRATION(); - uint256 warpTime = expiration + 1 seconds; - bytes32[] memory merkleProof; - vm.warp({ newTimestamp: warpTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); - merkleLL.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); +contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Integration_Shared_Test { + function setUp() public override(Claim_Integration_Test, MerkleLL_Integration_Shared_Test) { + super.setUp(); } - modifier givenCampaignNotExpired() { - _; - } - - function test_RevertGiven_AlreadyClaimed() external givenCampaignNotExpired { - claimLL(); - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); - merkleLL.claim(index1, users.recipient1, amount, merkleProof); - } - - modifier givenNotClaimed() { - _; - } - - modifier givenNotIncludedInMerkleTree() { - _; - } - - function test_RevertWhen_InvalidIndex() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 invalidIndex = 1337; - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLL.claim(invalidIndex, users.recipient1, amount, merkleProof); - } - - function test_RevertWhen_InvalidRecipient() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - address invalidRecipient = address(1337); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLL.claim(index1, invalidRecipient, amount, merkleProof); - } - - function test_RevertWhen_InvalidAmount() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 invalidAmount = 1337; - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLL.claim(index1, users.recipient1, invalidAmount, merkleProof); - } - - function test_RevertWhen_InvalidMerkleProof() - external - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLL.claim(index1, users.recipient1, amount, invalidMerkleProof); - } - - modifier givenIncludedInMerkleTree() { - _; - } - - function test_Claim() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { + function test_ClaimLL() external givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { uint256 expectedStreamId = lockupLinear.nextStreamId(); vm.expectEmit({ emitter: address(merkleLL) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); - uint256 actualStreamId = claimLL(); + claim(); - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(actualStreamId); + LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(expectedStreamId); LockupLinear.StreamLL memory expectedStream = LockupLinear.StreamLL({ amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), asset: dai, @@ -117,8 +34,7 @@ contract Claim_MerkleLL_Integration_Test is MerkleCampaign_Integration_Test { wasCanceled: false }); - assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(actualStreamId, expectedStreamId, "invalid stream id"); assertEq(actualStream, expectedStream); + assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol index 92181fe9b..b9e042f8a 100644 --- a/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/MerkleLT.t.sol @@ -27,12 +27,6 @@ abstract contract MerkleLT_Integration_Shared_Test is MerkleCampaign_Integration //////////////////////////////////////////////////////////////////////////*/ contract Clawback_MerkleLT_Integration_Test is Clawback_Integration_Test, MerkleLT_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimLT(); - _; - } - function setUp() public override(Clawback_Integration_Test, MerkleLT_Integration_Shared_Test) { Clawback_Integration_Test.setUp(); MerkleLT_Integration_Shared_Test.setUp(); @@ -43,12 +37,6 @@ contract GetFirstClaimTime_MerkleLT_Integration_Test is GetFirstClaimTime_Integration_Test, MerkleLT_Integration_Shared_Test { - modifier afterFirstClaim() override { - // Make the first claim to set `_firstClaimTime`. - claimLT(); - _; - } - function setUp() public override(GetFirstClaimTime_Integration_Test, MerkleLT_Integration_Shared_Test) { GetFirstClaimTime_Integration_Test.setUp(); MerkleLT_Integration_Shared_Test.setUp(); @@ -56,12 +44,6 @@ contract GetFirstClaimTime_MerkleLT_Integration_Test is } contract HasClaimed_MerkleLT_Integration_Test is HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test { - modifier givenRecipientHasClaimed() override { - // Make the first claim to set `_firstClaimTime`. - claimLT(); - _; - } - function setUp() public override(HasClaimed_Integration_Test, MerkleLT_Integration_Shared_Test) { HasClaimed_Integration_Test.setUp(); MerkleLT_Integration_Shared_Test.setUp(); @@ -69,11 +51,6 @@ contract HasClaimed_MerkleLT_Integration_Test is HasClaimed_Integration_Test, Me } contract HasExpired_MerkleLT_Integration_Test is HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test { - modifier createMerkleCampaignWithZeroExpiry() override { - campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLT({ expiration: 0 })); - _; - } - function setUp() public override(HasExpired_Integration_Test, MerkleLT_Integration_Shared_Test) { HasExpired_Integration_Test.setUp(); MerkleLT_Integration_Shared_Test.setUp(); diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index 05285864a..d5008e0f6 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -1,21 +1,19 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; -import { MerkleBase, MerkleLT } from "src/periphery/types/DataTypes.sol"; +import { MerkleLT } from "src/periphery/types/DataTypes.sol"; -import { MerkleBuilder } from "test/utils/MerkleBuilder.sol"; -import { Merkle } from "test/utils/Murky.sol"; +import { Claim_Integration_Test } from "../../shared/claim/claim.t.sol"; +import { MerkleLT_Integration_Shared_Test } from "../MerkleLT.t.sol"; -import { MerkleCampaign_Integration_Test } from "../../MerkleCampaign.t.sol"; - -contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_Test { - using MerkleBuilder for uint256[]; +contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Integration_Shared_Test { + function setUp() public override(Claim_Integration_Test, MerkleLT_Integration_Shared_Test) { + super.setUp(); + } modifier whenTotalPercentageNotOneHundred() { _; @@ -23,29 +21,23 @@ contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_T function test_RevertWhen_TotalPercentageLessThanOneHundred() external whenTotalPercentageNotOneHundred { // Create a MerkleLT campaign with a total percentage less than 100. - MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); - bool cancelable = defaults.CANCELABLE(); - bool transferable = defaults.TRANSFERABLE(); - uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); - uint256 recipientCount = defaults.RECIPIENT_COUNT(); - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); tranchesWithPercentages[0].unlockPercentage = ud2x18(0.05e18); tranchesWithPercentages[1].unlockPercentage = ud2x18(0.2e18); - uint64 totalPercentage = - tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); - merkleLT = merkleFactory.createMerkleLT( - baseParams, + defaults.baseParams(), lockupTranched, - cancelable, - transferable, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), tranchesWithPercentages, - aggregateAmount, - recipientCount + defaults.AGGREGATE_AMOUNT(), + defaults.RECIPIENT_COUNT() ); + uint64 totalPercentage = + tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); + // Claim an airstream. bytes32[] memory merkleProof = defaults.index1Proof(); @@ -53,34 +45,28 @@ contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_T abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); - merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 10_000e18, merkleProof: merkleProof }); } function test_RevertWhen_TotalPercentageGreaterThanOneHundred() external whenTotalPercentageNotOneHundred { // Create a MerkleLT campaign with a total percentage less than 100. - MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); - bool cancelable = defaults.CANCELABLE(); - bool transferable = defaults.TRANSFERABLE(); - uint256 aggregateAmount = defaults.AGGREGATE_AMOUNT(); - uint256 recipientCount = defaults.RECIPIENT_COUNT(); - MerkleLT.TrancheWithPercentage[] memory tranchesWithPercentages = defaults.tranchesWithPercentages(); tranchesWithPercentages[0].unlockPercentage = ud2x18(0.75e18); tranchesWithPercentages[1].unlockPercentage = ud2x18(0.8e18); - uint64 totalPercentage = - tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); - merkleLT = merkleFactory.createMerkleLT( - baseParams, + defaults.baseParams(), lockupTranched, - cancelable, - transferable, + defaults.CANCELABLE(), + defaults.TRANSFERABLE(), tranchesWithPercentages, - aggregateAmount, - recipientCount + defaults.AGGREGATE_AMOUNT(), + defaults.RECIPIENT_COUNT() ); + uint64 totalPercentage = + tranchesWithPercentages[0].unlockPercentage.unwrap() + tranchesWithPercentages[1].unlockPercentage.unwrap(); + // Claim an airstream. bytes32[] memory merkleProof = defaults.index1Proof(); @@ -88,177 +74,20 @@ contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_T abi.encodeWithSelector(Errors.SablierMerkleLT_TotalPercentageNotOneHundred.selector, totalPercentage) ); - merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 10_000e18, merkleProof: merkleProof }); } modifier whenTotalPercentageOneHundred() { _; } - function test_RevertGiven_CampaignExpired() external whenTotalPercentageOneHundred { - uint40 expiration = defaults.EXPIRATION(); - uint256 warpTime = expiration + 1 seconds; - bytes32[] memory merkleProof; - vm.warp({ newTimestamp: warpTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); - merkleLT.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); - } - - modifier givenCampaignNotExpired() { - _; - } - - function test_RevertGiven_AlreadyClaimed() external whenTotalPercentageOneHundred givenCampaignNotExpired { - claimLT(); - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); - merkleLT.claim(index1, users.recipient1, amount, merkleProof); - } - - modifier givenNotClaimed() { - _; - } - - modifier givenNotIncludedInMerkleTree() { - _; - } - - function test_RevertWhen_InvalidIndex() - external - whenTotalPercentageOneHundred - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 invalidIndex = 1337; - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLT.claim(invalidIndex, users.recipient1, amount, merkleProof); - } - - function test_RevertWhen_InvalidRecipient() - external - whenTotalPercentageOneHundred - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - address invalidRecipient = address(1337); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLT.claim(index1, invalidRecipient, amount, merkleProof); - } - - function test_RevertWhen_InvalidAmount() - external - whenTotalPercentageOneHundred - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 invalidAmount = 1337; - bytes32[] memory merkleProof = defaults.index1Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLT.claim(index1, users.recipient1, invalidAmount, merkleProof); - } - - function test_RevertWhen_InvalidMerkleProof() - external - whenTotalPercentageOneHundred - givenCampaignNotExpired - givenNotClaimed - givenNotIncludedInMerkleTree - { - uint256 index1 = defaults.INDEX1(); - uint128 amount = defaults.CLAIM_AMOUNT(); - bytes32[] memory invalidMerkleProof = defaults.index2Proof(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); - merkleLT.claim(index1, users.recipient1, amount, invalidMerkleProof); - } - - modifier givenIncludedInMerkleTree() { - _; - } - - /// @dev Needed this variable in storage due to how the imported libraries work. - uint256[] public leaves = new uint256[](4); // same number of recipients as in Defaults - - function test_Claim_CalculatedAmountsSumNotEqualClaimAmount() - external - whenTotalPercentageOneHundred - givenCampaignNotExpired - givenNotClaimed - givenIncludedInMerkleTree - { - // Declare a claim amount that will cause a rounding error. - uint128 claimAmount = defaults.CLAIM_AMOUNT() + 1; - - // Compute the test Merkle tree. - leaves = defaults.getLeaves(); - uint256 leaf = MerkleBuilder.computeLeaf(defaults.INDEX1(), users.recipient1, claimAmount); - leaves[0] = leaf; - MerkleBuilder.sortLeaves(leaves); - - // Compute the test Merkle proof. - uint256 pos = Arrays.findUpperBound(leaves, leaf); - bytes32[] memory proof = getProof(leaves.toBytes32(), pos); - - /// Declare the constructor params. - MerkleBase.ConstructorParams memory baseParams = defaults.baseParams(); - baseParams.merkleRoot = getRoot(leaves.toBytes32()); - - // Deploy a test MerkleLT contract. - ISablierMerkleLT testMerkleLT = merkleFactory.createMerkleLT( - baseParams, - lockupTranched, - defaults.CANCELABLE(), - defaults.TRANSFERABLE(), - defaults.tranchesWithPercentages(), - defaults.AGGREGATE_AMOUNT(), - defaults.RECIPIENT_COUNT() - ); - - // Fund the MerkleLT contract. - deal({ token: address(dai), to: address(testMerkleLT), give: defaults.AGGREGATE_AMOUNT() }); - - uint256 expectedStreamId = lockupTranched.nextStreamId(); - vm.expectEmit({ emitter: address(testMerkleLT) }); - emit Claim(defaults.INDEX1(), users.recipient1, claimAmount, expectedStreamId); - - uint256 actualStreamId = testMerkleLT.claim(defaults.INDEX1(), users.recipient1, claimAmount, proof); - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(actualStreamId); - LockupTranched.StreamLT memory expectedStream = LockupTranched.StreamLT({ - amounts: Lockup.Amounts({ deposited: claimAmount, refunded: 0, withdrawn: 0 }), - asset: dai, - endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), - isCancelable: defaults.CANCELABLE(), - isDepleted: false, - isStream: true, - isTransferable: defaults.TRANSFERABLE(), - recipient: users.recipient1, - sender: users.admin, - startTime: getBlockTimestamp(), - tranches: defaults.tranchesMerkleLT(claimAmount), - wasCanceled: false - }); - - assertTrue(testMerkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(actualStreamId, expectedStreamId, "invalid stream id"); - assertEq(actualStream, expectedStream); - } - modifier whenCalculatedAmountsSumEqualsClaimAmount() { _; } function test_Claim() external + override whenTotalPercentageOneHundred givenCampaignNotExpired givenNotClaimed @@ -269,8 +98,8 @@ contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_T vm.expectEmit({ emitter: address(merkleLT) }); emit Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); - uint256 actualStreamId = claimLT(); - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(actualStreamId); + claim(); + LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(expectedStreamId); LockupTranched.StreamLT memory expectedStream = LockupTranched.StreamLT({ amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), asset: dai, @@ -286,8 +115,7 @@ contract Claim_MerkleLT_Integration_Test is Merkle, MerkleCampaign_Integration_T wasCanceled: false }); - assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); - assertEq(actualStreamId, expectedStreamId, "invalid stream id"); assertEq(actualStream, expectedStream); + assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); } } diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.tree b/test/periphery/integration/merkle-campaign/lt/claim/claim.tree index ab986c299..8a316f6fe 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.tree +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.tree @@ -1,33 +1,9 @@ claim.t.sol -. ├── when the total percentage does not equal 100% │ ├── when the total percentage is less than 100% │ │ └── it should revert │ └── when the total percentage is greater than 100% │ └── it should revert └── when the total percentage equals 100% - ├── given the campaign has expired - │ └── it should revert - └── given the campaign has not expired - ├── given the recipient has claimed - │ └── it should revert - └── given the recipient has not claimed - ├── given the claim is not included in the Merkle tree - │ ├── when the index is not valid - │ │ └── it should revert - │ ├── when the recipient address is not valid - │ │ └── it should revert - │ ├── when the amount is not valid - │ │ └── it should revert - │ └── when the Merkle proof is not valid - │ └── it should revert - └── given the claim is included in the Merkle tree - ├── when the sum of the calculated amounts does not equal the claim amount - │ ├── it should adjust the last tranche amount - │ ├── it should mark the index as claimed - │ ├── it should create a stream - │ └── it should emit a {Claim} event - └── when the sum of the calculated amounts equals the claim amount - ├── it should mark the index as claimed - ├── it should create a stream - └── it should emit a {Claim} event + ├── it should create a stream + └── it should emit a {Claim} event \ No newline at end of file diff --git a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol index 24684a6e8..9b16e88e4 100644 --- a/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/MerkleCampaign.t.sol @@ -15,15 +15,25 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ } /*////////////////////////////////////////////////////////////////////////// - MODIFIERS + HELPERS //////////////////////////////////////////////////////////////////////////*/ - /// @dev A shared modifier meant to be overridden by the implementing test contracts. - modifier afterFirstClaim() virtual { - _; + function claim() internal { + merkleBase.claim({ + index: defaults.INDEX1(), + recipient: users.recipient1, + amount: defaults.CLAIM_AMOUNT(), + merkleProof: defaults.index1Proof() + }); } - modifier createMerkleCampaignWithZeroExpiry() virtual { + /*////////////////////////////////////////////////////////////////////////// + MODIFIERS + //////////////////////////////////////////////////////////////////////////*/ + + modifier afterFirstClaim() { + // Make the first claim to set `_firstClaimTime`. + claim(); _; } @@ -32,11 +42,29 @@ abstract contract MerkleCampaign_Integration_Shared_Test is MerkleCampaign_Integ _; } + modifier givenCampaignNotExpired() { + _; + } + modifier givenExpirationNotZero() { _; } - modifier givenRecipientHasClaimed() virtual { + modifier givenIncludedInMerkleTree() { + _; + } + + modifier givenNotClaimed() { + _; + } + + modifier givenNotIncludedInMerkleTree() { + _; + } + + modifier givenRecipientHasClaimed() { + // Make the first claim to set `_firstClaimTime`. + claim(); _; } diff --git a/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol new file mode 100644 index 000000000..214ca8002 --- /dev/null +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.t.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { Errors } from "src/periphery/libraries/Errors.sol"; + +import { MerkleCampaign_Integration_Shared_Test } from "../MerkleCampaign.t.sol"; + +abstract contract Claim_Integration_Test is MerkleCampaign_Integration_Shared_Test { + function setUp() public virtual override { + MerkleCampaign_Integration_Shared_Test.setUp(); + } + + function test_RevertGiven_CampaignExpired() external { + uint40 expiration = defaults.EXPIRATION(); + uint256 warpTime = expiration + 1 seconds; + bytes32[] memory merkleProof; + vm.warp({ newTimestamp: warpTime }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_CampaignExpired.selector, warpTime, expiration)); + merkleBase.claim({ index: 1, recipient: users.recipient1, amount: 1, merkleProof: merkleProof }); + } + + function test_RevertGiven_AlreadyClaimed() external givenCampaignNotExpired { + claim(); + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_StreamClaimed.selector, index1)); + merkleBase.claim(index1, users.recipient1, amount, merkleProof); + } + + function test_RevertWhen_InvalidIndex() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 invalidIndex = 1337; + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleBase.claim(invalidIndex, users.recipient1, amount, merkleProof); + } + + function test_RevertWhen_InvalidRecipient() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + address invalidRecipient = address(1337); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleBase.claim(index1, invalidRecipient, amount, merkleProof); + } + + function test_RevertWhen_InvalidAmount() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 invalidAmount = 1337; + bytes32[] memory merkleProof = defaults.index1Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleBase.claim(index1, users.recipient1, invalidAmount, merkleProof); + } + + function test_RevertWhen_InvalidMerkleProof() + external + givenCampaignNotExpired + givenNotClaimed + givenNotIncludedInMerkleTree + { + uint256 index1 = defaults.INDEX1(); + uint128 amount = defaults.CLAIM_AMOUNT(); + bytes32[] memory invalidMerkleProof = defaults.index2Proof(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierMerkleBase_InvalidProof.selector)); + merkleBase.claim(index1, users.recipient1, amount, invalidMerkleProof); + } + + /// @dev Since the implementation of `_claim()` differs in each Merkle campaign, we declare this test as virtual and + /// will be overridden in the Child contracts. + function test_Claim() external virtual givenCampaignNotExpired givenNotClaimed givenIncludedInMerkleTree { + // The child contract must check that the claim event is emitted. + // It should also mark the index as claimed. + } +} diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.tree b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree similarity index 83% rename from test/periphery/integration/merkle-campaign/ll/claim/claim.tree rename to test/periphery/integration/merkle-campaign/shared/claim/claim.tree index b61221784..e5e62fb43 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.tree +++ b/test/periphery/integration/merkle-campaign/shared/claim/claim.tree @@ -15,6 +15,5 @@ claim.t.sol │ └── when the Merkle proof is not valid │ └── it should revert └── given the claim is included in the Merkle tree - ├── it should mark the index as claimed - ├── it should create a stream - └── it should emit a {Claim} event + ├── it should mark the index as Claimed + └── it should emit {Claim} event diff --git a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol index 64d4ba322..b92ebb236 100644 --- a/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/clawback/clawback.t.sol @@ -42,7 +42,9 @@ abstract contract Clawback_Integration_Test is MerkleCampaign_Integration_Shared test_Clawback(users.admin); } - function testFuzz_Clawback(address to) + function testFuzz_Clawback( + address to + ) external whenCallerAdmin afterFirstClaim diff --git a/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol index 332eeaced..32cf37752 100644 --- a/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/get-first-claim-time/getFirstClaimTime.t.sol @@ -13,7 +13,7 @@ abstract contract GetFirstClaimTime_Integration_Test is MerkleCampaign_Integrati assertEq(firstClaimTime, 0); } - function test_GetFirstClaimTime() external view afterFirstClaim { + function test_GetFirstClaimTime() external afterFirstClaim { uint256 firstClaimTime = merkleBase.getFirstClaimTime(); assertEq(firstClaimTime, getBlockTimestamp()); } diff --git a/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol index c7480442b..e7ad4034b 100644 --- a/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol +++ b/test/periphery/integration/merkle-campaign/shared/has-expired/hasExpired.t.sol @@ -10,9 +10,8 @@ abstract contract HasExpired_Integration_Test is MerkleCampaign_Integration_Shar MerkleCampaign_Integration_Shared_Test.setUp(); } - ISablierMerkleBase internal campaignWithZeroExpiry; - - function test_HasExpired_ExpirationZero() external view createMerkleCampaignWithZeroExpiry { + function test_HasExpired_ExpirationZero() external { + ISablierMerkleBase campaignWithZeroExpiry = ISablierMerkleBase(createMerkleLT({ expiration: 0 })); assertFalse(campaignWithZeroExpiry.hasExpired(), "campaign expired"); } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 6eab6972f..d1f5e2619 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -403,7 +403,9 @@ contract Defaults is Constants, Merkle { } /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLD} parameters. - function batchCreateWithTimestampsLD(uint256 batchSize) + function batchCreateWithTimestampsLD( + uint256 batchSize + ) public view returns (BatchLockup.CreateWithTimestampsLD[] memory batch) @@ -417,7 +419,9 @@ contract Defaults is Constants, Merkle { } /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLL} parameters. - function batchCreateWithTimestampsLL(uint256 batchSize) + function batchCreateWithTimestampsLL( + uint256 batchSize + ) public view returns (BatchLockup.CreateWithTimestampsLL[] memory batch) @@ -431,7 +435,9 @@ contract Defaults is Constants, Merkle { } /// @dev Returns a batch of {BatchLockup.CreateWithTimestampsLL} parameters. - function batchCreateWithTimestampsLT(uint256 batchSize) + function batchCreateWithTimestampsLT( + uint256 batchSize + ) public view returns (BatchLockup.CreateWithTimestampsLT[] memory batch) diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index ae29abb3a..6a09e4b8a 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -24,7 +24,9 @@ abstract contract Utils is CommonBase, PRBMathUtils { } /// @dev Turns the segments with durations into canonical segments, which have timestamps. - function getSegmentsWithTimestamps(LockupDynamic.SegmentWithDuration[] memory segments) + function getSegmentsWithTimestamps( + LockupDynamic.SegmentWithDuration[] memory segments + ) internal view returns (LockupDynamic.Segment[] memory segmentsWithTimestamps) @@ -47,7 +49,9 @@ abstract contract Utils is CommonBase, PRBMathUtils { } /// @dev Turns the tranches with durations into canonical tranches, which have timestamps. - function getTranchesWithTimestamps(LockupTranched.TrancheWithDuration[] memory tranches) + function getTranchesWithTimestamps( + LockupTranched.TrancheWithDuration[] memory tranches + ) internal view returns (LockupTranched.Tranche[] memory tranchesWithTimestamps) From b1b31025b9cc8def66795a09201e6b585ab85300 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 14 Aug 2024 17:26:45 +0300 Subject: [PATCH 18/34] chore: order alphabetically scripts in package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index d6165fad3..bc9973c2e 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "test": "forge test", "test:core": "FOUNDRY_PROFILE=lite forge test --match-path \"test/core/**/*.sol\" --nmt \"testFork\"", "test:lite": "FOUNDRY_PROFILE=lite forge test", - "test:periphery": "FOUNDRY_PROFILE=lite forge test --match-path \"test/periphery/**/*.sol\" --nmt \"testFork\"", - "test:optimized": "bun run build:optimized && FOUNDRY_PROFILE=test-optimized forge test" + "test:optimized": "bun run build:optimized && FOUNDRY_PROFILE=test-optimized forge test", + "test:periphery": "FOUNDRY_PROFILE=lite forge test --match-path \"test/periphery/**/*.sol\" --nmt \"testFork\"" } } From ca68897ef8ef807d1a568e167c1045c75b5f427f Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Wed, 14 Aug 2024 22:41:16 +0530 Subject: [PATCH 19/34] feat: allow end time to be in the past (#1015) * feat: allow end time to be in the past * test(fork): check isSettled value prior to assertions --- src/core/interfaces/ISablierLockupDynamic.sol | 1 - src/core/interfaces/ISablierLockupLinear.sol | 1 - .../interfaces/ISablierLockupTranched.sol | 1 - src/core/libraries/Errors.sol | 3 -- src/core/libraries/Helpers.sol | 32 +++----------- test/core/fork/LockupDynamic.t.sol | 5 ++- test/core/fork/LockupLinear.t.sol | 21 ++++++--- test/core/fork/LockupTranched.t.sol | 5 ++- .../createWithTimestamps.t.sol | 23 ---------- .../createWithTimestamps.tree | 43 +++++++++---------- .../createWithTimestamps.t.sol | 21 --------- .../createWithTimestamps.tree | 39 ++++++++--------- .../createWithTimestamps.t.sol | 23 ---------- .../createWithTimestamps.tree | 43 +++++++++---------- .../lockup-dynamic/createWithTimestamps.t.sol | 3 -- .../lockup-linear/createWithTimestamps.t.sol | 1 - .../createWithTimestamps.t.sol | 3 -- .../shared/lockup/createWithTimestamps.t.sol | 4 -- .../handlers/LockupLinearCreateHandler.sol | 4 +- test/utils/Fuzzers.sol | 12 ++---- test/utils/Utils.sol | 5 +-- 21 files changed, 92 insertions(+), 201 deletions(-) diff --git a/src/core/interfaces/ISablierLockupDynamic.sol b/src/core/interfaces/ISablierLockupDynamic.sol index 1ad989e45..9442302b5 100644 --- a/src/core/interfaces/ISablierLockupDynamic.sol +++ b/src/core/interfaces/ISablierLockupDynamic.sol @@ -102,7 +102,6 @@ interface ISablierLockupDynamic is ISablierLockup { /// - `params.startTime` must be greater than zero and less than the first segment's timestamp. /// - `params.segments` must have at least one segment, but not more than `MAX_SEGMENT_COUNT`. /// - The segment timestamps must be arranged in ascending order. - /// - The last segment timestamp (i.e. the stream's end time) must be in the future. /// - The sum of the segment amounts must equal the deposit amount. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. diff --git a/src/core/interfaces/ISablierLockupLinear.sol b/src/core/interfaces/ISablierLockupLinear.sol index 978de2de9..05abed09d 100644 --- a/src/core/interfaces/ISablierLockupLinear.sol +++ b/src/core/interfaces/ISablierLockupLinear.sol @@ -98,7 +98,6 @@ interface ISablierLockupLinear is ISablierLockup { /// - `params.timestamps.start` must be greater than zero and less than `params.timestamps.end`. /// - If set, `params.timestamps.cliff` must be greater than `params.timestamps.start` and less than /// `params.timestamps.end`. - /// - `params.timestamps.end` must be in the future. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. /// diff --git a/src/core/interfaces/ISablierLockupTranched.sol b/src/core/interfaces/ISablierLockupTranched.sol index b9f58a5e8..966ff57ed 100644 --- a/src/core/interfaces/ISablierLockupTranched.sol +++ b/src/core/interfaces/ISablierLockupTranched.sol @@ -102,7 +102,6 @@ interface ISablierLockupTranched is ISablierLockup { /// - `params.startTime` must be greater than zero and less than the first tranche's timestamp. /// - `params.tranches` must have at least one tranche, but not more than `MAX_TRANCHE_COUNT`. /// - The tranche timestamps must be arranged in ascending order. - /// - The last tranche timestamp (i.e. the stream's end time) must be in the future. /// - The sum of the tranche amounts must equal the deposit amount. /// - `params.recipient` must not be the zero address. /// - `msg.sender` must have allowed this contract to spend at least `params.totalAmount` assets. diff --git a/src/core/libraries/Errors.sol b/src/core/libraries/Errors.sol index b329ecdbf..902228cae 100644 --- a/src/core/libraries/Errors.sol +++ b/src/core/libraries/Errors.sol @@ -40,9 +40,6 @@ library Errors { /// @notice Thrown when trying to create a stream with a zero deposit amount. error SablierLockup_DepositAmountZero(); - /// @notice Thrown when trying to create a stream with an end time not in the future. - error SablierLockup_EndTimeNotInTheFuture(uint40 blockTimestamp, uint40 endTime); - /// @notice Thrown when the hook does not return the correct selector. error SablierLockup_InvalidHookSelector(address recipient); diff --git a/src/core/libraries/Helpers.sol b/src/core/libraries/Helpers.sol index 33899e984..16e73d178 100644 --- a/src/core/libraries/Helpers.sol +++ b/src/core/libraries/Helpers.sol @@ -119,7 +119,7 @@ library Helpers { uint40 startTime ) internal - view + pure { // Check: the deposit amount is not zero. if (depositAmount == 0) { @@ -147,7 +147,7 @@ library Helpers { } /// @dev Checks the parameters of the {SablierLockupLinear-_create} function. - function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Timestamps memory timestamps) internal view { + function checkCreateLockupLinear(uint128 depositAmount, LockupLinear.Timestamps memory timestamps) internal pure { // Check: the deposit amount is not zero. if (depositAmount == 0) { revert Errors.SablierLockup_DepositAmountZero(); @@ -175,12 +175,6 @@ library Helpers { if (timestamps.start >= timestamps.end) { revert Errors.SablierLockupLinear_StartTimeNotLessThanEndTime(timestamps.start, timestamps.end); } - - // Check: the end time is in the future. - uint40 blockTimestamp = uint40(block.timestamp); - if (blockTimestamp >= timestamps.end) { - revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, timestamps.end); - } } /// @dev Checks the parameters of the {SablierLockupTranched-_create} function. @@ -191,7 +185,7 @@ library Helpers { uint40 startTime ) internal - view + pure { // Check: the deposit amount is not zero. if (depositAmount == 0) { @@ -234,7 +228,7 @@ library Helpers { uint40 startTime ) private - view + pure { // Check: the start time is strictly less than the first segment timestamp. if (startTime >= segments[0].timestamp) { @@ -269,14 +263,6 @@ library Helpers { previousSegmentTimestamp = currentSegmentTimestamp; } - // Check: the last timestamp is in the future. - // When the loop exits, the current segment's timestamp is the last segment's timestamp, i.e. the stream's end - // time. The variable is not renamed for gas efficiency purposes. - uint40 blockTimestamp = uint40(block.timestamp); - if (blockTimestamp >= currentSegmentTimestamp) { - revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, currentSegmentTimestamp); - } - // Check: the deposit amount is equal to the segment amounts sum. if (depositAmount != segmentAmountsSum) { revert Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum( @@ -297,7 +283,7 @@ library Helpers { uint40 startTime ) private - view + pure { // Check: the start time is strictly less than the first tranche timestamp. if (startTime >= tranches[0].timestamp) { @@ -332,14 +318,6 @@ library Helpers { previousTrancheTimestamp = currentTrancheTimestamp; } - // Check: the last timestamp is in the future. - // When the loop exits, the current tranche's timestamp is the last tranche's timestamp, i.e. the stream's end - // time. The variable is not renamed for gas efficiency purposes. - uint40 blockTimestamp = uint40(block.timestamp); - if (blockTimestamp >= currentTrancheTimestamp) { - revert Errors.SablierLockup_EndTimeNotInTheFuture(blockTimestamp, currentTrancheTimestamp); - } - // Check: the deposit amount is equal to the tranche amounts sum. if (depositAmount != trancheAmountsSum) { revert Errors.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum( diff --git a/test/core/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol index 27a306c61..42dbbae0d 100644 --- a/test/core/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -177,8 +177,9 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { ); // Check if the stream is settled. It is possible for a Lockup Dynamic stream to settle at the time of creation - // because some segment amounts can be zero. - vars.isSettled = lockupDynamic.refundableAmountOf(vars.streamId) == 0; + // because some segment amounts can be zero or the last segment timestamp can be in the past. + vars.isSettled = + lockupDynamic.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. diff --git a/test/core/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol index 21d517311..403ce7cdc 100644 --- a/test/core/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -61,6 +61,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { bool hasCliff; uint256 initialLockupLinearBalance; uint256 initialRecipientBalance; + bool isCancelable; bool isDepleted; bool isSettled; uint256 streamId; @@ -128,8 +129,8 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks ); } - // Bound the end time so that it is always greater than the block timestamp, the start time, and the cliff time. - vars.endTimeLowerBound = maxOfThree(params.timestamps.start, params.timestamps.cliff, vars.blockTimestamp); + // Bound the end time so that it is always greater than the start time, and the cliff time. + vars.endTimeLowerBound = maxOfTwo(params.timestamps.start, params.timestamps.cliff); params.timestamps.end = boundUint40(params.timestamps.end, vars.endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); @@ -183,13 +184,18 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { }) ); + // Check if the stream is settled. It is possible for a Lockup Linear stream to settle at the time of creation + // in case end time is in the past. + vars.isSettled = params.timestamps.end <= vars.blockTimestamp; + vars.isCancelable = vars.isSettled ? false : true; + // Assert that the stream has been created. LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(vars.streamId); assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); assertEq(actualStream.asset, FORK_ASSET, "asset"); assertEq(actualStream.cliffTime, params.timestamps.cliff, "cliffTime"); assertEq(actualStream.endTime, params.timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, true, "isCancelable"); + assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); assertEq(actualStream.isDepleted, false, "isDepleted"); assertEq(actualStream.isStream, true, "isStream"); assertEq(actualStream.isTransferable, true, "isTransferable"); @@ -200,8 +206,13 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Assert that the stream's status is correct. vars.actualStatus = lockupLinear.statusOf(vars.streamId); - vars.expectedStatus = - params.timestamps.start > vars.blockTimestamp ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + if (params.timestamps.end <= vars.blockTimestamp) { + vars.expectedStatus = Lockup.Status.SETTLED; + } else if (params.timestamps.start > vars.blockTimestamp) { + vars.expectedStatus = Lockup.Status.PENDING; + } else { + vars.expectedStatus = Lockup.Status.STREAMING; + } assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); // Assert that the next stream ID has been bumped. diff --git a/test/core/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol index 377a97374..38efc5d3c 100644 --- a/test/core/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -177,8 +177,9 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { ); // Check if the stream is settled. It is possible for a Lockup Tranched stream to settle at the time of creation - // because some tranche amounts can be zero. - vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + // because some tranche amounts can be zero or the last tranche timestamp can be in the past + vars.isSettled = + lockupTranched.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol index 4382ccc25..cae6e65d8 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol @@ -184,24 +184,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is createDefaultStreamWithSegments(segments); } - function test_RevertGiven_EndTimeNotInTheFuture() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenSegmentCountNotZero - whenSegmentCountNotTooHigh - whenSegmentAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstSegmentTimestamp - whenSegmentTimestampsOrdered - { - uint40 endTime = defaults.END_TIME(); - vm.warp({ newTimestamp: endTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); - createDefaultStream(); - } - function test_RevertWhen_DepositAmountNotEqualToSegmentAmountsSum() external whenNotDelegateCalled @@ -213,7 +195,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture { resetPrank({ msgSender: users.sender }); @@ -249,7 +230,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); @@ -270,7 +250,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum whenBrokerFeeNotTooHigh { @@ -294,7 +273,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum whenBrokerFeeNotTooHigh whenAssetContract @@ -313,7 +291,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum whenBrokerFeeNotTooHigh whenAssetContract diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree index 8105493e3..84c9ab25e 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree @@ -28,29 +28,26 @@ createWithTimestamps.t.sol ├── when the segment timestamps are not ordered │ └── it should revert └── when the segment timestamps are ordered - ├── when the end time is not in the future + ├── when the deposit amount is not equal to the segment amounts sum │ └── it should revert - └── when the end time is in the future - ├── when the deposit amount is not equal to the segment amounts sum + └── when the deposit amount is equal to the segment amounts sum + ├── when the broker fee is too high │ └── it should revert - └── when the deposit amount is equal to the segment amounts sum - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupDynamicStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupDynamicStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupDynamicStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupDynamicStream} event diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol index ca6103c7f..f017d6b2d 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol @@ -143,23 +143,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } - function test_RevertGiven_EndTimeNotInTheFuture() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeGreaterThanZero - whenStartTimeLessThanEndTime - whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture - { - uint40 endTime = defaults.END_TIME(); - vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); - createDefaultStream(); - } - function test_RevertWhen_BrokerFeeTooHigh() external whenNotDelegateCalled @@ -169,7 +152,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenCliffTimeGreaterThanZero whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); vm.expectRevert( @@ -187,7 +169,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenCliffTimeGreaterThanZero whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture whenBrokerFeeNotTooHigh { address nonContract = address(8128); @@ -204,7 +185,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenCliffTimeGreaterThanZero whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture whenBrokerFeeNotTooHigh whenAssetContract { @@ -219,7 +199,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is whenCliffTimeGreaterThanZero whenStartTimeLessThanEndTime whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree index 6729ea211..5f77ea69a 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree @@ -23,26 +23,23 @@ createWithTimestamps.t.sol ├── when the cliff time is not less than the end time │ └── it should revert └── when the cliff time is less than the end time - ├── when the end time is not in the future + ├── when the broker fee is too high │ └── it should revert - └── when the end time is in the future - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupLinearStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupLinearStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupLinearStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupLinearStream} event diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol index 5e0ddddd0..e3da16224 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol @@ -184,24 +184,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is createDefaultStreamWithTranches(tranches); } - function test_RevertGiven_EndTimeNotInTheFuture() - external - whenNotDelegateCalled - whenRecipientNonZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotTooHigh - whenTrancheAmountsSumDoesNotOverflow - whenStartTimeLessThanFirstTrancheTimestamp - whenTrancheTimestampsOrdered - { - uint40 endTime = defaults.END_TIME(); - vm.warp({ newTimestamp: endTime }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_EndTimeNotInTheFuture.selector, endTime, endTime)); - createDefaultStream(); - } - function test_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum() external whenNotDelegateCalled @@ -213,7 +195,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture { resetPrank({ msgSender: users.sender }); @@ -249,7 +230,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum { UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); @@ -270,7 +250,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum whenBrokerFeeNotTooHigh { @@ -294,7 +273,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum whenBrokerFeeNotTooHigh whenAssetContract @@ -313,7 +291,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum whenBrokerFeeNotTooHigh whenAssetContract diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree index 3c4205768..508e55c10 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -28,29 +28,26 @@ createWithTimestamps.t.sol ├── when the tranche timestamps are not ordered │ └── it should revert └── when the tranche timestamps are ordered - ├── when the end time is not in the future + ├── when the deposit amount is not equal to the tranche amounts sum │ └── it should revert - └── when the end time is in the future - ├── when the deposit amount is not equal to the tranche amounts sum + └── when the deposit amount is equal to the tranche amounts sum + ├── when the broker fee is too high │ └── it should revert - └── when the deposit amount is equal to the tranche amounts sum - ├── when the broker fee is too high + └── when the broker fee is not too high + ├── when the asset is not a contract │ └── it should revert - └── when the broker fee is not too high - ├── when the asset is not a contract - │ └── it should revert - └── when the asset is a contract - ├── when the asset misses the ERC-20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit a {MetadataUpdate} event - │ ├── it should perform the ERC-20 transfers - │ └── it should emit a {CreateLockupTranchedStream} event - └── when the asset does not miss the ERC-20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit a {MetadataUpdate} event - ├── it should perform the ERC-20 transfers - └── it should emit a {CreateLockupTranchedStream} event + └── when the asset is a contract + ├── when the asset misses the ERC-20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit a {MetadataUpdate} event + │ ├── it should perform the ERC-20 transfers + │ └── it should emit a {CreateLockupTranchedStream} event + └── when the asset does not miss the ERC-20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit a {MetadataUpdate} event + ├── it should perform the ERC-20 transfers + └── it should emit a {CreateLockupTranchedStream} event diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol index 9ca14875b..a943545e3 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol @@ -101,7 +101,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); @@ -140,7 +139,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum { vm.assume(broker.account != address(0)); @@ -188,7 +186,6 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is whenSegmentAmountsSumDoesNotOverflow whenStartTimeLessThanFirstSegmentTimestamp whenSegmentTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToSegmentAmountsSum whenBrokerFeeNotTooHigh whenAssetContract diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol index ac455fab8..9f2c240fb 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol @@ -105,7 +105,6 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is whenDepositAmountNotZero whenStartTimeNotZero whenCliffTimeLessThanEndTime - whenEndTimeInTheFuture whenBrokerFeeNotTooHigh whenAssetContract whenAssetERC20 diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol index 69329b70d..27b3a2730 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol @@ -101,7 +101,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture { depositDiff = boundUint128(depositDiff, 100, defaults.TOTAL_AMOUNT()); @@ -140,7 +139,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum { vm.assume(broker.account != address(0)); @@ -188,7 +186,6 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is whenTrancheAmountsSumDoesNotOverflow whenStartTimeLessThanFirstTrancheTimestamp whenTrancheTimestampsOrdered - whenEndTimeInTheFuture whenDepositAmountEqualToTrancheAmountsSum whenBrokerFeeNotTooHigh whenAssetContract diff --git a/test/core/integration/shared/lockup/createWithTimestamps.t.sol b/test/core/integration/shared/lockup/createWithTimestamps.t.sol index 252104613..3e181ef1e 100644 --- a/test/core/integration/shared/lockup/createWithTimestamps.t.sol +++ b/test/core/integration/shared/lockup/createWithTimestamps.t.sol @@ -46,10 +46,6 @@ abstract contract CreateWithTimestamps_Integration_Shared_Test is Lockup_Integra _; } - modifier whenEndTimeInTheFuture() { - _; - } - modifier whenNotDelegateCalled() { _; } diff --git a/test/core/invariant/handlers/LockupLinearCreateHandler.sol b/test/core/invariant/handlers/LockupLinearCreateHandler.sol index 09c383814..a3c302262 100644 --- a/test/core/invariant/handlers/LockupLinearCreateHandler.sol +++ b/test/core/invariant/handlers/LockupLinearCreateHandler.sol @@ -95,8 +95,8 @@ contract LockupLinearCreateHandler is BaseHandler { ); } - // Bound the end time so that it is always greater than the start time, the cliff time, and the block timestamp. - uint40 endTimeLowerBound = maxOfThree(params.timestamps.start, params.timestamps.cliff, blockTimestamp); + // Bound the end time so that it is always greater than the start time, and the cliff time. + uint40 endTimeLowerBound = maxOfTwo(params.timestamps.start, params.timestamps.cliff); params.timestamps.end = boundUint40(params.timestamps.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Mint enough assets to the Sender. diff --git a/test/utils/Fuzzers.sol b/test/utils/Fuzzers.sol index 17959ce37..3b2f30c9e 100644 --- a/test/utils/Fuzzers.sol +++ b/test/utils/Fuzzers.sol @@ -125,13 +125,11 @@ abstract contract Fuzzers is Constants, Utils { } /// @dev Fuzzes the segment timestamps. - function fuzzSegmentTimestamps(LockupDynamic.Segment[] memory segments, uint40 startTime) internal view { + function fuzzSegmentTimestamps(LockupDynamic.Segment[] memory segments, uint40 startTime) internal pure { // Return here if there's only one segment to not run into division by zero. uint40 segmentCount = uint40(segments.length); if (segmentCount == 1) { - // The end time must be in the future. - uint40 blockTimestamp = getBlockTimestamp(); - segments[0].timestamp = (startTime < blockTimestamp ? blockTimestamp : startTime) + 2 days; + segments[0].timestamp = startTime + 2 days; return; } @@ -173,13 +171,11 @@ abstract contract Fuzzers is Constants, Utils { } /// @dev Fuzzes the tranche timestamps. - function fuzzTrancheTimestamps(LockupTranched.Tranche[] memory tranches, uint40 startTime) internal view { + function fuzzTrancheTimestamps(LockupTranched.Tranche[] memory tranches, uint40 startTime) internal pure { // Return here if there's only one tranche to not run into division by zero. uint40 trancheCount = uint40(tranches.length); if (trancheCount == 1) { - // The end time must be in the future. - uint40 blockTimestamp = getBlockTimestamp(); - tranches[0].timestamp = (startTime < blockTimestamp ? blockTimestamp : startTime) + 2 days; + tranches[0].timestamp = startTime + 2 days; return; } diff --git a/test/utils/Utils.sol b/test/utils/Utils.sol index 6a09e4b8a..48e852c68 100644 --- a/test/utils/Utils.sol +++ b/test/utils/Utils.sol @@ -84,14 +84,11 @@ abstract contract Utils is CommonBase, PRBMathUtils { } /// @dev Returns the largest of the provided `uint40` numbers. - function maxOfThree(uint40 a, uint40 b, uint40 c) internal pure returns (uint40) { + function maxOfTwo(uint40 a, uint40 b) internal pure returns (uint40) { uint40 max = a; if (b > max) { max = b; } - if (c > max) { - max = c; - } return max; } From 6201781c09c8410794f6beb7034b8e10263e8225 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Mon, 19 Aug 2024 03:10:30 +0530 Subject: [PATCH 20/34] refactor: amounts type reference in Lockup.Stream struct (#1019) --- src/core/types/DataTypes.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/types/DataTypes.sol b/src/core/types/DataTypes.sol index ebe5c4820..5f1feaed9 100644 --- a/src/core/types/DataTypes.sol +++ b/src/core/types/DataTypes.sol @@ -97,7 +97,7 @@ library Lockup { bool isStream; bool isTransferable; // slot 2 and 3 - Lockup.Amounts amounts; + Amounts amounts; } } From 656821c6bbfa4ff84736ac7bcb97cc6120e967a8 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 6 Aug 2024 13:51:31 +0300 Subject: [PATCH 21/34] feat: add deploy multi chain rust script --- .gitignore | 2 + deploy-multi-chain/Cargo.toml | 10 ++ deploy-multi-chain/src/main.rs | 215 +++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 deploy-multi-chain/Cargo.toml create mode 100644 deploy-multi-chain/src/main.rs diff --git a/.gitignore b/.gitignore index 7a74302fe..d6aa4a7a0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ node_modules out out-optimized out-svg +target # files *.env @@ -16,6 +17,7 @@ out-svg *.log .DS_Store .pnp.* +Cargo.lock lcov.info package-lock.json pnpm-lock.yaml diff --git a/deploy-multi-chain/Cargo.toml b/deploy-multi-chain/Cargo.toml new file mode 100644 index 000000000..0112ef7a7 --- /dev/null +++ b/deploy-multi-chain/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "deploy-multi-chain" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dotenv = "0.15" # or the latest version +toml = "0.5" # or the latest version \ No newline at end of file diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs new file mode 100644 index 000000000..f9c427caf --- /dev/null +++ b/deploy-multi-chain/src/main.rs @@ -0,0 +1,215 @@ +use std::collections::HashMap; +use std::env; +use std::fs; +use std::path::Path; +use std::process::{Command, Stdio}; +use toml::Value; + +fn main() { + // Process command-line arguments + let args: Vec = env::args().collect(); + let mut iter = args.iter().skip(1); + + // Variables to store flags and provided chains + let mut broadcast_deployment = "".to_string(); + let mut script_name = "DeployProtocol.s.sol".to_string(); + let mut gas_price = "".to_string(); + let mut on_all_chains = false; + let mut provided_chains: Vec = Vec::new(); + + // Parse all arguments + while let Some(arg) = iter.next() { + match arg.as_str() { + "--all" => on_all_chains = true, + "--deterministic" => script_name = "DeployDeterministicProtocol.s.sol".to_string(), + "--broadcast" => broadcast_deployment = " --broadcast --verify".to_string(), + "--gas-price" => { + let value = iter.next().expect("gas price value").to_string(); + gas_price = format!(" --gas-price {}", value); + } + _ => { + if !arg.starts_with("--") && !on_all_chains { + provided_chains.push(arg.to_string()); + } else { + println!("Unknown flag: {}", arg); + } + } + } + } + + let mut chains = Vec::new(); + chains = get_all_chains(); + + if on_all_chains { + provided_chains = chains; + } else { + provided_chains.retain(|chain| { + if chains.contains(chain) { + true // Keep the element in the vector + } else { + println!("Chain {} is not configured in the TOML file", chain); + false // Remove the element from the vector + } + }); + } + + // Default to "sepolia" if no chains are specified and --all is not used + if provided_chains.is_empty() && !on_all_chains { + provided_chains.push("sepolia".to_string()); + } + + // Output the list of unique chains + let chains_string = provided_chains.clone().join(", "); + println!("Deploying to the chains: {}", chains_string); + + // Before deploying, create the deployments directory to store the deployment addresses. + create_deployments_dir(); + + let command = format!( + "FOUNDRY_PROFILE=optimized forge script ../script/{}{}{}", + script_name, broadcast_deployment, gas_price + ); + + for chain in provided_chains { + let deployment_command = + format!("{} {} --rpc-url {}", command, get_script_sig(&chain), chain); + + println!("Running the deployment command: {}", deployment_command); + + // Execute the deployment command + let output = Command::new("sh") + .arg("-c") + .arg(&deployment_command) + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output() + .expect("Failed to execute command"); + + // Capture and print output + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + // Print the command output in real-time + if !stdout.is_empty() { + print!("{}", stdout); + } + if !stderr.is_empty() { + eprint!("{}", stderr); + } + + // Check for error in output + if stderr.contains("Error") { + eprintln!("Deployment failed for chain {}", chain); + std::process::exit(1); + } + // Create a file for the chain + let chain_file = format!("{}/{}.txt", deployments_dir, chain); + let mut file = fs::File::create(&chain_file).expect("Failed to create file"); + + // Extract and save contract addresses + let batch_lockup_address = extract_address(&stdout, "batchLockup: contract"); + let lockup_dynamic_address = extract_address(&stdout, "lockupDynamic: contract"); + let lockup_linear_address = extract_address(&stdout, "lockupLinear: contract"); + let lockup_tranched_address = extract_address(&stdout, "lockupTranched: contract"); + let merkle_lockup_factory_address = + extract_address(&stdout, "merkleLockupFactory: contract"); + let nft_descriptor_address = extract_address(&stdout, "nftDescriptor: contract"); + + // Save to the chain file + writeln!(file, "Core Contracts").expect("Failed to write to file"); + writeln!(file, "SablierLockupDynamic = {}", lockup_dynamic_address) + .expect("Failed to write to file"); + writeln!(file, "SablierLockupLinear = {}", lockup_linear_address) + .expect("Failed to write to file"); + writeln!(file, "SablierLockupTranched = {}", lockup_tranched_address) + .expect("Failed to write to file"); + writeln!(file, "SablierNFTDescriptor = {}", nft_descriptor_address) + .expect("Failed to write to file"); + writeln!(file, "Periphery Contracts").expect("Failed to write to file"); + writeln!(file, "SablierBatchLockup = {}", batch_lockup_address) + .expect("Failed to write to file"); + writeln!( + file, + "SablierMerkleLockupFactory = {}", + merkle_lockup_factory_address + ) + .expect("Failed to write to file"); + } +} + +fn create_deployments_dir() { + let deployments = "../deployments"; + let path = Path::new(deployments); + + // Check if the directory exists + if path.exists() { + // Attempt to remove the directory if it exists + if let Err(e) = fs::remove_dir_all(deployments) { + eprintln!("Failed to remove directory '{}': {}", deployments, e); + return; // Exit the function if removal fails + } + } + + // Attempt to create the directory + if let Err(e) = fs::create_dir(deployments) { + eprintln!("Failed to create directory '{}': {}", deployments, e); + } +} + +// Function that reads the TOML chain configurations and extracts them +fn get_all_chains() -> Vec { + // Define the path to the TOML file + let toml_path = Path::new("../foundry.toml"); + + // Read and parse the TOML file content + let toml_content = match fs::read_to_string(toml_path) { + Ok(content) => content, + Err(_) => { + eprintln!("Failed to read the TOML file"); + return Vec::new(); + } + }; + + let toml_values: Value = match toml::from_str(&toml_content) { + Ok(value) => value, + Err(_) => { + eprintln!("Failed to parse TOML content"); + return Vec::new(); + } + }; + + // Extract chains from the TOML data + let sections = ["rpc_endpoints", "etherscan"]; + let mut chains = Vec::new(); + + for section in §ions { + if let Some(table) = toml_values.get(section).and_then(|v| v.as_table()) { + chains.extend(table.keys().filter(|&key| key != "localhost").cloned()); + } + } + + chains.into_iter().collect() +} + +// Function to get admin address based on the chain name +fn get_script_sig(chain: &str) -> String { + let mut admins = HashMap::new(); + let sablier_deployer = "0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F"; + + admins.insert("arbitrum", "0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376"); + admins.insert("avalanche", "0x4735517616373c5137dE8bcCDc887637B8ac85Ce"); + admins.insert("base", "0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66"); + admins.insert("bnb", "0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3"); + admins.insert("gnosis", "0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399"); + admins.insert("mainnet", "0x79Fb3e81aAc012c08501f41296CCC145a1E15844"); + admins.insert("optimism", "0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350"); + admins.insert("polygon", "0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6"); + admins.insert("scroll", "0x0F7Ad835235Ede685180A5c611111610813457a9"); + + // The admin address for the chain, or the default deployer address in case of testnets + // and no multisig on specific chain + let admin = admins.get(chain).unwrap_or(&sablier_deployer).to_string(); + + format!("--sig \"run(address)\" {}", admin) +} From 3417afc986c00747bdc951ff69623330f58e1a9f Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 6 Aug 2024 17:28:54 +0300 Subject: [PATCH 22/34] feat(script): write the addresses in deployments feat(script): add an admin map in base script feat(script): implement getVersion function refactor(script): move protocol scripts in their dir --- foundry.toml | 1 + script/Base.s.sol | 52 +++++- script/DeployDeterministicProtocol.s.sol | 45 ----- script/DeployProtocol.s.sol | 41 ----- .../DeployDeterministicProtocol.s.sol | 86 ++++++++++ script/protocol/DeployProtocol.s.sol | 79 +++++++++ script/protocol/Protocol.s.sol | 156 ++++++++++++++++++ 7 files changed, 372 insertions(+), 88 deletions(-) delete mode 100644 script/DeployDeterministicProtocol.s.sol delete mode 100644 script/DeployProtocol.s.sol create mode 100644 script/protocol/DeployDeterministicProtocol.s.sol create mode 100644 script/protocol/DeployProtocol.s.sol create mode 100644 script/protocol/Protocol.s.sol diff --git a/foundry.toml b/foundry.toml index 153219257..bf3bc8b33 100644 --- a/foundry.toml +++ b/foundry.toml @@ -6,6 +6,7 @@ { access = "read", path = "./out-optimized" }, { access = "read", path = "package.json" }, { access = "read-write", path = "./benchmark/results" }, + { access = "read-write", path = "./deployments/" }, ] gas_limit = 9223372036854775807 optimizer = true diff --git a/script/Base.s.sol b/script/Base.s.sol index 7fbf27703..cb2f51493 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -15,6 +15,9 @@ contract BaseScript is Script { /// @dev The default value for `segmentCountMap` and `trancheCountMap`. uint256 internal constant DEFAULT_MAX_COUNT = 500; + /// @dev The address of the Sablier deployer. + address internal constant SABLIER_DEPLOYER = 0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F; + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -27,6 +30,9 @@ contract BaseScript is Script { /// @dev Used to derive the broadcaster's address if $EOA is not defined. string internal mnemonic; + /// @dev Admin address mapped by the chain Id. + mapping(uint256 chainId => address admin) internal adminMap; + /// @dev Maximum segment count mapped by the chain Id. mapping(uint256 chainId => uint256 count) internal segmentCountMap; @@ -59,6 +65,14 @@ contract BaseScript is Script { if (trancheCountMap[block.chainid] == 0) { trancheCountMap[block.chainid] = DEFAULT_MAX_COUNT; } + + // Populate the admin map. + populateAdminMap(); + + // If there is no admin set for a specific chain, use the Sablier deployer. + if (adminMap[block.chainid] == address(0)) { + adminMap[block.chainid] = SABLIER_DEPLOYER; + } } modifier broadcast() { @@ -75,13 +89,47 @@ contract BaseScript is Script { /// - The version is obtained from `package.json`. function constructCreate2Salt() public view returns (bytes32) { string memory chainId = block.chainid.toString(); - string memory json = vm.readFile("package.json"); - string memory version = json.readString(".version"); + string memory version = getVersion(); string memory create2Salt = string.concat("ChainID ", chainId, ", Version ", version); console2.log("The CREATE2 salt is \"%s\"", create2Salt); return bytes32(abi.encodePacked(create2Salt)); } + function getVersion() public view returns (string memory) { + string memory json = vm.readFile("package.json"); + return json.readString(".version"); + } + + /// @dev Populates the admin map. + function populateAdminMap() internal { + // Arbitrum chain ID. + adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; + + // Avalanche chain ID. + adminMap[43_114] = 0x4735517616373c5137dE8bcCDc887637B8ac85Ce; + + // Base chain ID. + adminMap[8453] = 0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66; + + // BNB chain ID. + adminMap[56] = 0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3; + + // Gnosis chain ID. + adminMap[100] = 0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399; + + // Ethereum chain ID. + adminMap[1] = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; + + // Optimism chain ID. + adminMap[10] = 0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350; + + // Polygon chain ID. + adminMap[137] = 0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6; + + // Scroll chain ID. + adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; + } + /// @dev Populates the segment & tranche count map. Values can be updated using the `update-counts.sh` script. function populateSegmentAndTrancheCountMap() internal { // forgefmt: disable-start diff --git a/script/DeployDeterministicProtocol.s.sol b/script/DeployDeterministicProtocol.s.sol deleted file mode 100644 index aad615212..000000000 --- a/script/DeployDeterministicProtocol.s.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; -import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; -import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; -import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; -import { SablierMerkleFactory } from "../src/periphery/SablierMerkleFactory.sol"; -import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @notice Deploys the Lockup Protocol at deterministic addresses across chains. -contract DeployDeterministicProtocol is BaseScript { - /// @dev Deploy via Forge. - function run( - address initialAdmin - ) - public - virtual - broadcast - returns ( - LockupNFTDescriptor nftDescriptor, - SablierLockupDynamic lockupDynamic, - SablierLockupLinear lockupLinear, - SablierLockupTranched lockupTranched, - SablierBatchLockup batchLockup, - SablierMerkleFactory merkleFactory - ) - { - bytes32 salt = constructCreate2Salt(); - - // Deploy Core. - nftDescriptor = new LockupNFTDescriptor{ salt: salt }(); - lockupDynamic = - new SablierLockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, nftDescriptor); - lockupTranched = - new SablierLockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); - - // Deploy Periphery. - batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleFactory = new SablierMerkleFactory{ salt: salt }(); - } -} diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol deleted file mode 100644 index dbb1ba098..000000000 --- a/script/DeployProtocol.s.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity >=0.8.22 <0.9.0; - -import { LockupNFTDescriptor } from "../src/core/LockupNFTDescriptor.sol"; -import { SablierLockupDynamic } from "../src/core/SablierLockupDynamic.sol"; -import { SablierLockupLinear } from "../src/core/SablierLockupLinear.sol"; -import { SablierLockupTranched } from "../src/core/SablierLockupTranched.sol"; -import { SablierMerkleFactory } from "../src/periphery/SablierMerkleFactory.sol"; -import { SablierBatchLockup } from "../src/periphery/SablierBatchLockup.sol"; - -import { BaseScript } from "./Base.s.sol"; - -/// @notice Deploys the Lockup Protocol. -contract DeployProtocol is BaseScript { - /// @dev Deploy via Forge. - function run( - address initialAdmin - ) - public - virtual - broadcast - returns ( - LockupNFTDescriptor nftDescriptor, - SablierLockupDynamic lockupDynamic, - SablierLockupLinear lockupLinear, - SablierLockupTranched lockupTranched, - SablierBatchLockup batchLockup, - SablierMerkleFactory merkleFactory - ) - { - // Deploy Core. - nftDescriptor = new LockupNFTDescriptor(); - lockupDynamic = new SablierLockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); - lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); - lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); - - // Deploy Periphery. - batchLockup = new SablierBatchLockup(); - merkleFactory = new SablierMerkleFactory(); - } -} diff --git a/script/protocol/DeployDeterministicProtocol.s.sol b/script/protocol/DeployDeterministicProtocol.s.sol new file mode 100644 index 000000000..0b335de04 --- /dev/null +++ b/script/protocol/DeployDeterministicProtocol.s.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; +import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; + +import { BaseScript } from "../Base.s.sol"; + +/// @notice Deploys the Lockup Protocol at deterministic addresses across chains. +contract DeployDeterministicProtocol is BaseScript { + /// @dev Deploys the protocol with the admin set in `adminMap`. + function run() + public + virtual + broadcast + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + address initialAdmin = adminMap[block.chainid]; + + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = + _run(initialAdmin); + } + + /// @dev Deploys the protocol with the given `initialAdmin`. + function run(address initialAdmin) + internal + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = + _run(initialAdmin); + } + + /// @dev Common logic for the run functions. + function _run(address initialAdmin) + internal + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + bytes32 salt = constructCreate2Salt(); + + // Deploy Core. + nftDescriptor = new LockupNFTDescriptor{ salt: salt }(); + lockupDynamic = + new SablierLockupDynamic{ salt: salt }(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear{ salt: salt }(initialAdmin, nftDescriptor); + lockupTranched = + new SablierLockupTranched{ salt: salt }(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + + // Deploy Periphery. + batchLockup = new SablierBatchLockup{ salt: salt }(); + merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); + + _appendToFileDeployedAddresses( + address(lockupDynamic), + address(lockupLinear), + address(lockupTranched), + address(nftDescriptor), + address(batchLockup), + address(merkleLockupFactory) + ); + } +} diff --git a/script/protocol/DeployProtocol.s.sol b/script/protocol/DeployProtocol.s.sol new file mode 100644 index 000000000..d230f2461 --- /dev/null +++ b/script/protocol/DeployProtocol.s.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; +import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; +import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; +import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; +import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; + +import { ProtocolScript } from "./Protocol.s.sol"; + +/// @notice Deploys the Lockup Protocol. +contract DeployProtocol is ProtocolScript { + /// @dev Deploys the protocol with the admin set in `adminMap`. + function run() + public + virtual + broadcast + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + address initialAdmin = adminMap[block.chainid]; + + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = + _run(initialAdmin); + } + + /// @dev Deploys the protocol with the given `initialAdmin`. + function run(address initialAdmin) + internal + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = + _run(initialAdmin); + } + + /// @dev Common logic for the run functions. + function _run(address initialAdmin) + internal + returns ( + LockupNFTDescriptor nftDescriptor, + SablierLockupDynamic lockupDynamic, + SablierLockupLinear lockupLinear, + SablierLockupTranched lockupTranched, + SablierBatchLockup batchLockup, + SablierMerkleLockupFactory merkleLockupFactory + ) + { + nftDescriptor = new LockupNFTDescriptor(); + lockupDynamic = new SablierLockupDynamic(initialAdmin, nftDescriptor, segmentCountMap[block.chainid]); + lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); + lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); + batchLockup = new SablierBatchLockup(); + merkleLockupFactory = new SablierMerkleLockupFactory(); + + _appendToFileDeployedAddresses( + address(lockupDynamic), + address(lockupLinear), + address(lockupTranched), + address(nftDescriptor), + address(batchLockup), + address(merkleLockupFactory) + ); + } +} diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol new file mode 100644 index 000000000..1f74001ae --- /dev/null +++ b/script/protocol/Protocol.s.sol @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; +import { stdJson } from "forge-std/src/StdJson.sol"; + +import { BaseScript } from "../Base.s.sol"; + +abstract contract ProtocolScript is BaseScript { + using Strings for uint256; + using Strings for address; + using stdJson for string; + + /// @dev The path to the file where the deployment addresses are stored. + string internal deploymentFile = "deployments/"; + + string internal version = getVersion(); + + constructor() { + string memory chainId = block.chainid.toString(); + deploymentFile = string.concat(deploymentFile, chainId, ".md"); + + // Create the file if it doesn't exist, otherwise overwrite it. + vm.writeFile({ path: deploymentFile, data: string.concat("# Deployed Addresses for chain ", chainId, "\n\n") }); + } + + // forgefmt: disable-start + + // ### Core + + // | Contract | Address | Deployment | + // | :-------------------- | :-------------------------------------------- | :---------------------------------------------------------------------------------------- | + // | SablierLockupDynamic | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | + // | SablierLockupLinear | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | + // | SablierLockupTranched | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | + // | LockupNFTDescriptor | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | + + // ### Periphery + + // | Contract | Address | Deployment | + // | :------------------------- | :-------------------------------------------- | :-------------------------------------------------------------------------------------------------- | + // | SablierBatchLockup | [0x...](https:///address/0x...) | [periphery-](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/) | + // | SablierMerkleLockupFactory | [0x...](https:///address/0x...) | [periphery-](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/) | + + // forgefmt: disable-end + + function _appendToFileDeployedAddresses( + address lockupDynamic, + address lockupLinear, + address lockupTranched, + address nftDescriptor, + address batchLockup, + address merkleFactory + ) + internal + { + string memory core = " ### Core\n\n"; + _appendToFile(core); + + string memory firstTwoLines = "| Contract | Address | Deployment |\n | :------- | :------ | :----------|"; + _appendToFile(firstTwoLines); + + string memory lockupDynamicHex = lockupDynamic.toHexString(); + string memory lockupDynamicLine = string.concat( + "| SablierLockupDynamic | [", + lockupDynamicHex, + "](https:///address/", + lockupDynamicHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(lockupDynamicLine); + + string memory lockupLinearHex = lockupLinear.toHexString(); + string memory lockupLinearLine = string.concat( + "| SablierLockupLinear | [", + lockupLinearHex, + "](https:///address/", + lockupLinearHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(lockupLinearLine); + + string memory lockupTranchedHex = lockupTranched.toHexString(); + string memory lockupTranchedLine = string.concat( + "| SablierLockupTranched | [", + lockupTranchedHex, + "](https:///address/", + lockupTranchedHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(lockupTranchedLine); + + string memory nftDescriptorHex = nftDescriptor.toHexString(); + string memory nftDescriptorLine = string.concat( + "| LockupNFTDescriptor | [", + nftDescriptorHex, + "](https:///address/", + nftDescriptorHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(nftDescriptorLine); + + string memory periphery = " ### Periphery\n\n"; + _appendToFile(periphery); + _appendToFile(firstTwoLines); + + string memory batchLockupHex = batchLockup.toHexString(); + string memory batchLockupLine = string.concat( + "| SablierBatchLockup | [", + batchLockupHex, + "](https:///address/", + batchLockupHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(batchLockupLine); + + string memory merkleFactoryHex = merkleFactory.toHexString(); + string memory merkleFactoryLine = string.concat( + "| SablierBatchLockup | [", + merkleFactoryHex, + "](https:///address/", + merkleFactoryHex, + ") | [core-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + version, + ") |" + ); + _appendToFile(merkleFactoryLine); + } + + /// @dev Append a line to the deployment file path. + function _appendToFile(string memory line) internal { + vm.writeLine({ path: deploymentFile, data: line }); + } +} From 921e5390eb4e8b522f3c8a82b0af5f15bf74a19e Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 6 Aug 2024 18:41:39 +0300 Subject: [PATCH 23/34] feat(script): add explorer map refactor(script): move protocol admin map --- script/Base.s.sol | 41 ------------ script/protocol/Protocol.s.sol | 116 +++++++++++++++++++++++---------- 2 files changed, 82 insertions(+), 75 deletions(-) diff --git a/script/Base.s.sol b/script/Base.s.sol index cb2f51493..1107b6469 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -30,9 +30,6 @@ contract BaseScript is Script { /// @dev Used to derive the broadcaster's address if $EOA is not defined. string internal mnemonic; - /// @dev Admin address mapped by the chain Id. - mapping(uint256 chainId => address admin) internal adminMap; - /// @dev Maximum segment count mapped by the chain Id. mapping(uint256 chainId => uint256 count) internal segmentCountMap; @@ -65,14 +62,6 @@ contract BaseScript is Script { if (trancheCountMap[block.chainid] == 0) { trancheCountMap[block.chainid] = DEFAULT_MAX_COUNT; } - - // Populate the admin map. - populateAdminMap(); - - // If there is no admin set for a specific chain, use the Sablier deployer. - if (adminMap[block.chainid] == address(0)) { - adminMap[block.chainid] = SABLIER_DEPLOYER; - } } modifier broadcast() { @@ -100,36 +89,6 @@ contract BaseScript is Script { return json.readString(".version"); } - /// @dev Populates the admin map. - function populateAdminMap() internal { - // Arbitrum chain ID. - adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; - - // Avalanche chain ID. - adminMap[43_114] = 0x4735517616373c5137dE8bcCDc887637B8ac85Ce; - - // Base chain ID. - adminMap[8453] = 0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66; - - // BNB chain ID. - adminMap[56] = 0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3; - - // Gnosis chain ID. - adminMap[100] = 0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399; - - // Ethereum chain ID. - adminMap[1] = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; - - // Optimism chain ID. - adminMap[10] = 0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350; - - // Polygon chain ID. - adminMap[137] = 0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6; - - // Scroll chain ID. - adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; - } - /// @dev Populates the segment & tranche count map. Values can be updated using the `update-counts.sh` script. function populateSegmentAndTrancheCountMap() internal { // forgefmt: disable-start diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 1f74001ae..5af7eaf3f 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -6,44 +6,59 @@ import { stdJson } from "forge-std/src/StdJson.sol"; import { BaseScript } from "../Base.s.sol"; +/// @dev This contract creates a Markdown file with the deployed addresses with the format used in docs: +/// https://docs.sablier.com/contracts/v2/deployments abstract contract ProtocolScript is BaseScript { - using Strings for uint256; - using Strings for address; using stdJson for string; + using Strings for address; + using Strings for string; + using Strings for uint256; /// @dev The path to the file where the deployment addresses are stored. - string internal deploymentFile = "deployments/"; + string internal deploymentFile = string.concat("deployments/", block.chainid.toString(), ".md"); + /// @dev The version of the deployment. string internal version = getVersion(); + /// @dev Admin address mapped by the chain Id. + mapping(uint256 chainId => address admin) internal adminMap; + + /// @dev Explorer URL mapped by the chain Id. + mapping(uint256 chainId => string explorerUrl) internal explorerMap; + constructor() { - string memory chainId = block.chainid.toString(); - deploymentFile = string.concat(deploymentFile, chainId, ".md"); + // Populate the admin map. + populateAdminMap(); + + // Populate the explorer URLs. + populateExplorerMap(); + + // If there is no admin set for a specific chain, use the Sablier deployer. + if (adminMap[block.chainid] == address(0)) { + adminMap[block.chainid] = SABLIER_DEPLOYER; + } + + // If there is no explorer URL set for a specific chain, use a placeholder. + if (Strings.equal(explorerMap[block.chainid], "")) { + explorerMap[block.chainid] = ""; + } + + // Create the deployment file if it doesn't exist. + if (!vm.isDir("deployments")) { + string[] memory mkDirCommand = new string[](2); + mkDirCommand[0] = "mkdir"; + mkDirCommand[1] = "deployments"; + vm.ffi(mkDirCommand); + } // Create the file if it doesn't exist, otherwise overwrite it. - vm.writeFile({ path: deploymentFile, data: string.concat("# Deployed Addresses for chain ", chainId, "\n\n") }); + vm.writeFile({ + path: deploymentFile, + data: string.concat("# Deployed Addresses for chain ", block.chainid.toString(), "\n\n") + }); } - // forgefmt: disable-start - - // ### Core - - // | Contract | Address | Deployment | - // | :-------------------- | :-------------------------------------------- | :---------------------------------------------------------------------------------------- | - // | SablierLockupDynamic | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | - // | SablierLockupLinear | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | - // | SablierLockupTranched | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | - // | LockupNFTDescriptor | [0x...](https:///address/0x...) | [core-](https://github.com/sablier-labs/v2-deployments/tree/main/core/) | - - // ### Periphery - - // | Contract | Address | Deployment | - // | :------------------------- | :-------------------------------------------- | :-------------------------------------------------------------------------------------------------- | - // | SablierBatchLockup | [0x...](https:///address/0x...) | [periphery-](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/) | - // | SablierMerkleLockupFactory | [0x...](https:///address/0x...) | [periphery-](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/) | - - // forgefmt: disable-end - + /// @dev Function to append the deployed addresses to the deployment file. function _appendToFileDeployedAddresses( address lockupDynamic, address lockupLinear, @@ -64,7 +79,8 @@ abstract contract ProtocolScript is BaseScript { string memory lockupDynamicLine = string.concat( "| SablierLockupDynamic | [", lockupDynamicHex, - "](https:///address/", + "](", + explorerMap[block.chainid], lockupDynamicHex, ") | [core-", version, @@ -78,7 +94,8 @@ abstract contract ProtocolScript is BaseScript { string memory lockupLinearLine = string.concat( "| SablierLockupLinear | [", lockupLinearHex, - "](https:///address/", + "](", + explorerMap[block.chainid], lockupLinearHex, ") | [core-", version, @@ -92,7 +109,8 @@ abstract contract ProtocolScript is BaseScript { string memory lockupTranchedLine = string.concat( "| SablierLockupTranched | [", lockupTranchedHex, - "](https:///address/", + "](", + explorerMap[block.chainid], lockupTranchedHex, ") | [core-", version, @@ -106,7 +124,8 @@ abstract contract ProtocolScript is BaseScript { string memory nftDescriptorLine = string.concat( "| LockupNFTDescriptor | [", nftDescriptorHex, - "](https:///address/", + "](", + explorerMap[block.chainid], nftDescriptorHex, ") | [core-", version, @@ -116,7 +135,7 @@ abstract contract ProtocolScript is BaseScript { ); _appendToFile(nftDescriptorLine); - string memory periphery = " ### Periphery\n\n"; + string memory periphery = "\n ### Periphery\n\n"; _appendToFile(periphery); _appendToFile(firstTwoLines); @@ -124,7 +143,8 @@ abstract contract ProtocolScript is BaseScript { string memory batchLockupLine = string.concat( "| SablierBatchLockup | [", batchLockupHex, - "](https:///address/", + "](", + explorerMap[block.chainid], batchLockupHex, ") | [core-", version, @@ -136,9 +156,10 @@ abstract contract ProtocolScript is BaseScript { string memory merkleFactoryHex = merkleFactory.toHexString(); string memory merkleFactoryLine = string.concat( - "| SablierBatchLockup | [", + "| SablierMerkleFactory | [", merkleFactoryHex, - "](https:///address/", + "](", + explorerMap[block.chainid], merkleFactoryHex, ") | [core-", version, @@ -153,4 +174,31 @@ abstract contract ProtocolScript is BaseScript { function _appendToFile(string memory line) internal { vm.writeLine({ path: deploymentFile, data: line }); } + + /// @dev Populates the admin map. + function populateAdminMap() internal { + adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; + adminMap[43_114] = 0x4735517616373c5137dE8bcCDc887637B8ac85Ce; + adminMap[8453] = 0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66; + adminMap[56] = 0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3; + adminMap[100] = 0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399; + adminMap[1] = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; + adminMap[10] = 0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350; + adminMap[137] = 0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6; + adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; + } + + function populateExplorerMap() internal { + explorerMap[42_161] = "https://arbiscan.io/address/"; + explorerMap[43_114] = "https://snowtrace.io/address/"; + explorerMap[8453] = "https://basescan.org/address/"; + explorerMap[81_457] = "https://blastscan.io/address/"; + explorerMap[56] = "https://bscscan.com/address/"; + explorerMap[1] = "https://etherscan.io/address/"; + explorerMap[100] = "https://gnosisscan.io/address/"; + explorerMap[10] = "https://optimistic.etherscan.io/address/"; + explorerMap[137] = "https://polygonscan.com/address/"; + explorerMap[534_352] = "https://scrollscan.com/address/"; + explorerMap[11_155_111] = "https://sepolia.etherscan.io/address/"; + } } From 2010f21e80a35a31ba8dd0bf06501a7574c00e20 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Tue, 6 Aug 2024 18:42:10 +0300 Subject: [PATCH 24/34] build: update rust script --- deploy-multi-chain/src/main.rs | 124 ++++++--------------------------- 1 file changed, 20 insertions(+), 104 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index f9c427caf..2725c0b4d 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use std::env; use std::fs; use std::path::Path; -use std::process::{Command, Stdio}; +use std::process::Command; use toml::Value; fn main() { @@ -15,7 +15,7 @@ fn main() { let mut script_name = "DeployProtocol.s.sol".to_string(); let mut gas_price = "".to_string(); let mut on_all_chains = false; - let mut provided_chains: Vec = Vec::new(); + let mut provided_chains = Vec::new(); // Parse all arguments while let Some(arg) = iter.next() { @@ -62,98 +62,36 @@ fn main() { let chains_string = provided_chains.clone().join(", "); println!("Deploying to the chains: {}", chains_string); - // Before deploying, create the deployments directory to store the deployment addresses. - create_deployments_dir(); - let command = format!( - "FOUNDRY_PROFILE=optimized forge script ../script/{}{}{}", + "FOUNDRY_PROFILE=optimized forge script ../script/protocol/{}{}{}", script_name, broadcast_deployment, gas_price ); for chain in provided_chains { - let deployment_command = - format!("{} {} --rpc-url {}", command, get_script_sig(&chain), chain); + let deployment_command = format!("{} --rpc-url {}", command, chain); println!("Running the deployment command: {}", deployment_command); - // Execute the deployment command - let output = Command::new("sh") - .arg("-c") - .arg(&deployment_command) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .output() - .expect("Failed to execute command"); - - // Capture and print output - let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); - - // Print the command output in real-time - if !stdout.is_empty() { - print!("{}", stdout); - } - if !stderr.is_empty() { - eprint!("{}", stderr); - } + // Split the command into parts + let parts: Vec<&str> = deployment_command.split_whitespace().collect(); - // Check for error in output - if stderr.contains("Error") { - eprintln!("Deployment failed for chain {}", chain); - std::process::exit(1); - } - // Create a file for the chain - let chain_file = format!("{}/{}.txt", deployments_dir, chain); - let mut file = fs::File::create(&chain_file).expect("Failed to create file"); - - // Extract and save contract addresses - let batch_lockup_address = extract_address(&stdout, "batchLockup: contract"); - let lockup_dynamic_address = extract_address(&stdout, "lockupDynamic: contract"); - let lockup_linear_address = extract_address(&stdout, "lockupLinear: contract"); - let lockup_tranched_address = extract_address(&stdout, "lockupTranched: contract"); - let merkle_lockup_factory_address = - extract_address(&stdout, "merkleLockupFactory: contract"); - let nft_descriptor_address = extract_address(&stdout, "nftDescriptor: contract"); - - // Save to the chain file - writeln!(file, "Core Contracts").expect("Failed to write to file"); - writeln!(file, "SablierLockupDynamic = {}", lockup_dynamic_address) - .expect("Failed to write to file"); - writeln!(file, "SablierLockupLinear = {}", lockup_linear_address) - .expect("Failed to write to file"); - writeln!(file, "SablierLockupTranched = {}", lockup_tranched_address) - .expect("Failed to write to file"); - writeln!(file, "SablierNFTDescriptor = {}", nft_descriptor_address) - .expect("Failed to write to file"); - writeln!(file, "Periphery Contracts").expect("Failed to write to file"); - writeln!(file, "SablierBatchLockup = {}", batch_lockup_address) - .expect("Failed to write to file"); - writeln!( - file, - "SablierMerkleLockupFactory = {}", - merkle_lockup_factory_address - ) - .expect("Failed to write to file"); - } -} + // Set the environment variable + let env_var = parts[0]; + let env_var_parts: Vec<&str> = env_var.split('=').collect(); + std::env::set_var(env_var_parts[0], env_var_parts[1]); -fn create_deployments_dir() { - let deployments = "../deployments"; - let path = Path::new(deployments); + // Define the command and arguments + let mut cmd = Command::new(parts[1]); + cmd.args(&parts[2..]); - // Check if the directory exists - if path.exists() { - // Attempt to remove the directory if it exists - if let Err(e) = fs::remove_dir_all(deployments) { - eprintln!("Failed to remove directory '{}': {}", deployments, e); - return; // Exit the function if removal fails - } - } + // Capture the command output + let output = cmd.output().expect("Failed to run command"); - // Attempt to create the directory - if let Err(e) = fs::create_dir(deployments) { - eprintln!("Failed to create directory '{}': {}", deployments, e); + // Check if the command executed successfully + if output.status.success() { + let output_str = String::from_utf8_lossy(&output.stdout); + println!("Command output: {}", output_str); + } } } @@ -191,25 +129,3 @@ fn get_all_chains() -> Vec { chains.into_iter().collect() } - -// Function to get admin address based on the chain name -fn get_script_sig(chain: &str) -> String { - let mut admins = HashMap::new(); - let sablier_deployer = "0xb1bEF51ebCA01EB12001a639bDBbFF6eEcA12B9F"; - - admins.insert("arbitrum", "0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376"); - admins.insert("avalanche", "0x4735517616373c5137dE8bcCDc887637B8ac85Ce"); - admins.insert("base", "0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66"); - admins.insert("bnb", "0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3"); - admins.insert("gnosis", "0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399"); - admins.insert("mainnet", "0x79Fb3e81aAc012c08501f41296CCC145a1E15844"); - admins.insert("optimism", "0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350"); - admins.insert("polygon", "0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6"); - admins.insert("scroll", "0x0F7Ad835235Ede685180A5c611111610813457a9"); - - // The admin address for the chain, or the default deployer address in case of testnets - // and no multisig on specific chain - let admin = admins.get(chain).unwrap_or(&sablier_deployer).to_string(); - - format!("--sig \"run(address)\" {}", admin) -} From 24ae07cc3a99e998b748277b4d0f05a168be151d Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 7 Aug 2024 00:40:03 +0300 Subject: [PATCH 25/34] various fixes and polishes --- script/protocol/Protocol.s.sol | 57 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 5af7eaf3f..15bee4758 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -39,11 +39,11 @@ abstract contract ProtocolScript is BaseScript { } // If there is no explorer URL set for a specific chain, use a placeholder. - if (Strings.equal(explorerMap[block.chainid], "")) { + if (explorerMap[block.chainid].equal("")) { explorerMap[block.chainid] = ""; } - // Create the deployment file if it doesn't exist. + // Create the deployment directory if it doesn't exist. This requires `--ffi` flag. if (!vm.isDir("deployments")) { string[] memory mkDirCommand = new string[](2); mkDirCommand[0] = "mkdir"; @@ -69,8 +69,8 @@ abstract contract ProtocolScript is BaseScript { ) internal { - string memory core = " ### Core\n\n"; - _appendToFile(core); + string memory coreTitle = " ### Core\n\n"; + _appendToFile(coreTitle); string memory firstTwoLines = "| Contract | Address | Deployment |\n | :------- | :------ | :----------|"; _appendToFile(firstTwoLines); @@ -84,7 +84,7 @@ abstract contract ProtocolScript is BaseScript { lockupDynamicHex, ") | [core-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", version, ") |" ); @@ -99,7 +99,7 @@ abstract contract ProtocolScript is BaseScript { lockupLinearHex, ") | [core-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", version, ") |" ); @@ -114,7 +114,7 @@ abstract contract ProtocolScript is BaseScript { lockupTranchedHex, ") | [core-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", version, ") |" ); @@ -129,14 +129,14 @@ abstract contract ProtocolScript is BaseScript { nftDescriptorHex, ") | [core-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", version, ") |" ); _appendToFile(nftDescriptorLine); - string memory periphery = "\n ### Periphery\n\n"; - _appendToFile(periphery); + string memory peripheryTitle = "\n ### Periphery\n\n"; + _appendToFile(peripheryTitle); _appendToFile(firstTwoLines); string memory batchLockupHex = batchLockup.toHexString(); @@ -146,9 +146,9 @@ abstract contract ProtocolScript is BaseScript { "](", explorerMap[block.chainid], batchLockupHex, - ") | [core-", + ") | [periphery-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/v", version, ") |" ); @@ -161,9 +161,9 @@ abstract contract ProtocolScript is BaseScript { "](", explorerMap[block.chainid], merkleFactoryHex, - ") | [core-", + ") | [periphery-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/", + "](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/v", version, ") |" ); @@ -177,26 +177,37 @@ abstract contract ProtocolScript is BaseScript { /// @dev Populates the admin map. function populateAdminMap() internal { - adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; - adminMap[43_114] = 0x4735517616373c5137dE8bcCDc887637B8ac85Ce; - adminMap[8453] = 0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66; - adminMap[56] = 0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3; - adminMap[100] = 0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399; - adminMap[1] = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; - adminMap[10] = 0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350; - adminMap[137] = 0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6; - adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; + adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; // Arbitrum + adminMap[43_114] = 0x4735517616373c5137dE8bcCDc887637B8ac85Ce; // Avalanche + adminMap[8453] = 0x83A6fA8c04420B3F9C7A4CF1c040b63Fbbc89B66; // Base + adminMap[56] = 0x6666cA940D2f4B65883b454b7Bc7EEB039f64fa3; // BNB + adminMap[100] = 0x72ACB57fa6a8fa768bE44Db453B1CDBa8B12A399; // Gnosis + adminMap[1] = 0x79Fb3e81aAc012c08501f41296CCC145a1E15844; // Mainnet + adminMap[59_144] = 0x72dCfa0483d5Ef91562817C6f20E8Ce07A81319D; // Linea + adminMap[10] = 0x43c76FE8Aec91F63EbEfb4f5d2a4ba88ef880350; // Optimism + adminMap[137] = 0x40A518C5B9c1d3D6d62Ba789501CE4D526C9d9C6; // Polygon + adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; // Scroll } + /// @dev Populates the explorer map. function populateExplorerMap() internal { explorerMap[42_161] = "https://arbiscan.io/address/"; explorerMap[43_114] = "https://snowtrace.io/address/"; explorerMap[8453] = "https://basescan.org/address/"; + explorerMap[84_532] = "https://sepolia.basescan.org/address/"; explorerMap[81_457] = "https://blastscan.io/address/"; + explorerMap[168_587_773] = "https://sepolia.blastscan.io/address/"; explorerMap[56] = "https://bscscan.com/address/"; explorerMap[1] = "https://etherscan.io/address/"; explorerMap[100] = "https://gnosisscan.io/address/"; + explorerMap[59_144] = "https://lineascan.build/address/"; + explorerMap[59_141] = "https://sepolia.lineascan.build/address/"; + explorerMap[1890] = "https://phoenix.lightlink.io/address/"; + explorerMap[34_443] = "https://explorer.mode.network/address/"; + explorerMap[919] = "https://sepolia.explorer.mode.network/address/"; + explorerMap[333_000_333] = "https://meldscan.io/address/"; explorerMap[10] = "https://optimistic.etherscan.io/address/"; + explorerMap[11_155_420] = "https://sepolia-optimistic.etherscan.io/address/"; explorerMap[137] = "https://polygonscan.com/address/"; explorerMap[534_352] = "https://scrollscan.com/address/"; explorerMap[11_155_111] = "https://sepolia.etherscan.io/address/"; From b7e83ab16e6d50091806edbad90d2392202e67f4 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 7 Aug 2024 17:43:46 +0300 Subject: [PATCH 26/34] feat(script): add information about the script used refactor(script): dry-fy the code --- .../DeployDeterministicProtocol.s.sol | 6 +- script/protocol/DeployProtocol.s.sol | 4 +- script/protocol/Protocol.s.sol | 152 ++++++++---------- 3 files changed, 73 insertions(+), 89 deletions(-) diff --git a/script/protocol/DeployDeterministicProtocol.s.sol b/script/protocol/DeployDeterministicProtocol.s.sol index 0b335de04..9b342eea5 100644 --- a/script/protocol/DeployDeterministicProtocol.s.sol +++ b/script/protocol/DeployDeterministicProtocol.s.sol @@ -8,10 +8,10 @@ import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol" import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; -import { BaseScript } from "../Base.s.sol"; +import { ProtocolScript } from "./Protocol.s.sol"; /// @notice Deploys the Lockup Protocol at deterministic addresses across chains. -contract DeployDeterministicProtocol is BaseScript { +contract DeployDeterministicProtocol is ProtocolScript("deterministic") { /// @dev Deploys the protocol with the admin set in `adminMap`. function run() public @@ -74,7 +74,7 @@ contract DeployDeterministicProtocol is BaseScript { batchLockup = new SablierBatchLockup{ salt: salt }(); merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); - _appendToFileDeployedAddresses( + appendToFileDeployedAddresses( address(lockupDynamic), address(lockupLinear), address(lockupTranched), diff --git a/script/protocol/DeployProtocol.s.sol b/script/protocol/DeployProtocol.s.sol index d230f2461..2b23358a7 100644 --- a/script/protocol/DeployProtocol.s.sol +++ b/script/protocol/DeployProtocol.s.sol @@ -11,7 +11,7 @@ import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { ProtocolScript } from "./Protocol.s.sol"; /// @notice Deploys the Lockup Protocol. -contract DeployProtocol is ProtocolScript { +contract DeployProtocol is ProtocolScript("non_deterministic") { /// @dev Deploys the protocol with the admin set in `adminMap`. function run() public @@ -67,7 +67,7 @@ contract DeployProtocol is ProtocolScript { batchLockup = new SablierBatchLockup(); merkleLockupFactory = new SablierMerkleLockupFactory(); - _appendToFileDeployedAddresses( + appendToFileDeployedAddresses( address(lockupDynamic), address(lockupLinear), address(lockupTranched), diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 15bee4758..fc19455c1 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -15,10 +15,7 @@ abstract contract ProtocolScript is BaseScript { using Strings for uint256; /// @dev The path to the file where the deployment addresses are stored. - string internal deploymentFile = string.concat("deployments/", block.chainid.toString(), ".md"); - - /// @dev The version of the deployment. - string internal version = getVersion(); + string internal deploymentFile; /// @dev Admin address mapped by the chain Id. mapping(uint256 chainId => address admin) internal adminMap; @@ -26,7 +23,7 @@ abstract contract ProtocolScript is BaseScript { /// @dev Explorer URL mapped by the chain Id. mapping(uint256 chainId => string explorerUrl) internal explorerMap; - constructor() { + constructor(string memory deterministicOrNot) { // Populate the admin map. populateAdminMap(); @@ -51,6 +48,9 @@ abstract contract ProtocolScript is BaseScript { vm.ffi(mkDirCommand); } + // Set the deployment file path. + deploymentFile = string.concat("deployments/", block.chainid.toString(), "_", deterministicOrNot, ".md"); + // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: deploymentFile, @@ -59,7 +59,7 @@ abstract contract ProtocolScript is BaseScript { } /// @dev Function to append the deployed addresses to the deployment file. - function _appendToFileDeployedAddresses( + function appendToFileDeployedAddresses( address lockupDynamic, address lockupLinear, address lockupTranched, @@ -75,104 +75,88 @@ abstract contract ProtocolScript is BaseScript { string memory firstTwoLines = "| Contract | Address | Deployment |\n | :------- | :------ | :----------|"; _appendToFile(firstTwoLines); - string memory lockupDynamicHex = lockupDynamic.toHexString(); - string memory lockupDynamicLine = string.concat( - "| SablierLockupDynamic | [", - lockupDynamicHex, - "](", - explorerMap[block.chainid], - lockupDynamicHex, - ") | [core-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", - version, - ") |" - ); + string memory lockupDynamicLine = _getContractLine({ + contractName: "SablierLockupDynamic", + contractAddress: lockupDynamic.toHexString(), + coreOrPeriphery: "core" + }); _appendToFile(lockupDynamicLine); - string memory lockupLinearHex = lockupLinear.toHexString(); - string memory lockupLinearLine = string.concat( - "| SablierLockupLinear | [", - lockupLinearHex, - "](", - explorerMap[block.chainid], - lockupLinearHex, - ") | [core-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", - version, - ") |" - ); + string memory lockupLinearLine = _getContractLine({ + contractName: "SablierLockupLinear", + contractAddress: lockupLinear.toHexString(), + coreOrPeriphery: "core" + }); _appendToFile(lockupLinearLine); - string memory lockupTranchedHex = lockupTranched.toHexString(); - string memory lockupTranchedLine = string.concat( - "| SablierLockupTranched | [", - lockupTranchedHex, - "](", - explorerMap[block.chainid], - lockupTranchedHex, - ") | [core-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", - version, - ") |" - ); + string memory lockupTranchedLine = _getContractLine({ + contractName: "SablierLockupTranched", + contractAddress: lockupTranched.toHexString(), + coreOrPeriphery: "core" + }); _appendToFile(lockupTranchedLine); - string memory nftDescriptorHex = nftDescriptor.toHexString(); - string memory nftDescriptorLine = string.concat( - "| LockupNFTDescriptor | [", - nftDescriptorHex, - "](", - explorerMap[block.chainid], - nftDescriptorHex, - ") | [core-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/core/v", - version, - ") |" - ); + string memory nftDescriptorLine = _getContractLine({ + contractName: "SablierNFTDescriptor", + contractAddress: nftDescriptor.toHexString(), + coreOrPeriphery: "core" + }); _appendToFile(nftDescriptorLine); string memory peripheryTitle = "\n ### Periphery\n\n"; _appendToFile(peripheryTitle); _appendToFile(firstTwoLines); - string memory batchLockupHex = batchLockup.toHexString(); - string memory batchLockupLine = string.concat( - "| SablierBatchLockup | [", - batchLockupHex, - "](", - explorerMap[block.chainid], - batchLockupHex, - ") | [periphery-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/v", - version, - ") |" - ); + string memory batchLockupLine = _getContractLine({ + contractName: "SablierBatchLockup", + contractAddress: batchLockup.toHexString(), + coreOrPeriphery: "periphery" + }); _appendToFile(batchLockupLine); - string memory merkleFactoryHex = merkleFactory.toHexString(); - string memory merkleFactoryLine = string.concat( - "| SablierMerkleFactory | [", - merkleFactoryHex, + string memory merkleFactoryLine = _getContractLine({ + contractName: "MerkleFactory", + contractAddress: merkleFactory.toHexString(), + coreOrPeriphery: "periphery" + }); + _appendToFile(merkleFactoryLine); + } + + /// @dev Append a line to the deployment file path. + function _appendToFile(string memory line) private { + vm.writeLine({ path: deploymentFile, data: line }); + } + + function _getContractLine( + string memory contractName, + string memory contractAddress, + string memory coreOrPeriphery + ) + private + view + returns (string memory) + { + string memory version = getVersion(); + version = string.concat("v", version); + + return string.concat( + "| ", + contractName, + " | [", + contractAddress, "](", explorerMap[block.chainid], - merkleFactoryHex, - ") | [periphery-", + contractAddress, + ") | [", + coreOrPeriphery, + "-", version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/periphery/v", + "](https://github.com/sablier-labs/v2-deployments/tree/main/", + coreOrPeriphery, + "/", version, ") |" ); - _appendToFile(merkleFactoryLine); - } - - /// @dev Append a line to the deployment file path. - function _appendToFile(string memory line) internal { - vm.writeLine({ path: deploymentFile, data: line }); } /// @dev Populates the admin map. From b5b7d2e73f3f5e3138f0ae3bf5a207e4141332dc Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 7 Aug 2024 18:07:34 +0300 Subject: [PATCH 27/34] feat: add move_broadcast_file function --- deploy-multi-chain/Cargo.toml | 1 + deploy-multi-chain/src/main.rs | 98 ++++++++++++++++++++++++++-------- script/protocol/Protocol.s.sol | 5 ++ 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/deploy-multi-chain/Cargo.toml b/deploy-multi-chain/Cargo.toml index 0112ef7a7..b30a7fb89 100644 --- a/deploy-multi-chain/Cargo.toml +++ b/deploy-multi-chain/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] dotenv = "0.15" # or the latest version +serde_json = "1.0" toml = "0.5" # or the latest version \ No newline at end of file diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index 2725c0b4d..bb0ffe2f7 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -1,9 +1,9 @@ -use std::collections::HashMap; +use serde_json::Value; use std::env; use std::fs; use std::path::Path; use std::process::Command; -use toml::Value; +use toml::Value as TomlValue; fn main() { // Process command-line arguments @@ -12,8 +12,8 @@ fn main() { // Variables to store flags and provided chains let mut broadcast_deployment = "".to_string(); - let mut script_name = "DeployProtocol.s.sol".to_string(); let mut gas_price = "".to_string(); + let mut script_name = "DeployProtocol.s.sol".to_string(); let mut on_all_chains = false; let mut provided_chains = Vec::new(); @@ -37,12 +37,12 @@ fn main() { } } - let mut chains = Vec::new(); - chains = get_all_chains(); + let chains = get_all_chains(); if on_all_chains { provided_chains = chains; } else { + // Filter out chains that are not configured in the TOML file provided_chains.retain(|chain| { if chains.contains(chain) { true // Keep the element in the vector @@ -62,27 +62,34 @@ fn main() { let chains_string = provided_chains.clone().join(", "); println!("Deploying to the chains: {}", chains_string); - let command = format!( - "FOUNDRY_PROFILE=optimized forge script ../script/protocol/{}{}{}", - script_name, broadcast_deployment, gas_price - ); - for chain in provided_chains { - let deployment_command = format!("{} --rpc-url {}", command, chain); - - println!("Running the deployment command: {}", deployment_command); - - // Split the command into parts - let parts: Vec<&str> = deployment_command.split_whitespace().collect(); + let env_var = "FOUNDRY_PROFILE=optimized"; + let command = "forge"; + let script_arg = format!("../script/protocol/{}", script_name); + + let command_args = vec![ + "script", + &script_arg, + "--rpc-url", + &chain, + &broadcast_deployment, + &gas_price, + ]; + + println!( + "Running the deployment command: {} {} {}", + env_var, + command, + command_args.join(" ") + ); // Set the environment variable - let env_var = parts[0]; let env_var_parts: Vec<&str> = env_var.split('=').collect(); - std::env::set_var(env_var_parts[0], env_var_parts[1]); + env::set_var(env_var_parts[0], env_var_parts[1]); - // Define the command and arguments - let mut cmd = Command::new(parts[1]); - cmd.args(&parts[2..]); + // Create the CLI + let mut cmd = Command::new(command); + cmd.args(&command_args); // Capture the command output let output = cmd.output().expect("Failed to run command"); @@ -91,10 +98,57 @@ fn main() { if output.status.success() { let output_str = String::from_utf8_lossy(&output.stdout); println!("Command output: {}", output_str); + } else { + let error_str = String::from_utf8_lossy(&output.stderr); + eprintln!("Command failed with error: {}", error_str); + } + + if !broadcast_deployment.is_empty() { + move_broadcast_file( + &script_name, + &chain, + &String::from_utf8_lossy(&output.stdout), + ); } } } +fn move_broadcast_file(script_name: &str, chain: &str, output: &str) { + // Find the chain_id in the `output` + let chain_id = output + .split(&format!("broadcast/{}/", script_name)) + .nth(1) + .and_then(|s| s.split('/').next()) + .unwrap_or(""); + + let broadcast_file_path = format!( + "../broadcast/{}/{}/run-latest.json", + script_name, chain_id + ); + let version = serde_json::from_str::(&fs::read_to_string("../package.json").unwrap()) + .unwrap()["version"] + .as_str() + .unwrap() + .to_string(); + + // Up to be changed, see this: https://github.com/sablier-labs/v2-deployments/issues/10 + let destination_path = format!( + "../../v2-deployments/protocol/v{}/broadcasts/{}.json", + version, chain + ); + + // Create the parent directory if it doesn't exist + if let Some(parent) = Path::new(&destination_path).parent() { + if !parent.exists() { + fs::create_dir_all(parent).expect("Failed to create directories"); + } + } + + // Move and rename the file + fs::rename(&broadcast_file_path, &destination_path) + .expect("Failed to move and rename run-latest.json to v2-deployments"); +} + // Function that reads the TOML chain configurations and extracts them fn get_all_chains() -> Vec { // Define the path to the TOML file @@ -109,7 +163,7 @@ fn get_all_chains() -> Vec { } }; - let toml_values: Value = match toml::from_str(&toml_content) { + let toml_values: TomlValue = match toml::from_str(&toml_content) { Ok(value) => value, Err(_) => { eprintln!("Failed to parse TOML content"); diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index fc19455c1..2079c3fde 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -51,6 +51,11 @@ abstract contract ProtocolScript is BaseScript { // Set the deployment file path. deploymentFile = string.concat("deployments/", block.chainid.toString(), "_", deterministicOrNot, ".md"); + // TODO: if the file exists, first save a copy of it with a different name, then overwrite it. + // if (vm.isFile(deploymentFile)) { + // deploymentFile = string.concat(deploymentFile, ".md"); + // } + // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: deploymentFile, From e68671e196ca593441ba8b00a1bb46ae15f49542 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 8 Aug 2024 12:54:41 +0300 Subject: [PATCH 28/34] check wether the deployment is broadcasted in move_broadcast_file --- deploy-multi-chain/src/main.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index bb0ffe2f7..cbb78b973 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -12,6 +12,7 @@ fn main() { // Variables to store flags and provided chains let mut broadcast_deployment = "".to_string(); + let mut cp_broadcasted_file = false; let mut gas_price = "".to_string(); let mut script_name = "DeployProtocol.s.sol".to_string(); let mut on_all_chains = false; @@ -21,6 +22,7 @@ fn main() { while let Some(arg) = iter.next() { match arg.as_str() { "--all" => on_all_chains = true, + "--cp-bf" => cp_broadcasted_file = true, "--deterministic" => script_name = "DeployDeterministicProtocol.s.sol".to_string(), "--broadcast" => broadcast_deployment = " --broadcast --verify".to_string(), "--gas-price" => { @@ -103,17 +105,18 @@ fn main() { eprintln!("Command failed with error: {}", error_str); } - if !broadcast_deployment.is_empty() { + if cp_broadcasted_file { move_broadcast_file( &script_name, &chain, &String::from_utf8_lossy(&output.stdout), + &broadcast_deployment, ); } } } -fn move_broadcast_file(script_name: &str, chain: &str, output: &str) { +fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_deployment: &str) { // Find the chain_id in the `output` let chain_id = output .split(&format!("broadcast/{}/", script_name)) @@ -121,10 +124,15 @@ fn move_broadcast_file(script_name: &str, chain: &str, output: &str) { .and_then(|s| s.split('/').next()) .unwrap_or(""); - let broadcast_file_path = format!( - "../broadcast/{}/{}/run-latest.json", - script_name, chain_id - ); + let broadcast_file_path = if broadcast_deployment.is_empty() { + format!( + "../broadcast/{}/{}/dry-run/run-latest.json", + script_name, chain_id + ) + } else { + format!("../broadcast/{}/{}/run-latest.json", script_name, chain_id) + }; + let version = serde_json::from_str::(&fs::read_to_string("../package.json").unwrap()) .unwrap()["version"] .as_str() From 49b5be6d32027fd557e51c07598f995b14cbf46e Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Mon, 19 Aug 2024 14:36:43 +0300 Subject: [PATCH 29/34] feat: run prettier on deployment files fix: update factory name --- deploy-multi-chain/src/main.rs | 6 ++++++ .../protocol/DeployDeterministicProtocol.s.sol | 18 +++++++++++------- script/protocol/DeployProtocol.s.sol | 18 +++++++++++------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index cbb78b973..4090a89d4 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -114,6 +114,12 @@ fn main() { ); } } + + // Run Prettier to format the deployment files + let _ = Command::new("bun") + .args(["prettier", "--write", "../deployments/**/*.md"]) + .status() + .expect("Failed to run Prettier"); } fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_deployment: &str) { diff --git a/script/protocol/DeployDeterministicProtocol.s.sol b/script/protocol/DeployDeterministicProtocol.s.sol index 9b342eea5..626b5c4ca 100644 --- a/script/protocol/DeployDeterministicProtocol.s.sol +++ b/script/protocol/DeployDeterministicProtocol.s.sol @@ -5,7 +5,7 @@ import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; -import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { ProtocolScript } from "./Protocol.s.sol"; @@ -23,7 +23,7 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { address initialAdmin = adminMap[block.chainid]; @@ -33,7 +33,9 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { } /// @dev Deploys the protocol with the given `initialAdmin`. - function run(address initialAdmin) + function run( + address initialAdmin + ) internal returns ( LockupNFTDescriptor nftDescriptor, @@ -41,7 +43,7 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = @@ -49,7 +51,9 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { } /// @dev Common logic for the run functions. - function _run(address initialAdmin) + function _run( + address initialAdmin + ) internal returns ( LockupNFTDescriptor nftDescriptor, @@ -57,7 +61,7 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { bytes32 salt = constructCreate2Salt(); @@ -72,7 +76,7 @@ contract DeployDeterministicProtocol is ProtocolScript("deterministic") { // Deploy Periphery. batchLockup = new SablierBatchLockup{ salt: salt }(); - merkleLockupFactory = new SablierMerkleLockupFactory{ salt: salt }(); + merkleLockupFactory = new SablierMerkleFactory{ salt: salt }(); appendToFileDeployedAddresses( address(lockupDynamic), diff --git a/script/protocol/DeployProtocol.s.sol b/script/protocol/DeployProtocol.s.sol index 2b23358a7..286d2f4e7 100644 --- a/script/protocol/DeployProtocol.s.sol +++ b/script/protocol/DeployProtocol.s.sol @@ -5,7 +5,7 @@ import { LockupNFTDescriptor } from "../../src/core/LockupNFTDescriptor.sol"; import { SablierLockupDynamic } from "../../src/core/SablierLockupDynamic.sol"; import { SablierLockupLinear } from "../../src/core/SablierLockupLinear.sol"; import { SablierLockupTranched } from "../../src/core/SablierLockupTranched.sol"; -import { SablierMerkleLockupFactory } from "../../src/periphery/SablierMerkleLockupFactory.sol"; +import { SablierMerkleFactory } from "../../src/periphery/SablierMerkleFactory.sol"; import { SablierBatchLockup } from "../../src/periphery/SablierBatchLockup.sol"; import { ProtocolScript } from "./Protocol.s.sol"; @@ -23,7 +23,7 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { address initialAdmin = adminMap[block.chainid]; @@ -33,7 +33,9 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { } /// @dev Deploys the protocol with the given `initialAdmin`. - function run(address initialAdmin) + function run( + address initialAdmin + ) internal returns ( LockupNFTDescriptor nftDescriptor, @@ -41,7 +43,7 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleLockupFactory) = @@ -49,7 +51,9 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { } /// @dev Common logic for the run functions. - function _run(address initialAdmin) + function _run( + address initialAdmin + ) internal returns ( LockupNFTDescriptor nftDescriptor, @@ -57,7 +61,7 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { SablierLockupLinear lockupLinear, SablierLockupTranched lockupTranched, SablierBatchLockup batchLockup, - SablierMerkleLockupFactory merkleLockupFactory + SablierMerkleFactory merkleLockupFactory ) { nftDescriptor = new LockupNFTDescriptor(); @@ -65,7 +69,7 @@ contract DeployProtocol is ProtocolScript("non_deterministic") { lockupLinear = new SablierLockupLinear(initialAdmin, nftDescriptor); lockupTranched = new SablierLockupTranched(initialAdmin, nftDescriptor, trancheCountMap[block.chainid]); batchLockup = new SablierBatchLockup(); - merkleLockupFactory = new SablierMerkleLockupFactory(); + merkleLockupFactory = new SablierMerkleFactory(); appendToFileDeployedAddresses( address(lockupDynamic), From 80121e0a3fa0a79f1ba3a8ffe7f748f2e9da8cd2 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 21 Aug 2024 19:05:56 +0300 Subject: [PATCH 30/34] feat: add chain name map feat: create the deployments if it doesn't exists feat: backup previous deployments files using the timestamp --- deploy-multi-chain/src/main.rs | 120 ++++++++++++++++++++++----------- script/protocol/Protocol.s.sol | 62 +++++++++++------ 2 files changed, 124 insertions(+), 58 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index 4090a89d4..c1f481918 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -3,6 +3,7 @@ use std::env; use std::fs; use std::path::Path; use std::process::Command; +use std::time::{SystemTime, UNIX_EPOCH}; use toml::Value as TomlValue; fn main() { @@ -14,6 +15,7 @@ fn main() { let mut broadcast_deployment = "".to_string(); let mut cp_broadcasted_file = false; let mut gas_price = "".to_string(); + let mut is_deterministic = false; let mut script_name = "DeployProtocol.s.sol".to_string(); let mut on_all_chains = false; let mut provided_chains = Vec::new(); @@ -23,7 +25,10 @@ fn main() { match arg.as_str() { "--all" => on_all_chains = true, "--cp-bf" => cp_broadcasted_file = true, - "--deterministic" => script_name = "DeployDeterministicProtocol.s.sol".to_string(), + "--deterministic" => { + script_name = "DeployDeterministicProtocol.s.sol".to_string(); + is_deterministic = true; + } "--broadcast" => broadcast_deployment = " --broadcast --verify".to_string(), "--gas-price" => { let value = iter.next().expect("gas price value").to_string(); @@ -64,6 +69,20 @@ fn main() { let chains_string = provided_chains.clone().join(", "); println!("Deploying to the chains: {}", chains_string); + let deployment_path = get_deployment_path(is_deterministic, false); + + // Create the parent directory if it doesn't exist + if let Some(parent) = Path::new(&deployment_path).parent() { + if parent.exists() { + _ = fs::copy( + &deployment_path, + get_deployment_path(is_deterministic, true), + ); + } + + fs::create_dir_all(parent).expect("Failed to create directories"); + } + for chain in provided_chains { let env_var = "FOUNDRY_PROFILE=optimized"; let command = "forge"; @@ -122,6 +141,64 @@ fn main() { .expect("Failed to run Prettier"); } +// Function that reads the TOML chain configurations and extracts them +fn get_all_chains() -> Vec { + // Define the path to the TOML file + let toml_path = Path::new("../foundry.toml"); + + // Read and parse the TOML file content + let toml_content = match fs::read_to_string(toml_path) { + Ok(content) => content, + Err(_) => { + eprintln!("Failed to read the TOML file"); + return Vec::new(); + } + }; + + let toml_values: TomlValue = match toml::from_str(&toml_content) { + Ok(value) => value, + Err(_) => { + eprintln!("Failed to parse TOML content"); + return Vec::new(); + } + }; + + // Extract chains from the TOML data + let sections = ["rpc_endpoints", "etherscan"]; + let mut chains = Vec::new(); + + for section in §ions { + if let Some(table) = toml_values.get(section).and_then(|v| v.as_table()) { + chains.extend(table.keys().filter(|&key| key != "localhost").cloned()); + } + } + + chains.into_iter().collect() +} + +fn get_deployment_path(is_deterministic: bool, with_timestamp: bool) -> String { + let mut deployment_path = if is_deterministic { + "../deployments/deterministic.md".to_string() + } else { + "../deployments/non_deterministic.md".to_string() + }; + + if with_timestamp { + // Get the current Unix timestamp as a string + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs() + .to_string(); + + // Insert the timestamp before the filename + let filename_start = deployment_path.rfind('/').unwrap() + 1; + deployment_path.insert_str(filename_start, &format!("{}_{}", timestamp, "")); + } + + deployment_path +} + fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_deployment: &str) { // Find the chain_id in the `output` let chain_id = output @@ -146,54 +223,19 @@ fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_d .to_string(); // Up to be changed, see this: https://github.com/sablier-labs/v2-deployments/issues/10 - let destination_path = format!( + let dest_path = format!( "../../v2-deployments/protocol/v{}/broadcasts/{}.json", version, chain ); // Create the parent directory if it doesn't exist - if let Some(parent) = Path::new(&destination_path).parent() { + if let Some(parent) = Path::new(&dest_path).parent() { if !parent.exists() { fs::create_dir_all(parent).expect("Failed to create directories"); } } // Move and rename the file - fs::rename(&broadcast_file_path, &destination_path) + fs::rename(&broadcast_file_path, &dest_path) .expect("Failed to move and rename run-latest.json to v2-deployments"); } - -// Function that reads the TOML chain configurations and extracts them -fn get_all_chains() -> Vec { - // Define the path to the TOML file - let toml_path = Path::new("../foundry.toml"); - - // Read and parse the TOML file content - let toml_content = match fs::read_to_string(toml_path) { - Ok(content) => content, - Err(_) => { - eprintln!("Failed to read the TOML file"); - return Vec::new(); - } - }; - - let toml_values: TomlValue = match toml::from_str(&toml_content) { - Ok(value) => value, - Err(_) => { - eprintln!("Failed to parse TOML content"); - return Vec::new(); - } - }; - - // Extract chains from the TOML data - let sections = ["rpc_endpoints", "etherscan"]; - let mut chains = Vec::new(); - - for section in §ions { - if let Some(table) = toml_values.get(section).and_then(|v| v.as_table()) { - chains.extend(table.keys().filter(|&key| key != "localhost").cloned()); - } - } - - chains.into_iter().collect() -} diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 2079c3fde..15ce2850c 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -20,6 +20,9 @@ abstract contract ProtocolScript is BaseScript { /// @dev Admin address mapped by the chain Id. mapping(uint256 chainId => address admin) internal adminMap; + /// @dev Chain names mapped by the chain Id. + mapping(uint256 chainId => string name) internal nameMap; + /// @dev Explorer URL mapped by the chain Id. mapping(uint256 chainId => string explorerUrl) internal explorerMap; @@ -27,6 +30,9 @@ abstract contract ProtocolScript is BaseScript { // Populate the admin map. populateAdminMap(); + // Populate the chain name map. + populateChainNameMap(); + // Populate the explorer URLs. populateExplorerMap(); @@ -40,27 +46,11 @@ abstract contract ProtocolScript is BaseScript { explorerMap[block.chainid] = ""; } - // Create the deployment directory if it doesn't exist. This requires `--ffi` flag. - if (!vm.isDir("deployments")) { - string[] memory mkDirCommand = new string[](2); - mkDirCommand[0] = "mkdir"; - mkDirCommand[1] = "deployments"; - vm.ffi(mkDirCommand); - } - // Set the deployment file path. - deploymentFile = string.concat("deployments/", block.chainid.toString(), "_", deterministicOrNot, ".md"); + deploymentFile = string.concat("deployments/", deterministicOrNot, ".md"); - // TODO: if the file exists, first save a copy of it with a different name, then overwrite it. - // if (vm.isFile(deploymentFile)) { - // deploymentFile = string.concat(deploymentFile, ".md"); - // } - - // Create the file if it doesn't exist, otherwise overwrite it. - vm.writeFile({ - path: deploymentFile, - data: string.concat("# Deployed Addresses for chain ", block.chainid.toString(), "\n\n") - }); + // Create the file . + vm.writeFile({ path: deploymentFile, data: string.concat("# ", nameMap[block.chainid], "\n\n") }); } /// @dev Function to append the deployed addresses to the deployment file. @@ -178,12 +168,42 @@ abstract contract ProtocolScript is BaseScript { adminMap[534_352] = 0x0F7Ad835235Ede685180A5c611111610813457a9; // Scroll } + /// @dev Populates the chain name map. + function populateChainNameMap() internal { + nameMap[42_161] = "Arbitrum"; + nameMap[43_114] = "Avalanche"; + nameMap[8453] = "Base"; + nameMap[84_532] = "Base Sepolia"; + nameMap[80_084] = "Berachain Bartio"; + nameMap[81_457] = "Blast"; + nameMap[168_587_773] = "Blast Sepolia"; + nameMap[56] = "BNB Smart Chain"; + nameMap[100] = "Gnosis"; + nameMap[1890] = "Lightlink"; + nameMap[59_144] = "Linea"; + nameMap[59_141] = "Linea Sepolia"; + nameMap[1] = "Mainnet"; + nameMap[333_000_333] = "Meld"; + nameMap[34_443] = "Mode"; + nameMap[919] = "Mode Sepolia"; + nameMap[2810] = "Morph Holesky"; + nameMap[10] = "Optimism"; + nameMap[11_155_420] = "Optimism Sepolia"; + nameMap[137] = "Polygon"; + nameMap[534_352] = "Scroll"; + nameMap[11_155_111] = "Sepolia"; + nameMap[53_302] = "Superseed Sepolia"; + nameMap[167_009] = "Taiko Hekla"; + nameMap[167_000] = "Taiko Mainnet"; + } + /// @dev Populates the explorer map. function populateExplorerMap() internal { explorerMap[42_161] = "https://arbiscan.io/address/"; explorerMap[43_114] = "https://snowtrace.io/address/"; explorerMap[8453] = "https://basescan.org/address/"; explorerMap[84_532] = "https://sepolia.basescan.org/address/"; + explorerMap[80_084] = "https://bartio.beratrail.io/address/"; explorerMap[81_457] = "https://blastscan.io/address/"; explorerMap[168_587_773] = "https://sepolia.blastscan.io/address/"; explorerMap[56] = "https://bscscan.com/address/"; @@ -194,11 +214,15 @@ abstract contract ProtocolScript is BaseScript { explorerMap[1890] = "https://phoenix.lightlink.io/address/"; explorerMap[34_443] = "https://explorer.mode.network/address/"; explorerMap[919] = "https://sepolia.explorer.mode.network/address/"; + explorerMap[2810] = "https://explorer-holesky.morphl2.io/address/"; explorerMap[333_000_333] = "https://meldscan.io/address/"; explorerMap[10] = "https://optimistic.etherscan.io/address/"; explorerMap[11_155_420] = "https://sepolia-optimistic.etherscan.io/address/"; explorerMap[137] = "https://polygonscan.com/address/"; explorerMap[534_352] = "https://scrollscan.com/address/"; explorerMap[11_155_111] = "https://sepolia.etherscan.io/address/"; + explorerMap[53_302] = "https://sepolia-explorer.superseed.xyz/address/"; + explorerMap[167_009] = "https://explorer.hekla.taiko.xyz/address/"; + explorerMap[167_000] = "https://taikoscan.io/address/"; } } From d011e43cc5ed3352905eee5db716842f693138b3 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Wed, 21 Aug 2024 19:24:37 +0300 Subject: [PATCH 31/34] feat: write in the deployment file its type --- deploy-multi-chain/src/main.rs | 32 +++++++++++++++++++++++++++++--- script/protocol/Protocol.s.sol | 4 ++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index c1f481918..6fa8a5508 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -1,6 +1,8 @@ use serde_json::Value; use std::env; use std::fs; +use std::fs::OpenOptions; +use std::io::Write; use std::path::Path; use std::process::Command; use std::time::{SystemTime, UNIX_EPOCH}; @@ -83,6 +85,9 @@ fn main() { fs::create_dir_all(parent).expect("Failed to create directories"); } + // Append the type of deployment at the start of the deployment file + append_type_of_deployment(&deployment_path, broadcast_deployment.is_empty()); + for chain in provided_chains { let env_var = "FOUNDRY_PROFILE=optimized"; let command = "forge"; @@ -129,7 +134,7 @@ fn main() { &script_name, &chain, &String::from_utf8_lossy(&output.stdout), - &broadcast_deployment, + broadcast_deployment.is_empty(), ); } } @@ -141,6 +146,22 @@ fn main() { .expect("Failed to run Prettier"); } +fn append_type_of_deployment(deployment_path: &str, is_broadcast_deployment: bool) { + let message = if is_broadcast_deployment { + " # This is a deployment simulation\n\n\n" + } else { + " # This deployment is broadcasted\n" + }; + + OpenOptions::new() + .append(true) + .create(true) + .open(deployment_path) + .expect("Failed to open the file") + .write_all(message.as_bytes()) + .expect("Failed to write to the file"); +} + // Function that reads the TOML chain configurations and extracts them fn get_all_chains() -> Vec { // Define the path to the TOML file @@ -199,7 +220,12 @@ fn get_deployment_path(is_deterministic: bool, with_timestamp: bool) -> String { deployment_path } -fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_deployment: &str) { +fn move_broadcast_file( + script_name: &str, + chain: &str, + output: &str, + is_broadcast_deployment: bool, +) { // Find the chain_id in the `output` let chain_id = output .split(&format!("broadcast/{}/", script_name)) @@ -207,7 +233,7 @@ fn move_broadcast_file(script_name: &str, chain: &str, output: &str, broadcast_d .and_then(|s| s.split('/').next()) .unwrap_or(""); - let broadcast_file_path = if broadcast_deployment.is_empty() { + let broadcast_file_path = if is_broadcast_deployment { format!( "../broadcast/{}/{}/dry-run/run-latest.json", script_name, chain_id diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 15ce2850c..98ab67f54 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -49,8 +49,8 @@ abstract contract ProtocolScript is BaseScript { // Set the deployment file path. deploymentFile = string.concat("deployments/", deterministicOrNot, ".md"); - // Create the file . - vm.writeFile({ path: deploymentFile, data: string.concat("# ", nameMap[block.chainid], "\n\n") }); + // Append the chain name to the deployment file. + _appendToFile(string.concat("# ", nameMap[block.chainid], "\n\n")); } /// @dev Function to append the deployed addresses to the deployment file. From 6697736da74ea53ad8430a4e2a5591294604f843 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 22 Aug 2024 13:38:15 +0300 Subject: [PATCH 32/34] fix: the file creation if it already exists fix: handle non-set nameMap for unknown chain id --- deploy-multi-chain/src/main.rs | 58 +++++++++++------------ script/protocol/Protocol.s.sol | 85 ++++++++++++++++++---------------- 2 files changed, 74 insertions(+), 69 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index 6fa8a5508..9286347e9 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -73,16 +73,16 @@ fn main() { let deployment_path = get_deployment_path(is_deterministic, false); - // Create the parent directory if it doesn't exist - if let Some(parent) = Path::new(&deployment_path).parent() { - if parent.exists() { - _ = fs::copy( - &deployment_path, - get_deployment_path(is_deterministic, true), - ); - } - - fs::create_dir_all(parent).expect("Failed to create directories"); + // Check if the deployment file exists + if Path::new(&deployment_path).exists() { + // Move the existing file to a new path with timestamp + _ = fs::rename( + &deployment_path, + get_deployment_path(is_deterministic, true), + ); + } else { + // Create the parent directory + _ = fs::create_dir_all(Path::new(&deployment_path).parent().unwrap()); } // Append the type of deployment at the start of the deployment file @@ -113,53 +113,53 @@ fn main() { let env_var_parts: Vec<&str> = env_var.split('=').collect(); env::set_var(env_var_parts[0], env_var_parts[1]); - // Create the CLI - let mut cmd = Command::new(command); - cmd.args(&command_args); - - // Capture the command output - let output = cmd.output().expect("Failed to run command"); + // Create the CLI and capture the command output + let output = Command::new(command) + .args(command_args) + .output() + .expect("Failed to run command"); - // Check if the command executed successfully + // Process command output + let output_str = String::from_utf8_lossy(&output.stdout); if output.status.success() { - let output_str = String::from_utf8_lossy(&output.stdout); println!("Command output: {}", output_str); } else { - let error_str = String::from_utf8_lossy(&output.stderr); - eprintln!("Command failed with error: {}", error_str); + eprintln!( + "Command failed with error: {}", + String::from_utf8_lossy(&output.stderr) + ); } + // Move broadcast file if needed if cp_broadcasted_file { move_broadcast_file( &script_name, &chain, - &String::from_utf8_lossy(&output.stdout), + &output_str, broadcast_deployment.is_empty(), ); } } // Run Prettier to format the deployment files - let _ = Command::new("bun") + _ = Command::new("bun") .args(["prettier", "--write", "../deployments/**/*.md"]) .status() .expect("Failed to run Prettier"); } fn append_type_of_deployment(deployment_path: &str, is_broadcast_deployment: bool) { - let message = if is_broadcast_deployment { - " # This is a deployment simulation\n\n\n" - } else { - " # This deployment is broadcasted\n" + let message = match is_broadcast_deployment { + true => " # This deployment is a simulation\n\n", + false => " # This deployment is broadcasted\n\n", }; OpenOptions::new() .append(true) .create(true) .open(deployment_path) - .expect("Failed to open the file") - .write_all(message.as_bytes()) - .expect("Failed to write to the file"); + .and_then(|mut file| file.write_all(message.as_bytes())) + .expect("Failed to open or write to the file"); } // Function that reads the TOML chain configurations and extracts them diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 98ab67f54..4ff822e53 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -20,12 +20,12 @@ abstract contract ProtocolScript is BaseScript { /// @dev Admin address mapped by the chain Id. mapping(uint256 chainId => address admin) internal adminMap; - /// @dev Chain names mapped by the chain Id. - mapping(uint256 chainId => string name) internal nameMap; - /// @dev Explorer URL mapped by the chain Id. mapping(uint256 chainId => string explorerUrl) internal explorerMap; + /// @dev Chain names mapped by the chain Id. + mapping(uint256 chainId => string name) internal nameMap; + constructor(string memory deterministicOrNot) { // Populate the admin map. populateAdminMap(); @@ -46,6 +46,11 @@ abstract contract ProtocolScript is BaseScript { explorerMap[block.chainid] = ""; } + // If there is no chain name set for a specific chain, use the chain ID. + if (nameMap[block.chainid].equal("")) { + nameMap[block.chainid] = block.chainid.toString(); + } + // Set the deployment file path. deploymentFile = string.concat("deployments/", deterministicOrNot, ".md"); @@ -117,43 +122,6 @@ abstract contract ProtocolScript is BaseScript { _appendToFile(merkleFactoryLine); } - /// @dev Append a line to the deployment file path. - function _appendToFile(string memory line) private { - vm.writeLine({ path: deploymentFile, data: line }); - } - - function _getContractLine( - string memory contractName, - string memory contractAddress, - string memory coreOrPeriphery - ) - private - view - returns (string memory) - { - string memory version = getVersion(); - version = string.concat("v", version); - - return string.concat( - "| ", - contractName, - " | [", - contractAddress, - "](", - explorerMap[block.chainid], - contractAddress, - ") | [", - coreOrPeriphery, - "-", - version, - "](https://github.com/sablier-labs/v2-deployments/tree/main/", - coreOrPeriphery, - "/", - version, - ") |" - ); - } - /// @dev Populates the admin map. function populateAdminMap() internal { adminMap[42_161] = 0xF34E41a6f6Ce5A45559B1D3Ee92E141a3De96376; // Arbitrum @@ -225,4 +193,41 @@ abstract contract ProtocolScript is BaseScript { explorerMap[167_009] = "https://explorer.hekla.taiko.xyz/address/"; explorerMap[167_000] = "https://taikoscan.io/address/"; } + + /// @dev Append a line to the deployment file path. + function _appendToFile(string memory line) private { + vm.writeLine({ path: deploymentFile, data: line }); + } + + function _getContractLine( + string memory contractName, + string memory contractAddress, + string memory coreOrPeriphery + ) + private + view + returns (string memory) + { + string memory version = getVersion(); + version = string.concat("v", version); + + return string.concat( + "| ", + contractName, + " | [", + contractAddress, + "](", + explorerMap[block.chainid], + contractAddress, + ") | [", + coreOrPeriphery, + "-", + version, + "](https://github.com/sablier-labs/v2-deployments/tree/main/", + coreOrPeriphery, + "/", + version, + ") |" + ); + } } From 5d314f8604bb53144bc7aea281fe6fdcf52d6037 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 22 Aug 2024 14:34:42 +0300 Subject: [PATCH 33/34] docs: polish natspec in Protocol.s.sol --- script/protocol/Protocol.s.sol | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/script/protocol/Protocol.s.sol b/script/protocol/Protocol.s.sol index 4ff822e53..c8e0a0dbc 100644 --- a/script/protocol/Protocol.s.sol +++ b/script/protocol/Protocol.s.sol @@ -6,8 +6,9 @@ import { stdJson } from "forge-std/src/StdJson.sol"; import { BaseScript } from "../Base.s.sol"; -/// @dev This contract creates a Markdown file with the deployed addresses with the format used in docs: -/// https://docs.sablier.com/contracts/v2/deployments +/// @dev This contract appends to a Markdown file, which is assumed to be already created at the `deploymentFile` path, +/// the deployed addresses in the format used in the docs: https://docs.sablier.com/contracts/v2/deployments. +/// This script is intended to be used in `deploy-multi-chain/src/main.rs`. abstract contract ProtocolScript is BaseScript { using stdJson for string; using Strings for address; @@ -199,6 +200,7 @@ abstract contract ProtocolScript is BaseScript { vm.writeLine({ path: deploymentFile, data: line }); } + /// @dev Returns a string for a single contract line formatted according to the docs. function _getContractLine( string memory contractName, string memory contractAddress, From 181543d71b8c384dcfd07fdf8113d35665e409d2 Mon Sep 17 00:00:00 2001 From: andreivladbrg Date: Thu, 22 Aug 2024 16:56:38 +0300 Subject: [PATCH 34/34] fix: pass correctly the is_broadcast_deployment bool --- deploy-multi-chain/src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/deploy-multi-chain/src/main.rs b/deploy-multi-chain/src/main.rs index 9286347e9..84190c596 100644 --- a/deploy-multi-chain/src/main.rs +++ b/deploy-multi-chain/src/main.rs @@ -86,7 +86,7 @@ fn main() { } // Append the type of deployment at the start of the deployment file - append_type_of_deployment(&deployment_path, broadcast_deployment.is_empty()); + append_type_of_deployment(&deployment_path, !broadcast_deployment.is_empty()); for chain in provided_chains { let env_var = "FOUNDRY_PROFILE=optimized"; @@ -136,7 +136,7 @@ fn main() { &script_name, &chain, &output_str, - broadcast_deployment.is_empty(), + !broadcast_deployment.is_empty(), ); } } @@ -150,8 +150,8 @@ fn main() { fn append_type_of_deployment(deployment_path: &str, is_broadcast_deployment: bool) { let message = match is_broadcast_deployment { - true => " # This deployment is a simulation\n\n", - false => " # This deployment is broadcasted\n\n", + true => " # This deployment is broadcasted\n\n", + false => " # This deployment is a simulation\n\n", }; OpenOptions::new() @@ -234,12 +234,12 @@ fn move_broadcast_file( .unwrap_or(""); let broadcast_file_path = if is_broadcast_deployment { + format!("../broadcast/{}/{}/run-latest.json", script_name, chain_id) + } else { format!( "../broadcast/{}/{}/dry-run/run-latest.json", script_name, chain_id ) - } else { - format!("../broadcast/{}/{}/run-latest.json", script_name, chain_id) }; let version = serde_json::from_str::(&fs::read_to_string("../package.json").unwrap())