diff --git a/README.md b/README.md index d16a25a46..c0e3d0c04 100644 --- a/README.md +++ b/README.md @@ -71,10 +71,10 @@ This is just a glimpse of Sablier Lockup. For more guides and examples, see the [documentation](https://docs.sablier.com). ```solidity -import { ISablierLockupLinear } from "@sablier/lockup/src/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockup } from "@sablier/lockup/src/interfaces/ISablierLockup.sol"; contract MyContract { - ISablierLockupLinear lockup; + ISablierLockup lockup; function buildSomethingWithSablier() external { // ... @@ -84,9 +84,9 @@ contract MyContract { ## Architecture -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. +Lockup uses a singleton-style architecture, where all streams are managed in the `SablierLockup` contract. That is, +Sablier does not deploy a new contract for each distribution model or stream. It bundles all streams into a single +contract, which is more gas-efficient and easier to maintain. For more information, see the [Technical Overview](https://docs.sablier.com/contracts/v2/reference/overview) in our docs, as well as these [diagrams](https://docs.sablier.com/contracts/v2/reference/diagrams). diff --git a/benchmark/BatchLockup.Gas.t.sol b/benchmark/BatchLockup.Gas.t.sol index 2ab0baedf..0fd048d53 100644 --- a/benchmark/BatchLockup.Gas.t.sol +++ b/benchmark/BatchLockup.Gas.t.sol @@ -85,8 +85,8 @@ contract BatchLockup_Gas_Test is Benchmark_Test { function gasCreateWithTimestampsLD(uint256 batchSize, uint256 segmentsCount) internal { Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNull(); LockupDynamic.Segment[] memory segments = _generateSegments(segmentsCount); - createParams.startTime = getBlockTimestamp(); - createParams.endTime = segments[segments.length - 1].timestamp; + createParams.timestamps.start = getBlockTimestamp(); + createParams.timestamps.end = segments[segments.length - 1].timestamp; createParams.totalAmount = uint128(AMOUNT_PER_ITEM * segmentsCount); BatchLockup.CreateWithTimestampsLD[] memory params = BatchLockupBuilder.fillBatch(createParams, segments, batchSize); @@ -131,7 +131,7 @@ contract BatchLockup_Gas_Test is Benchmark_Test { function gasCreateWithTimestampsLL(uint256 batchSize) internal { BatchLockup.CreateWithTimestampsLL[] memory params = BatchLockupBuilder.fillBatch({ params: defaults.createWithTimestampsBrokerNull(), - cliff: defaults.CLIFF_TIME(), + cliffTime: defaults.CLIFF_TIME(), batchSize: batchSize }); @@ -175,8 +175,8 @@ contract BatchLockup_Gas_Test is Benchmark_Test { function gasCreateWithTimestampsLT(uint256 batchSize, uint256 tranchesCount) internal { Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNull(); LockupTranched.Tranche[] memory tranches = _generateTranches(tranchesCount); - createParams.startTime = getBlockTimestamp(); - createParams.endTime = tranches[tranches.length - 1].timestamp; + createParams.timestamps.start = getBlockTimestamp(); + createParams.timestamps.end = tranches[tranches.length - 1].timestamp; createParams.totalAmount = uint128(AMOUNT_PER_ITEM * tranchesCount); BatchLockup.CreateWithTimestampsLT[] memory params = BatchLockupBuilder.fillBatch(createParams, tranches, batchSize); diff --git a/benchmark/EstimateMaxCount.t.sol b/benchmark/EstimateMaxCount.t.sol index a5f90d7a1..854d966a8 100644 --- a/benchmark/EstimateMaxCount.t.sol +++ b/benchmark/EstimateMaxCount.t.sol @@ -5,7 +5,6 @@ import { console2 } from "forge-std/src/console2.sol"; import { Test } from "forge-std/src/Test.sol"; import { Lockup_Dynamic_Gas_Test } from "./LockupDynamic.Gas.t.sol"; -import { Lockup_Tranched_Gas_Test } from "./LockupTranched.Gas.t.sol"; /// @notice Structure to group the block gas limit and chain id. struct ChainInfo { @@ -62,30 +61,4 @@ contract EstimateMaxCount is Test { console2.log("count: %d and gasUsed: %d and chainId: %d", count, lastGasConsumed, chains[i].chainId); } } - - /// @notice Estimate the maximum number of tranches allowed in LockupTranched. - function test_EstimateTranches() public { - Lockup_Tranched_Gas_Test lockupTranchedGasTest = new Lockup_Tranched_Gas_Test(); - lockupTranchedGasTest.setUp(); - - for (uint256 i = 0; i < chains.length; ++i) { - uint128 count = INITIAL_GUESS; - - // Subtract `BUFFER_GAS` from `blockGasLimit` as an additional precaution to account for the dynamic gas for - // ether transfer on different chains. - uint256 blockGasLimit = chains[i].blockGasLimit - BUFFER_GAS; - - uint256 gasConsumed = 0; - uint256 lastGasConsumed = 0; - while (blockGasLimit > gasConsumed) { - count += 10; - lastGasConsumed = gasConsumed; - - // Estimate the gas consumed by adding 10 tranches. - gasConsumed = lockupTranchedGasTest.computeGas_CreateWithDurationsLT(count + 10); - } - - console2.log("count: %d and gasUsed: %d and chainId: %d", count, lastGasConsumed, chains[i].chainId); - } - } } diff --git a/benchmark/LockupDynamic.Gas.t.sol b/benchmark/LockupDynamic.Gas.t.sol index b528d9cbc..d9df3478f 100644 --- a/benchmark/LockupDynamic.Gas.t.sol +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -38,7 +38,7 @@ contract Lockup_Dynamic_Gas_Test is Benchmark_Test { vm.writeFile({ path: benchmarkResultsFile, data: string.concat( - "# Benchmarks for Lockup Dynamic\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + "# Benchmarks for Lockup Dynamic Model\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" ) }); @@ -224,8 +224,8 @@ contract Lockup_Dynamic_Gas_Test is Benchmark_Test { params = defaults.createWithTimestamps(); params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); - params.startTime = getBlockTimestamp(); - params.endTime = segments_[totalSegments - 1].timestamp; + params.timestamps.start = getBlockTimestamp(); + params.timestamps.end = segments_[totalSegments - 1].timestamp; params.broker.fee = brokerFee; return (params, segments_); } diff --git a/benchmark/LockupLinear.Gas.t.sol b/benchmark/LockupLinear.Gas.t.sol index b4f9af45a..4d1e8b73b 100644 --- a/benchmark/LockupLinear.Gas.t.sol +++ b/benchmark/LockupLinear.Gas.t.sol @@ -21,7 +21,9 @@ contract Lockup_Linear_Gas_Test is Benchmark_Test { // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: benchmarkResultsFile, - data: string.concat("# Benchmarks for Lockup Linear\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") + data: string.concat( + "# Benchmarks for Lockup Linear Model\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + ) }); vm.warp({ newTimestamp: defaults.END_TIME() }); diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol index cbedc39a4..42cae278f 100644 --- a/benchmark/LockupTranched.Gas.t.sol +++ b/benchmark/LockupTranched.Gas.t.sol @@ -29,7 +29,7 @@ contract Lockup_Tranched_Gas_Test is Benchmark_Test { vm.writeFile({ path: benchmarkResultsFile, data: string.concat( - "# Benchmarks for Lockup Tranched\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + "# Benchmarks for Lockup Tranched Model\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" ) }); @@ -207,8 +207,8 @@ contract Lockup_Tranched_Gas_Test is Benchmark_Test { params = defaults.createWithTimestamps(); params.broker.fee = brokerFee; - params.startTime = getBlockTimestamp(); - params.endTime = tranches_[totalTranches - 1].timestamp; + params.timestamps.start = getBlockTimestamp(); + params.timestamps.end = tranches_[totalTranches - 1].timestamp; params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); return (params, tranches_); } diff --git a/benchmark/results/SablierBatchLockup.md b/benchmark/results/SablierBatchLockup.md index 8bb8db383..3a154f1dd 100644 --- a/benchmark/results/SablierBatchLockup.md +++ b/benchmark/results/SablierBatchLockup.md @@ -2,33 +2,33 @@ | Function | Lockup Type | Segments/Tranches | Batch Size | Gas Usage | | ------------------------ | --------------- | ----------------- | ---------- | --------- | -| `createWithDurationsLL` | Lockup Linear | N/A | 5 | 779252 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 5 | 737531 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 5 | 4119940 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 5 | 3888761 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 5 | 3995338 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 5 | 3804250 | -| `createWithDurationsLL` | Lockup Linear | N/A | 10 | 1425098 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 10 | 1424116 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 10 | 8190322 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 10 | 7728484 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 10 | 7938702 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 10 | 7559817 | -| `createWithDurationsLL` | Lockup Linear | N/A | 20 | 2799677 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 20 | 2798898 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 20 | 16351825 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 20 | 15412578 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 20 | 15824057 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 20 | 15075556 | -| `createWithDurationsLL` | Lockup Linear | N/A | 30 | 4168931 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 30 | 4177876 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 30 | 24550618 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 30 | 23110560 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 30 | 23709058 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 30 | 22605337 | -| `createWithDurationsLL` | Lockup Linear | N/A | 50 | 6914041 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 50 | 6941746 | -| `createWithDurationsLD` | Lockup Dynamic | 12 | 50 | 24037239 | -| `createWithTimestampsLD` | Lockup Dynamic | 12 | 50 | 22827992 | -| `createWithDurationsLT` | Lockup Tranched | 12 | 50 | 23314745 | -| `createWithTimestampsLT` | Lockup Tranched | 12 | 50 | 22415432 | +| `createWithDurationsLL` | Lockup Linear | N/A | 5 | 778232 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 5 | 738090 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 5 | 4117172 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 5 | 3887412 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 5 | 3993178 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 5 | 3806069 | +| `createWithDurationsLL` | Lockup Linear | N/A | 10 | 1423058 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 10 | 1425240 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 10 | 8189792 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 10 | 7725792 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 10 | 7934383 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 10 | 7563478 | +| `createWithDurationsLL` | Lockup Linear | N/A | 20 | 2795598 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 20 | 2801161 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 20 | 16350772 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 20 | 15407205 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 20 | 15815419 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 20 | 15082887 | +| `createWithDurationsLL` | Lockup Linear | N/A | 30 | 4162811 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 30 | 4181289 | +| `createWithDurationsLD` | Lockup Dynamic | 24 | 30 | 24549048 | +| `createWithTimestampsLD` | Lockup Dynamic | 24 | 30 | 23102525 | +| `createWithDurationsLT` | Lockup Tranched | 24 | 30 | 23696100 | +| `createWithTimestampsLT` | Lockup Tranched | 24 | 30 | 22616357 | +| `createWithDurationsLL` | Lockup Linear | N/A | 50 | 6903841 | +| `createWithTimestampsLL` | Lockup Linear | N/A | 50 | 6947495 | +| `createWithDurationsLD` | Lockup Dynamic | 12 | 50 | 24028066 | +| `createWithTimestampsLD` | Lockup Dynamic | 12 | 50 | 22808040 | +| `createWithDurationsLT` | Lockup Tranched | 12 | 50 | 23292554 | +| `createWithTimestampsLT` | Lockup Tranched | 12 | 50 | 22433243 | diff --git a/benchmark/results/SablierLockup_Dynamic.md b/benchmark/results/SablierLockup_Dynamic.md index 43b56f6a9..3d5bce19c 100644 --- a/benchmark/results/SablierLockup_Dynamic.md +++ b/benchmark/results/SablierLockup_Dynamic.md @@ -1,31 +1,31 @@ -# Benchmarks for Lockup Dynamic +# Benchmarks for Lockup Dynamic Model | Implementation | Gas Usage | | ------------------------------------------------------------ | --------- | -| `burn` | 15737 | -| `cancel` | 69877 | -| `renounce` | 37913 | -| `createWithDurationsLD` (2 segments) (Broker fee set) | 211048 | -| `createWithDurationsLD` (2 segments) (Broker fee not set) | 194992 | -| `createWithTimestampsLD` (2 segments) (Broker fee set) | 191907 | -| `createWithTimestampsLD` (2 segments) (Broker fee not set) | 187158 | -| `withdraw` (2 segments) (After End Time) (by Recipient) | 19081 | -| `withdraw` (2 segments) (Before End Time) (by Recipient) | 28414 | -| `withdraw` (2 segments) (After End Time) (by Anyone) | 14337 | -| `withdraw` (2 segments) (Before End Time) (by Anyone) | 28470 | -| `createWithDurationsLD` (10 segments) (Broker fee set) | 418495 | -| `createWithDurationsLD` (10 segments) (Broker fee not set) | 413754 | -| `createWithTimestampsLD` (10 segments) (Broker fee set) | 398397 | -| `createWithTimestampsLD` (10 segments) (Broker fee not set) | 393659 | -| `withdraw` (10 segments) (After End Time) (by Recipient) | 14268 | -| `withdraw` (10 segments) (Before End Time) (by Recipient) | 35941 | -| `withdraw` (10 segments) (After End Time) (by Anyone) | 14345 | -| `withdraw` (10 segments) (Before End Time) (by Anyone) | 35997 | -| `createWithDurationsLD` (100 segments) (Broker fee set) | 2917762 | -| `createWithDurationsLD` (100 segments) (Broker fee not set) | 2914004 | -| `createWithTimestampsLD` (100 segments) (Broker fee set) | 2725623 | -| `createWithTimestampsLD` (100 segments) (Broker fee not set) | 2721888 | -| `withdraw` (100 segments) (After End Time) (by Recipient) | 14268 | -| `withdraw` (100 segments) (Before End Time) (by Recipient) | 121045 | -| `withdraw` (100 segments) (After End Time) (by Anyone) | 14324 | -| `withdraw` (100 segments) (Before End Time) (by Anyone) | 121101 | +| `burn` | 15759 | +| `cancel` | 68674 | +| `renounce` | 37726 | +| `createWithDurationsLD` (2 segments) (Broker fee set) | 210925 | +| `createWithDurationsLD` (2 segments) (Broker fee not set) | 194672 | +| `createWithTimestampsLD` (2 segments) (Broker fee set) | 191434 | +| `createWithTimestampsLD` (2 segments) (Broker fee not set) | 186483 | +| `withdraw` (2 segments) (After End Time) (by Recipient) | 19035 | +| `withdraw` (2 segments) (Before End Time) (by Recipient) | 28249 | +| `withdraw` (2 segments) (After End Time) (by Anyone) | 14291 | +| `withdraw` (2 segments) (Before End Time) (by Anyone) | 28305 | +| `createWithDurationsLD` (10 segments) (Broker fee set) | 418459 | +| `createWithDurationsLD` (10 segments) (Broker fee not set) | 413521 | +| `createWithTimestampsLD` (10 segments) (Broker fee set) | 398011 | +| `createWithTimestampsLD` (10 segments) (Broker fee not set) | 393076 | +| `withdraw` (10 segments) (After End Time) (by Recipient) | 14222 | +| `withdraw` (10 segments) (Before End Time) (by Recipient) | 35552 | +| `withdraw` (10 segments) (After End Time) (by Anyone) | 14299 | +| `withdraw` (10 segments) (Before End Time) (by Anyone) | 35608 | +| `createWithDurationsLD` (100 segments) (Broker fee set) | 2918719 | +| `createWithDurationsLD` (100 segments) (Broker fee not set) | 2914766 | +| `createWithTimestampsLD` (100 segments) (Broker fee set) | 2726237 | +| `createWithTimestampsLD` (100 segments) (Broker fee not set) | 2722308 | +| `withdraw` (100 segments) (After End Time) (by Recipient) | 14222 | +| `withdraw` (100 segments) (Before End Time) (by Recipient) | 118136 | +| `withdraw` (100 segments) (After End Time) (by Anyone) | 14278 | +| `withdraw` (100 segments) (Before End Time) (by Anyone) | 118192 | diff --git a/benchmark/results/SablierLockup_Linear.md b/benchmark/results/SablierLockup_Linear.md index 8b9e9819f..f62e872ea 100644 --- a/benchmark/results/SablierLockup_Linear.md +++ b/benchmark/results/SablierLockup_Linear.md @@ -1,19 +1,19 @@ -# Benchmarks for Lockup Linear +# Benchmarks for Lockup Linear Model | Implementation | Gas Usage | | ------------------------------------------------------------- | --------- | -| `burn` | 15737 | -| `cancel` | 69877 | -| `renounce` | 37913 | -| `createWithDurationsLL` (Broker fee set) (cliff not set) | 131096 | -| `createWithDurationsLL` (Broker fee not set) (cliff not set) | 115013 | -| `createWithDurationsLL` (Broker fee set) (cliff set) | 139355 | -| `createWithDurationsLL` (Broker fee not set) (cliff set) | 134567 | -| `createWithTimestampsLL` (Broker fee set) (cliff not set) | 116775 | -| `createWithTimestampsLL` (Broker fee not set) (cliff not set) | 111988 | -| `createWithTimestampsLL` (Broker fee set) (cliff set) | 139034 | -| `createWithTimestampsLL` (Broker fee not set) (cliff set) | 134244 | -| `withdraw` (After End Time) (by Recipient) | 29468 | -| `withdraw` (Before End Time) (by Recipient) | 23600 | -| `withdraw` (After End Time) (by Anyone) | 24724 | -| `withdraw` (Before End Time) (by Anyone) | 20646 | +| `burn` | 15759 | +| `cancel` | 68674 | +| `renounce` | 37726 | +| `createWithDurationsLL` (Broker fee set) (cliff not set) | 131057 | +| `createWithDurationsLL` (Broker fee not set) (cliff not set) | 114740 | +| `createWithDurationsLL` (Broker fee set) (cliff set) | 139354 | +| `createWithDurationsLL` (Broker fee not set) (cliff set) | 134336 | +| `createWithTimestampsLL` (Broker fee set) (cliff not set) | 116950 | +| `createWithTimestampsLL` (Broker fee not set) (cliff not set) | 111929 | +| `createWithTimestampsLL` (Broker fee set) (cliff set) | 139254 | +| `createWithTimestampsLL` (Broker fee not set) (cliff set) | 134231 | +| `withdraw` (After End Time) (by Recipient) | 29422 | +| `withdraw` (Before End Time) (by Recipient) | 22353 | +| `withdraw` (After End Time) (by Anyone) | 24678 | +| `withdraw` (Before End Time) (by Anyone) | 20457 | diff --git a/benchmark/results/SablierLockup_Tranched.md b/benchmark/results/SablierLockup_Tranched.md index f1839a92f..15e9b513f 100644 --- a/benchmark/results/SablierLockup_Tranched.md +++ b/benchmark/results/SablierLockup_Tranched.md @@ -1,31 +1,31 @@ -# Benchmarks for Lockup Tranched +# Benchmarks for Lockup Tranched Model | Implementation | Gas Usage | | ------------------------------------------------------------ | --------- | -| `burn` | 15737 | -| `cancel` | 69877 | -| `renounce` | 37913 | -| `createWithDurationsLT` (2 tranches) (Broker fee set) | 209326 | -| `createWithDurationsLT` (2 tranches) (Broker fee not set) | 193271 | -| `createWithTimestampsLT` (2 tranches) (Broker fee set) | 190646 | -| `createWithTimestampsLT` (2 tranches) (Broker fee not set) | 185889 | -| `withdraw` (2 tranches) (After End Time) (by Recipient) | 19081 | -| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 17705 | -| `withdraw` (2 tranches) (After End Time) (by Anyone) | 14337 | -| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 17761 | -| `createWithDurationsLT` (10 tranches) (Broker fee set) | 409136 | -| `createWithDurationsLT` (10 tranches) (Broker fee not set) | 404389 | -| `createWithTimestampsLT` (10 tranches) (Broker fee set) | 391945 | -| `createWithTimestampsLT` (10 tranches) (Broker fee not set) | 387200 | -| `withdraw` (10 tranches) (After End Time) (by Recipient) | 14287 | -| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 26509 | -| `withdraw` (10 tranches) (After End Time) (by Anyone) | 14344 | -| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 26565 | -| `createWithDurationsLT` (100 tranches) (Broker fee set) | 2819059 | -| `createWithDurationsLT` (100 tranches) (Broker fee not set) | 2814813 | -| `createWithTimestampsLT` (100 tranches) (Broker fee set) | 2658722 | -| `createWithTimestampsLT` (100 tranches) (Broker fee not set) | 2654477 | -| `withdraw` (100 tranches) (After End Time) (by Recipient) | 14268 | -| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 126282 | -| `withdraw` (100 tranches) (After End Time) (by Anyone) | 14324 | -| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 126338 | +| `burn` | 15759 | +| `cancel` | 68674 | +| `renounce` | 37726 | +| `createWithDurationsLT` (2 tranches) (Broker fee set) | 209043 | +| `createWithDurationsLT` (2 tranches) (Broker fee not set) | 192794 | +| `createWithTimestampsLT` (2 tranches) (Broker fee set) | 191023 | +| `createWithTimestampsLT` (2 tranches) (Broker fee not set) | 186072 | +| `withdraw` (2 tranches) (After End Time) (by Recipient) | 19035 | +| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 16714 | +| `withdraw` (2 tranches) (After End Time) (by Anyone) | 14292 | +| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 16770 | +| `createWithDurationsLT` (10 tranches) (Broker fee set) | 408861 | +| `createWithDurationsLT` (10 tranches) (Broker fee not set) | 403916 | +| `createWithTimestampsLT` (10 tranches) (Broker fee set) | 392335 | +| `createWithTimestampsLT` (10 tranches) (Broker fee not set) | 387399 | +| `withdraw` (10 tranches) (After End Time) (by Recipient) | 14235 | +| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 23465 | +| `withdraw` (10 tranches) (After End Time) (by Anyone) | 14298 | +| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 23521 | +| `createWithDurationsLT` (100 tranches) (Broker fee set) | 2818875 | +| `createWithDurationsLT` (100 tranches) (Broker fee not set) | 2814433 | +| `createWithTimestampsLT` (100 tranches) (Broker fee set) | 2659191 | +| `createWithTimestampsLT` (100 tranches) (Broker fee not set) | 2654768 | +| `withdraw` (100 tranches) (After End Time) (by Recipient) | 14222 | +| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 99780 | +| `withdraw` (100 tranches) (After End Time) (by Anyone) | 14278 | +| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 99836 | diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 36a27a3ca..455cad283 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -19,11 +19,11 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_BATCH_LOCKUP = - hex"60808060405234601557611888908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd314610e1357806349a32c4014610b81578063606ef875146109205780639e743f2914610649578063a514f83e146103875763f7ca34eb1461005b575f80fd5b346102e157610069366110a0565b92839291921561035f579092905f90815b83811061032e57506001600160a01b036100979116918583611548565b6100a082611212565b926001600160a01b035f9516945b8381106100c757604051806100c3878261111c565b0390f35b6100df6100d582868561145c565b60c08101906113e2565b6100ed6100d584888761145c565b5f190191821015905061031a576060020160400161010a9061147f565b9061011681868561145c565b61011f90611244565b9161012b82878661145c565b60200161013790611244565b9061014383888761145c565b60400161014f90611177565b61015a84898861145c565b60600161016690611258565b610171858a8961145c565b60800161017d90611258565b90610189868b8a61145c565b60a0016101959061147f565b926101a1878c8b61145c565b60e00195604051986101b28a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b031660408801528b606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e08401523661020f91611265565b61010083015261022081868561145c565b60c0810161022d916113e2565b9290836040519485937f53ac8bc30000000000000000000000000000000000000000000000000000000085526101648501906004860161026c91611491565b61016061014486015252610184830191905f905b8082106102f857505050908060209203815f885af180156102ed575f906102b7575b600192506102b082886113bd565b52016100ae565b506020823d82116102e5575b816102d0602093836111d8565b810103126102e157600191516102a2565b5f80fd5b3d91506102c3565b6040513d5f823e3d90fd5b919350916060808261030c60019488611418565b019401920185939291610280565b634e487b7160e01b5f52603260045260245ffd5b916001906001600160801b03610353604061034d87898b9c9a9c61145c565b01611177565b1601920194929461007a565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e15760603660031901126102e1576103a0611074565b6103a861108a565b6044359067ffffffffffffffff82116102e157366023830112156102e157816004013567ffffffffffffffff81116102e15760248301926024369161014084020101116102e157801561035f57905f935f5b83811061061e57506001600160a01b036104179116948286611548565b61042082611212565b926001600160a01b035f9216915b83811061044357604051806100c3878261111c565b61044e818584611537565b61045790611244565b90610463818685611537565b60200161046f90611244565b61047a828786611537565b60400161048690611177565b610491838887611537565b60600161049d90611258565b6104a8848988611537565b6080016104b490611258565b6104bf858a89611537565b60a0016104cb9061147f565b916104d7868b8a611537565b60e0016104e39061147f565b936104ef878c8b611537565b6101000195604051986105018a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b0316604088015288606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e08401523661055e91611265565b61010083015261056f818685611537565b60c00161057b9061147f565b604051927f9e7f5dbb000000000000000000000000000000000000000000000000000000008452600484016105af91611491565b64ffffffffff166101448301528180885a925f61016492602095f180156102ed575f906105ec575b600192506105e582886113bd565b520161042e565b506020823d8211610616575b81610605602093836111d8565b810103126102e157600191516105d7565b3d91506105f8565b946001906001600160801b0361063d604061034d8a898b9a999a611537565b160195019291926103fa565b346102e157610657366110a0565b92839291921561035f579092905f90815b8381106108f557506001600160a01b036106859116918583611548565b61068e82611212565b926001600160a01b035f9516945b8381106106b157604051806100c3878261111c565b6106c96106bf82868561145c565b60c08101906112af565b6106d76106bf84888761145c565b5f190191821015905061031a5760061b016020016106f49061147f565b9061070081868561145c565b61070990611244565b9161071582878661145c565b60200161072190611244565b9061072d83888761145c565b60400161073990611177565b61074484898861145c565b60600161075090611258565b61075b858a8961145c565b60800161076790611258565b90610773868b8a61145c565b60a00161077f9061147f565b9261078b878c8b61145c565b60e001956040519861079c8a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b031660408801528b606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e0840152366107f991611265565b61010083015261080a81868561145c565b60c08101610817916112af565b9290836040519485937f56b955e80000000000000000000000000000000000000000000000000000000085526101648501906004860161085691611491565b61016061014486015252610184830191905f905b8082106108d357505050908060209203815f885af180156102ed575f906108a1575b6001925061089a82886113bd565b520161069c565b506020823d82116108cb575b816108ba602093836111d8565b810103126102e1576001915161088c565b3d91506108ad565b91935091604080826108e760019488611390565b01940192018593929161086a565b916001906001600160801b03610914604061034d87898b9c9a9c61145c565b16019201949294610668565b346102e15761092e366110a0565b92839291921561035f579092905f90815b838110610b5657506001600160a01b0361095c9116918583611548565b61096582611212565b926001600160a01b035f9516945b83811061098857604051806100c3878261111c565b610993818584611155565b61099c90611244565b906109a8818685611155565b6020016109b490611244565b6109bf828786611155565b6040016109cb90611177565b6109d6838887611155565b6060016109e290611258565b6109ed848988611155565b6080016109f990611258565b91610a05858a89611155565b60c0019360405196610a168861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a084015236610a5b91611265565b60c0830152610a6b818685611155565b60a08101610a78916113e2565b9290836040519485937f42e94a7b00000000000000000000000000000000000000000000000000000000855261012485019060048601610ab7916112e5565b61012061010486015252610144830191905f905b808210610b3457505050908060209203815f885af180156102ed575f90610b02575b60019250610afb82886113bd565b5201610973565b506020823d8211610b2c575b81610b1b602093836111d8565b810103126102e15760019151610aed565b3d9150610b0e565b9193509160608082610b4860019488611418565b019401920185939291610acb565b916001906001600160801b03610b75604061034d87898b9c9a9c611155565b1601920194929461093f565b346102e15760603660031901126102e157610b9a611074565b610ba261108a565b6044359067ffffffffffffffff82116102e157366023830112156102e157816004013567ffffffffffffffff81116102e15760248301926024369161012084020101116102e157801561035f57905f935f5b838110610de857506001600160a01b03610c119116948286611548565b610c1a82611212565b926001600160a01b035f9216915b838110610c3d57604051806100c3878261111c565b610c488185846113d1565b610c5190611244565b90610c5d8186856113d1565b602001610c6990611244565b610c748287866113d1565b604001610c8090611177565b610c8b8388876113d1565b606001610c9790611258565b610ca28489886113d1565b608001610cae90611258565b91610cba858a896113d1565b60e0019360405196610ccb8861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015286606086015215156080850152151560a084015236610d1091611265565b60c0830152610d208186856113d1565b604051927f8222b69400000000000000000000000000000000000000000000000000000000845260048401610d54916112e5565b610d6060a0820161137e565b64ffffffffff1661010484015260c001610d799061137e565b64ffffffffff166101248301528180885a925f61014492602095f180156102ed575f90610db6575b60019250610daf82886113bd565b5201610c28565b506020823d8211610de0575b81610dcf602093836111d8565b810103126102e15760019151610da1565b3d9150610dc2565b946001906001600160801b03610e07604061034d8a898b9a999a6113d1565b16019501929192610bf4565b346102e157610e21366110a0565b92839291921561035f579092905f90815b83811061104957506001600160a01b03610e4f9116918583611548565b610e5882611212565b926001600160a01b035f9516945b838110610e7b57604051806100c3878261111c565b610e86818584611155565b610e8f90611244565b90610e9b818685611155565b602001610ea790611244565b610eb2828786611155565b604001610ebe90611177565b610ec9838887611155565b606001610ed590611258565b610ee0848988611155565b608001610eec90611258565b91610ef8858a89611155565b60c0019360405196610f098861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a084015236610f4e91611265565b60c0830152610f5e818685611155565b60a08101610f6b916112af565b9290836040519485937f6611ceab00000000000000000000000000000000000000000000000000000000855261012485019060048601610faa916112e5565b61012061010486015252610144830191905f905b80821061102757505050908060209203815f885af180156102ed575f90610ff5575b60019250610fee82886113bd565b5201610e66565b506020823d821161101f575b8161100e602093836111d8565b810103126102e15760019151610fe0565b3d9150611001565b919350916040808261103b60019488611390565b019401920185939291610fbe565b916001906001600160801b03611068604061034d87898b9c9a9c611155565b16019201949294610e32565b600435906001600160a01b03821682036102e157565b602435906001600160a01b03821682036102e157565b9060606003198301126102e1576004356001600160a01b03811681036102e157916024356001600160a01b03811681036102e1579160443567ffffffffffffffff81116102e15760040182601f820112156102e15780359267ffffffffffffffff84116102e1576020808301928560051b0101116102e1579190565b60206040818301928281528451809452019201905f5b81811061113f5750505090565b8251845260209384019390920191600101611132565b919081101561031a5760051b8101359060fe19813603018212156102e1570190565b356001600160801b03811681036102e15790565b60e0810190811067ffffffffffffffff8211176111a757604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff8211176111a757604052565b90601f8019910116810190811067ffffffffffffffff8211176111a757604052565b67ffffffffffffffff81116111a75760051b60200190565b9061121c826111fa565b61122960405191826111d8565b828152809261123a601f19916111fa565b0190602036910137565b356001600160a01b03811681036102e15790565b3580151581036102e15790565b91908260409103126102e1576040516040810181811067ffffffffffffffff8211176111a757604052809280356001600160a01b03811681036102e1578252602090810135910152565b903590601e19813603018212156102e1570180359067ffffffffffffffff82116102e157602001918160061b360383136102e157565b9060c080611368936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a08501520151910190602080916001600160a01b0381511684520151910152565b565b35906001600160801b03821682036102e157565b359064ffffffffff821682036102e157565b64ffffffffff6113b7602080936001600160801b036113ae8261136a565b1686520161137e565b16910152565b805182101561031a5760209160051b010190565b919081101561031a57610120020190565b903590601e19813603018212156102e1570180359067ffffffffffffffff82116102e1576020019160608202360383136102e157565b6001600160801b036114298261136a565b168252602081013567ffffffffffffffff81168091036102e1576113b76040809364ffffffffff9360208701520161137e565b919081101561031a5760051b8101359061011e19813603018212156102e1570190565b3564ffffffffff811681036102e15790565b9061010080611368936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a085015264ffffffffff60c08201511660c085015264ffffffffff60e08201511660e08501520151910190602080916001600160a01b0381511684520151910152565b919081101561031a57610140020190565b919061159d6040517f23b872dd000000000000000000000000000000000000000000000000000000006020820152336024820152306044820152836064820152606481526115976084826111d8565b8261172b565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156102ed5784915f916116de575b5010611609575b50505050565b5f8060405194602086019063095ea7b360e01b82528760248801526044870152604486526116386064876111d8565b85519082855af1906116486117b0565b826116ac575b50816116a1575b5015611662575b80611603565b611694611699936040519063095ea7b360e01b602083015260248201525f6044820152604481526115976064826111d8565b61172b565b5f808061165c565b90503b15155f611655565b805191925081159182156116c4575b5050905f61164e565b6116d79250602080918301019101611713565b5f806116bb565b9150506020813d60201161170b575b816116fa602093836111d8565b810103126102e1578390515f6115fc565b3d91506116ed565b908160209103126102e1575180151581036102e15790565b5f806001600160a01b0361175493169360208151910182865af161174d6117b0565b90836117ef565b8051908115159182611795575b505061176a5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6117a89250602080918301019101611713565b155f80611761565b3d156117ea573d9067ffffffffffffffff82116111a757604051916117df601f8201601f1916602001846111d8565b82523d5f602084013e565b606090565b9061182c575080511561180457805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611872575b61183d575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561183556fea164736f6c634300081a000a"; + hex"60808060405234601557611744908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd314610cc857806349a32c4014610a36578063606ef875146107d55780639e743f29146105fb578063a10679d11461036f5763f7ca34eb1461005b575f80fd5b346102cf5761006936610f55565b928392919215610347579092905f90815b83811061031c57506001600160a01b036100979116918583611404565b6100a0826110e3565b926001600160a01b035f9516945b8381106100c757604051806100c38782610fd1565b0390f35b6100df6100d582868561131c565b60c08101906112a2565b6100ed6100d584888761131c565b5f19019182101590506103085761010b91606060409202010161133f565b9061020861012261011d83888761131c565b611115565b926101bb61013c6020610136868b8a61131c565b01611115565b91866001600160801b038a6001600160a01b0360e06101c98a61016b604061016583888b61131c565b0161102c565b94610182606061017c84848c61131c565b01611129565b9764ffffffffff610199608061017c86868661131c565b9a816101b160a06101ab88888861131c565b0161133f565b6040519e8f611070565b168d521660208c015261131c565b0196816040519b6101d98d61108c565b168b521660208a01521660408801528b606088015215156080870152151560a086015260c08501523690611136565b60e083015261021b6100d582878661131c565b9290836040519485937f1b1a433f00000000000000000000000000000000000000000000000000000000855261025a6101648601916004870190611351565b61016061014486015252610184830191905f905b8082106102e657505050908060209203815f885af180156102db575f906102a5575b6001925061029e828861127d565b52016100ae565b506020823d82116102d3575b816102be602093836110a9565b810103126102cf5760019151610290565b5f80fd5b3d91506102b1565b6040513d5f823e3d90fd5b91935091606080826102fa600194886112d8565b01940192018593929161026e565b634e487b7160e01b5f52603260045260245ffd5b916001906001600160801b0361033b604061016587898b9c9a9c61131c565b1601920194929461007a565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102cf5760603660031901126102cf57610388610f29565b610390610f3f565b6044359067ffffffffffffffff82116102cf57366023830112156102cf57816004013567ffffffffffffffff81116102cf5760248301926024369161014084020101116102cf578015610347575f935f5b8281106105d657506001600160a01b036103fe9116948386611404565b610407816110e3565b926001600160a01b035f9316925b82811061042a57604051806100c38782610fd1565b61043861011d8285856113f3565b9061044960206101368387876113f3565b61045960406101658488886113f3565b9061046a606061017c8589896113f3565b61047a608061017c868a8a6113f3565b906001600160801b0361048e868a8a6113f3565b946001600160a01b036101006104a5898d8d6113f3565b0195816040519a6104b58c61108c565b168a5216602089015216604087015288606087015215156080860152151560a08501526040609f1983360301126102cf576105219161051060c0604051926104fc84611070565b61050860a0820161123e565b84520161123e565b602082015260c08501523690611136565b60e083015264ffffffffff61053c60e06101ab8488886113f3565b610570604051947fab605ced0000000000000000000000000000000000000000000000000000000086526004860190611351565b16610144830152602082610164815f8b5af180156102db575f906105a4575b6001925061059d828861127d565b5201610415565b506020823d82116105ce575b816105bd602093836110a9565b810103126102cf576001915161058f565b3d91506105b0565b946001906001600160801b036105f260406101658a888b6113f3565b160195016103e1565b346102cf5761060936610f55565b928392919215610347579092905f90815b8381106107aa57506001600160a01b036106379116918583611404565b610640826110e3565b926001600160a01b035f9516945b83811061066357604051806100c38782610fd1565b61067b61067182868561131c565b60c081019061116f565b61068961067184888761131c565b5f1901918210159050610308576106a79160209160061b010161133f565b906106b961012261011d83888761131c565b60e08301526106cc61067182878661131c565b9290836040519485937fd6a03d3100000000000000000000000000000000000000000000000000000000855261070b6101648601916004870190611351565b61016061014486015252610184830191905f905b80821061078857505050908060209203815f885af180156102db575f90610756575b6001925061074f828861127d565b520161064e565b506020823d8211610780575b8161076f602093836110a9565b810103126102cf5760019151610741565b3d9150610762565b919350916040808261079c60019488611250565b01940192018593929161071f565b916001906001600160801b036107c9604061016587898b9c9a9c61131c565b1601920194929461061a565b346102cf576107e336610f55565b928392919215610347579092905f90815b838110610a0b57506001600160a01b036108119116918583611404565b61081a826110e3565b926001600160a01b035f9516945b83811061083d57604051806100c38782610fd1565b61084881858461100a565b61085190611115565b9061085d81868561100a565b60200161086990611115565b61087482878661100a565b6040016108809061102c565b61088b83888761100a565b60600161089790611129565b6108a284898861100a565b6080016108ae90611129565b916108ba858a8961100a565b60c00193604051966108cb88611040565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a08401523661091091611136565b60c083015261092081868561100a565b60a0810161092d916112a2565b9290836040519485937f42e94a7b0000000000000000000000000000000000000000000000000000000085526101248501906004860161096c916111a5565b61012061010486015252610144830191905f905b8082106109e957505050908060209203815f885af180156102db575f906109b7575b600192506109b0828861127d565b5201610828565b506020823d82116109e1575b816109d0602093836110a9565b810103126102cf57600191516109a2565b3d91506109c3565b91935091606080826109fd600194886112d8565b019401920185939291610980565b916001906001600160801b03610a2a604061016587898b9c9a9c61100a565b160192019492946107f4565b346102cf5760603660031901126102cf57610a4f610f29565b610a57610f3f565b6044359067ffffffffffffffff82116102cf57366023830112156102cf57816004013567ffffffffffffffff81116102cf5760248301926024369161012084020101116102cf57801561034757905f935f5b838110610c9d57506001600160a01b03610ac69116948286611404565b610acf826110e3565b926001600160a01b035f9216915b838110610af257604051806100c38782610fd1565b610afd818584611291565b610b0690611115565b90610b12818685611291565b602001610b1e90611115565b610b29828786611291565b604001610b359061102c565b610b40838887611291565b606001610b4c90611129565b610b57848988611291565b608001610b6390611129565b91610b6f858a89611291565b60e0019360405196610b8088611040565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015286606086015215156080850152151560a084015236610bc591611136565b60c0830152610bd5818685611291565b604051927f8222b69400000000000000000000000000000000000000000000000000000000845260048401610c09916111a5565b610c1560a0820161123e565b64ffffffffff1661010484015260c001610c2e9061123e565b64ffffffffff166101248301528180885a925f61014492602095f180156102db575f90610c6b575b60019250610c64828861127d565b5201610add565b506020823d8211610c95575b81610c84602093836110a9565b810103126102cf5760019151610c56565b3d9150610c77565b946001906001600160801b03610cbc60406101658a898b9a999a611291565b16019501929192610aa9565b346102cf57610cd636610f55565b928392919215610347579092905f90815b838110610efe57506001600160a01b03610d049116918583611404565b610d0d826110e3565b926001600160a01b035f9516945b838110610d3057604051806100c38782610fd1565b610d3b81858461100a565b610d4490611115565b90610d5081868561100a565b602001610d5c90611115565b610d6782878661100a565b604001610d739061102c565b610d7e83888761100a565b606001610d8a90611129565b610d9584898861100a565b608001610da190611129565b91610dad858a8961100a565b60c0019360405196610dbe88611040565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a084015236610e0391611136565b60c0830152610e1381868561100a565b60a08101610e209161116f565b9290836040519485937f6611ceab00000000000000000000000000000000000000000000000000000000855261012485019060048601610e5f916111a5565b61012061010486015252610144830191905f905b808210610edc57505050908060209203815f885af180156102db575f90610eaa575b60019250610ea3828861127d565b5201610d1b565b506020823d8211610ed4575b81610ec3602093836110a9565b810103126102cf5760019151610e95565b3d9150610eb6565b9193509160408082610ef060019488611250565b019401920185939291610e73565b916001906001600160801b03610f1d604061016587898b9c9a9c61100a565b16019201949294610ce7565b600435906001600160a01b03821682036102cf57565b602435906001600160a01b03821682036102cf57565b9060606003198301126102cf576004356001600160a01b03811681036102cf57916024356001600160a01b03811681036102cf579160443567ffffffffffffffff81116102cf5760040182601f820112156102cf5780359267ffffffffffffffff84116102cf576020808301928560051b0101116102cf579190565b60206040818301928281528451809452019201905f5b818110610ff45750505090565b8251845260209384019390920191600101610fe7565b91908110156103085760051b8101359060fe19813603018212156102cf570190565b356001600160801b03811681036102cf5790565b60e0810190811067ffffffffffffffff82111761105c57604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff82111761105c57604052565b610100810190811067ffffffffffffffff82111761105c57604052565b90601f8019910116810190811067ffffffffffffffff82111761105c57604052565b67ffffffffffffffff811161105c5760051b60200190565b906110ed826110cb565b6110fa60405191826110a9565b828152809261110b601f19916110cb565b0190602036910137565b356001600160a01b03811681036102cf5790565b3580151581036102cf5790565b91908260409103126102cf5760405161114e81611070565b809280356001600160a01b03811681036102cf578252602090810135910152565b903590601e19813603018212156102cf570180359067ffffffffffffffff82116102cf57602001918160061b360383136102cf57565b9060c080611228936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a08501520151910190602080916001600160a01b0381511684520151910152565b565b35906001600160801b03821682036102cf57565b359064ffffffffff821682036102cf57565b64ffffffffff611277602080936001600160801b0361126e8261122a565b1686520161123e565b16910152565b80518210156103085760209160051b010190565b919081101561030857610120020190565b903590601e19813603018212156102cf570180359067ffffffffffffffff82116102cf576020019160608202360383136102cf57565b6001600160801b036112e98261122a565b168252602081013567ffffffffffffffff81168091036102cf576112776040809364ffffffffff9360208701520161123e565b91908110156103085760051b8101359061011e19813603018212156102cf570190565b3564ffffffffff811681036102cf5790565b9061010060e0611228936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a085015264ffffffffff602060c08301518281511660c0880152015116828501520151910190602080916001600160a01b0381511684520151910152565b919081101561030857610140020190565b91906114596040517f23b872dd000000000000000000000000000000000000000000000000000000006020820152336024820152306044820152836064820152606481526114536084826110a9565b826115e7565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156102db5784915f9161159a575b50106114c5575b50505050565b5f8060405194602086019063095ea7b360e01b82528760248801526044870152604486526114f46064876110a9565b85519082855af19061150461166c565b82611568575b508161155d575b501561151e575b806114bf565b611550611555936040519063095ea7b360e01b602083015260248201525f6044820152604481526114536064826110a9565b6115e7565b5f8080611518565b90503b15155f611511565b80519192508115918215611580575b5050905f61150a565b61159392506020809183010191016115cf565b5f80611577565b9150506020813d6020116115c7575b816115b6602093836110a9565b810103126102cf578390515f6114b8565b3d91506115a9565b908160209103126102cf575180151581036102cf5790565b5f806001600160a01b0361161093169360208151910182865af161160961166c565b90836116ab565b8051908115159182611651575b50506116265750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b61166492506020809183010191016115cf565b155f8061161d565b3d156116a6573d9067ffffffffffffffff821161105c576040519161169b601f8201601f1916602001846110a9565b82523d5f602084013e565b606090565b906116e857508051156116c057805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061172e575b6116f9575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156116f156fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP = - hex"60c0604052346103ce5761612b6060813803918261001c816103d2565b9384928339810103126103ce5780516001600160a01b038116908190036103ce5760208201516001600160a01b03811692908390036103ce576040015161006360406103d2565b92601284527114d8589b1a595c88131bd8dadd5c0813919560721b602085015261008d60406103d2565b600a81526905341422d4c4f434b55560b41b6020820152306080525f80546001600160a01b031916851781559093907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a383516001600160401b0381116102df57600154600181811c911680156103c4575b60208210146102c157601f8111610361575b50602094601f82116001146102fe579481929394955f926102f3575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102df57600254600181811c911680156102d5575b60208210146102c157601f811161025e575b506020601f82116001146101fb57819293945f926101f0575b50508160011b915f199060031b1c1916176002555b600880546001600160a01b03191691909117905560a0526001600755604051615d3390816103f882396080518161485e015260a05181818161202d01528181614a47015261518b0152f35b015190505f80610190565b601f1982169060025f52805f20915f5b8181106102465750958360019596971061022e575b505050811b016002556101a5565b01515f1960f88460031b161c191690555f8080610220565b9192602060018192868b01518155019401920161020b565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102b7575b601f0160051c01905b8181106102ac5750610177565b5f815560010161029f565b9091508190610296565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610165565b634e487b7160e01b5f52604160045260245ffd5b015190505f8061012f565b601f1982169560015f52805f20915f5b88811061034957508360019596979810610331575b505050811b01600155610144565b01515f1960f88460031b161c191690555f8080610323565b9192602060018192868501518155019401920161030e565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ba575b601f0160051c01905b8181106103af5750610113565b5f81556001016103a2565b9091508190610399565b90607f1690610101565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102df5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461388757508063027b67441461386557806306fdde03146137aa578063081812fc1461378c578063095ea7b3146136875780631400ecec146135d65780631c1cdd4c146135725780631e897afb1461348d5780631e99d5691461347057806323b872dd14613459578063303acc851461341c578063406887cb146132ad57806340e58ee514612fd6578063425d30dd14612f8657806342842e0e14612f5d57806342966c6814612d8357806342e94a7b14612ac55780634426757014612a9f5780634857501f14612a2e5780634869e12d146129f45780634cc55e111461264d57806353ac8bc31461256d57806356b955e81461249f57806357404b12146123d95780636352211e146121285780636611ceab146121575780636d0cee751461212857806370a08231146120be57806375829def1461205057806377163c1d14612016578063780a82c814611fca5780637cad6cd114611eed5780637de6b1db14611da05780637f5799f914611c745780638222b69414611b3a5780638659c270146117825780638f69b993146117025780639067b677146116b357806395d89b41146115ab5780639e7f5dbb1461155a578063a22cb465146114a6578063a80fc07114611455578063ad35efd41461140a578063b2564569146113ba578063b637b8651461127b578063b88d4fde146111f1578063b8a3be66146111bc578063b971302a1461116e578063bc2be1be1461111f578063c156a11d14610d00578063c87b56dd14610bf5578063d4dbd20b14610ba4578063d511609f14610b59578063d975dfed14610b0e578063e6c417eb14610aa3578063e985e9c514610a4a578063ea5ead1914610707578063eac8f5b8146106b6578063f590c1761461065a578063f851a440146106355763fdd46d60146102bb575f80fd5b34610631576060366003190112610631576004356102d76139b4565b906044356001600160801b038116809103610631576102f4614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f52600a60205260ff600160405f20015460a01c1661060b576001600160a01b03831680156105f857825f5260036020526001600160a01b0360405f2054169384821415806105e7575b6105cd5782156105ba576001600160801b0361037585615b3e565b168084116105a05750835f52600a60205282600260405f20015460801c016001600160801b03811161058c576103d490855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526103eb600260405f20016148ae565b6001600160801b0361040f8160208401511692826040818351169201511690613c65565b16111561055a575b835f52600a60205261043b836001600160a01b03600160405f200154169283615b64565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610544575b6104a157005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f9161050a575b5016036104f857005b635f3a039d60e01b5f5260045260245ffd5b61052c915060203d602011610532575b6105248183613bf1565b810190614262565b5f6104ef565b503d61051a565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661049b565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610417565b634e487b7160e01b5f52601160045260245ffd5b8385632176546160e01b5f5260045260245260445260645ffd5b83633dd1eadf60e21b5f5260045260245ffd5b50826297d0a360e61b5f526004523360245260445260645ffd5b506105f285856148e0565b1561035a565b826316c90d2760e21b5f5260045260245ffd5b5063449491f560e11b5f5260045260245ffd5b50631643770160e21b5f5260045260245ffd5b5f80fd5b34610631575f3660031901126106315760206001600160a01b035f5416604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060405f205460f81c6040519015158152f35b631643770160e21b5f5260045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b34610631576040366003190112610631576004356107236139b4565b61072c82615b3e565b91610735614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c16610a38576001600160a01b0382168015610a2557815f5260036020526001600160a01b0360405f205416938482141580610a14575b6109fa576001600160801b03169283156109e7576001600160801b036107c084615b3e565b168085116109cd5750825f52600a60205283600260405f20015460801c016001600160801b03811161058c5761081f90845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052610836600260405f20016148ae565b6001600160801b0361085a8160208401511692826040818351169201511690613c65565b16111561099b575b825f52600a602052610886846001600160a01b03600160405f200154169283615b64565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a18333141580610985575b6108f6575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af1908115610539576392b9102b60e01b916001600160e01b0319915f91610966575b5016036109535781806108eb565b50635f3a039d60e01b5f5260045260245ffd5b61097f915060203d602011610532576105248183613bf1565b85610945565b50835f52600960205260ff60405f2054166108e6565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610862565b8484632176546160e01b5f5260045260245260445260645ffd5b82633dd1eadf60e21b5f5260045260245ffd5b50906297d0a360e61b5f526004523360245260445260645ffd5b50610a1f85846148e0565b1561079b565b506316c90d2760e21b5f5260045260245ffd5b63449491f560e11b5f5260045260245ffd5b3461063157604036600319011261063157610a6361399e565b6001600160a01b03610a736139b4565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260ff600160405f20015460b81c166040516003821015610afa576020918152f35b634e487b7160e01b5f52602160045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457610b48602091615b3e565b6001600160801b0360405191168152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a6020526020600260405f20015460801c604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160801b03600360405f20015416604051908152f35b3461063157602036600319011261063157600435610c1281614282565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610539575f90610c83575b610c7f90604051918291602083526020830190613979565b0390f35b503d805f833e610c938183613bf1565b8101906020818303126106315780519067ffffffffffffffff821161063157019080601f8301121561063157815191610ccb83613c13565b91610cd96040519384613bf1565b8383526020848301011161063157610c7f92610cfb9160208085019101613958565b610c67565b3461063157604036600319011261063157600435610d1c6139b4565b610d24614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f5260036020526001600160a01b0360405f20541690610d6082846148e0565b15611108576001600160801b03610d7684615b3e565b169081158015610dff575b506001600160a01b03811615610dec57610da3846001600160a01b039261471a565b169182610dbd5783637e27328960e01b5f5260045260245ffd5b8084918403610dd157602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610e07614854565b845f52600a60205260ff600160405f20015460a81c16156110f557845f52600a60205260ff600160405f20015460a01c166110e25783156110cf57845f5260036020526001600160a01b0360405f2054169081851415806110be575b6110a457611091576001600160801b03610e7c86615b3e565b168084116110775750845f52600a60205282600260405f20015460801c016001600160801b03811161058c57610edb90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610ef2600260405f20016148ae565b6001600160801b03610f168160208401511692826040818351169201511690613c65565b161115611045575b845f52600a6020526001600160a01b03600160405f20015416610f42848683615b64565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a1803314158061102f575b15610d81576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f91611010575b501614610d8157635f3a039d60e01b5f5260045260245ffd5b611029915060203d602011610532576105248183613bf1565b88610ff7565b50805f52600960205260ff60405f205416610fa2565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610f1e565b8386632176546160e01b5f5260045260245260445260645ffd5b84633dd1eadf60e21b5f5260045260245ffd5b84866297d0a360e61b5f526004523360245260445260645ffd5b506110c982876148e0565b15610e63565b846316c90d2760e21b5f5260045260245ffd5b8463449491f560e11b5f5260045260245ffd5b84631643770160e21b5f5260045260245ffd5b82634dda2c3960e11b5f526004523360245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160a01b0360405f205416604051908152f35b34610631576020366003190112610631576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346106315760803660031901126106315761120a61399e565b6112126139b4565b6064359167ffffffffffffffff831161063157366023840112156106315782600401359161123f83613c13565b9261124d6040519485613bf1565b8084523660248287010111610631576020815f9260246112799801838801378501015260443591614172565b005b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460b81c166003811015610afa57600103611371575f52600c60205260405f2080546112e681613efe565b916112f46040519384613bf1565b81835260208301905f5260205f205f915b8383106113225760405160208082528190610c7f90820188613b00565b60016020819260405161133481613b6b565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190611305565b5f52600a60205260ff600160405f20015460b81c167fb2a2ea58000000000000000000000000000000000000000000000000000000005f526003811015610afa5760045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576114429061468b565b6040516005821015610afa576020918152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160801b03600260405f20015416604051908152f35b34610631576040366003190112610631576114bf61399e565b60243590811515809203610631576001600160a01b031690811561152e57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461063157366003190161016081126106315761014013610631576101443564ffffffffff81168103610631576115a3602091611595614854565b61159e36614038565b61563e565b604051908152f35b34610631575f366003190112610631576040515f6002548060011c906001811680156116a9575b602083108114611695578285529081156116715750600114611613575b610c7f836115ff81850382613bf1565b604051918291602083526020830190613979565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210611657575090915081016020016115ff6115ef565b91926001816020925483858801015201910190929161163f565b60ff191660208086019190915291151560051b840190910191506115ff90506115ef565b634e487b7160e01b5f52602260045260245ffd5b91607f16916115d2565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a45761173a9061468b565b600581101580610afa5760028214908115611776575b8115611764575b6020826040519015158152f35b9050610afa5760046020911482611757565b5050600381145f611750565b346106315760203660031901126106315760043567ffffffffffffffff8111610631576117b39036906004016139ca565b906117bc614854565b5f915b8083106117c857005b6117d3838284614028565b35926117dd614854565b835f52600a60205260ff600160405f20015460a81c1615611b2757835f52600a60205260ff600160405f20015460a01c165f14611827578363449491f560e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611b155761185c815f52600a6020526001600160a01b0360405f205416331490565b15611aff5761186a816142a3565b90805f52600a602052611882600260405f20016148ae565b916001600160801b038351166001600160801b0382161015611aec57815f52600a60205260ff60405f205460f01c1615611ad957806001600160801b036020816118d6948188511603169501511690613c65565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611ab4575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506119e86001600160a01b03600160405f20015416946119c0888588615b64565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611a39575b505050505060010191906117bf565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561053957630d4af11f60e31b916001600160e01b0319915f91611a96575b5016036104f85780808080611a2a565b611aae915060203d8111610532576105248183613bf1565b87611a86565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611920565b50635c7470b760e01b5f5260045260245ffd5b5063fa36c71760e01b5f5260045260245ffd5b634dda2c3960e11b5f526004523360245260445ffd5b63e707ae4f60e01b5f5260045260245ffd5b83631643770160e21b5f5260045260245ffd5b34610631573660031901610140811261063157610100136106315760403661010319011261063157611b6a614854565b611b7261413f565b64ffffffffff42169081815264ffffffffff611b8c61415d565b16611c59575b610124359064ffffffffff821682036106315764ffffffffff60206001600160a01b0392819583866115a3975082011690816040840152611bd1613f51565b611bd9613f67565b87611be2613f7d565b6001600160801b03611bf2613f93565b9183611bfc613fa9565b95611c05613fb8565b976040519e8f91611c1583613b9b565b169052168a8d01521660408b015216606089015215156080880152151560a087015260c086015260e0850152611c4a36613fef565b6101008501520151169061563e565b64ffffffffff611c6761415d565b8301166020820152611b92565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460b81c166003811015610afa57600203611d57575f52600d60205260405f208054611cdf81613efe565b91611ced6040519384613bf1565b81835260208301905f5260205f205f915b838310611d1b5760405160208082528190610c7f90820188613a97565b600160208192604051611d2d81613bb8565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190611cfe565b5f52600a60205260ff600160405f20015460b81c167fcfcba4ef000000000000000000000000000000000000000000000000000000005f526003811015610afa5760045260245ffd5b3461063157602036600319011261063157600435611dbc614854565b805f52600a60205260ff600160405f20015460a81c16156106a457611de08161468b565b6005811015610afa5760048103611e04575063449491f560e11b5f5260045260245ffd5b60038103611e1f575063e707ae4f60e01b5f5260045260245ffd5b600214611edb57611e44815f52600a6020526001600160a01b0360405f205416331490565b15611aff57805f52600a60205260ff60405f205460f01c1615611ec9576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635c7470b760e01b5f5260045260245ffd5b63fa36c71760e01b5f5260045260245ffd5b34610631576020366003190112610631576004356001600160a01b038116809103610631576001600160a01b035f5416338103611fb4575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161058c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600b602052602064ffffffffff60405f205416604051908152f35b34610631575f3660031901126106315760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346106315760203660031901126106315761206961399e565b5f546001600160a01b038116338103611fb457506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b34610631576020366003190112610631576001600160a01b036120df61399e565b1680156120fc575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610631576020366003190112610631576020612146600435614282565b6001600160a01b0360405191168152f35b3461063157366003190161012081126106315761010013610631576101043567ffffffffffffffff811161063157612193903690600401613a66565b61219b614854565b6040519182917f66f401dd000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b81811061239557845f81808703817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916122d3575b50612215613f51565b61221d613f67565b91612226613f7d565b9161222f613f93565b93612238613fa9565b612240613fb8565b908451955f19870196871161058c576020976001600160801b036001600160a01b03928364ffffffffff8c6122786115a39d8d613fc7565b5101511697816040519a61228b8c613b9b565b168a52168b89015216604087015216606085015215156080840152151560a083015264ffffffffff421660c083015260e08201526122c836613fef565b6101008201526150eb565b90503d805f833e6122e48183613bf1565b8101906020818303126106315780519067ffffffffffffffff8211610631570181601f820112156106315780519061231b82613efe565b926123296040519485613bf1565b82845260208085019360061b8301019181831161063157602001925b82841061235657505050508161220c565b604084830312610631576020604091825161237081613bb8565b61237987613f16565b8152612386838801613f2a565b83820152815201930192612345565b919350916040806001926001600160801b036123b088613c2f565b16815264ffffffffff6123c560208901613aee565b1660208201520194019101918493926121d9565b34610631576020366003190112610631576004356123f561413f565b50805f52600a60205260ff600160405f20015460a81c16156106a457806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261246584613b6b565b83526020830152604082015261249d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b3461063157366003190161016081126106315761014013610631576101443567ffffffffffffffff8111610631576124db903690600401613a66565b6124e3614854565b6124ec36614038565b906124f681613efe565b926125046040519485613bf1565b818452602084019160061b81019036821161063157915b81831061252e5760206115a386866150eb565b604083360312610631576020604091825161254881613bb8565b61255186613c2f565b815261255e838701613aee565b8382015281520192019161251b565b3461063157366003190161016081126106315761014013610631576101443567ffffffffffffffff8111610631576125a9903690600401613a35565b6125b1614854565b6125ba36614038565b906125c481613efe565b926125d26040519485613bf1565b818452606060208501920281019036821161063157915b8183106125fc5760206115a38686614991565b60608336031261063157602060609160405161261781613b6b565b61262086613c2f565b815261262d838701613f3c565b8382015261263d60408701613aee565b60408201528152019201916125e9565b346106315760403660031901126106315760043567ffffffffffffffff81116106315761267e9036906004016139ca565b60243567ffffffffffffffff81116106315761269e9036906004016139ca565b6126a9939193614854565b8083036129c5575f5b8381106126bb57005b6126c6818585614028565b356126d2828686614028565b355f5260036020526001600160a01b0360405f205416906126f4838589614028565b356001600160801b038116908181036106315750612710614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f52600a60205260ff600160405f20015460a01c1661060b578215610a2557815f5260036020526001600160a01b0360405f2054169283811415806129b4575b61299b5781156109e7576001600160801b0361278784615b3e565b168083116129815750825f52600a60205281600260405f20015460801c016001600160801b03811161058c576127e690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526127fd600260405f20016148ae565b6001600160801b036128218160208401511692826040818351169201511690613c65565b16111561294f575b825f52600a6020526001600160a01b03600160405f2001541661284d838383615b64565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612939575b6128be575b505050506001016126b2565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f9161291b575b5016036104f8578080806128b2565b612933915060203d8111610532576105248183613bf1565b8961290c565b50835f52600960205260ff60405f2054166128ad565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612829565b8284632176546160e01b5f5260045260245260445260645ffd5b826297d0a360e61b5f526004523360245260445260645ffd5b506129bf84846148e0565b1561276c565b827fc0a1a35a000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457610b4860209161506a565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f612a678261468b565b6005811015610afa57600203612a85575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612a78565b34610631575f3660031901126106315760206001600160a01b0360085416604051908152f35b3461063157366003190161012081126106315761010013610631576101043567ffffffffffffffff811161063157612b01903690600401613a35565b612b09614854565b6040519182917fca31a854000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b818110612d2457845f81808703817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f91612c42575b50612b83613f51565b612b8b613f67565b91612b94613f7d565b91612b9d613f93565b93612ba6613fa9565b612bae613fb8565b908451955f19870196871161058c576020976001600160801b036001600160a01b03928364ffffffffff6040612be76115a39d8d613fc7565b5101511697816040519a612bfa8c613b9b565b168a52168b89015216604087015216606085015215156080840152151560a083015264ffffffffff421660c083015260e0820152612c3736613fef565b610100820152614991565b90503d805f833e612c538183613bf1565b8101906020818303126106315780519067ffffffffffffffff8211610631570181601f8201121561063157805190612c8a82613efe565b92612c986040519485613bf1565b8284526020606081860194028301019181831161063157602001925b828410612cc5575050505081612b7a565b6060848303126106315760405190612cdc82613b6b565b612ce585613f16565b825260208501519067ffffffffffffffff821682036106315782602092836060950152612d1460408801613f2a565b6040820152815201930192612cb4565b919350916060806001926001600160801b03612d3f88613c2f565b16815267ffffffffffffffff612d5760208901613f3c565b16602082015264ffffffffff612d6f60408901613aee565b166040820152019401910191849392612b47565b3461063157602036600319011261063157600435612d9f614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c1615612f3257805f526003602052612df46001600160a01b0360405f205416826148e0565b15611aff57805f5260036020526001600160a01b0360405f205416151580612f2b575b80612f0e575b612efc577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612ec5575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612eb357005b637e27328960e01b5f5260045260245ffd5b612ee4835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612e6b565b6349d74b1160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615612e1d565b505f612e17565b7fa6ba32da000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461063157611279612f6e366139fb565b9060405192612f7e602085613bf1565b5f8452614172565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b3461063157602036600319011261063157600435612ff2614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c165f1461303b5763449491f560e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611b155761306d815f52600a6020526001600160a01b0360405f205416331490565b15611aff5761307b816142a3565b90805f52600a602052613093600260405f20016148ae565b916001600160801b038351166001600160801b0382161015611aec57815f52600a60205260ff60405f205460f01c1615611ad957806001600160801b036020816130e7948188511603169501511690613c65565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115613288575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506131d16001600160a01b03600160405f20015416946119c0888588615b64565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f20541661321457005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561053957630d4af11f60e31b916001600160e01b0319915f91613269575016036104f857005b613282915060203d602011610532576105248183613bf1565b846104ef565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055613131565b34610631576020366003190112610631576132c661399e565b6001600160a01b035f54169033820361340557806001600160a01b03913b156133d957166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610539575f916133aa575b501561337f57805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f976c0d64000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6133cc915060203d6020116133d2575b6133c48183613bf1565b810190613ee6565b82613334565b503d6133ba565b7f65453b0d000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b34610631576020366003190112610631576001600160a01b0361343d61399e565b165f526009602052602060ff60405f2054166040519015158152f35b346106315761127961346a366139fb565b91613cb4565b34610631575f366003190112610631576020600754604051908152f35b346106315760203660031901126106315760043567ffffffffffffffff8111610631576134be9036906004016139ca565b9036819003601e1901905f5b83811015611279578060051b8201358381121561063157820180359067ffffffffffffffff821161063157602001813603811361063157815f92918392604051928392833781018381520390305af4613521613c85565b901561353057506001016134ca565b61356e906040519182917fd9354485000000000000000000000000000000000000000000000000000000008352602060048401526024830190613979565b0390fd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576135aa9061468b565b6005811015610afa5780602091159081156135cb575b506040519015158152f35b6001915014826135c0565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576020905f90805f52600a835260ff60405f205460f01c168061366b575b613639575b506001600160801b0360405191168152f35b6136659150805f52600a835261365f6001600160801b03600260405f20015416916142a3565b90613c65565b82613627565b50805f52600a835260ff600160405f20015460a01c1615613622565b34610631576040366003190112610631576136a061399e565b6024356136ac81614282565b33151580613779575b80613746575b61371a5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156136bb565b50336001600160a01b03821614156136b5565b34610631576020366003190112610631576020612146600435613c43565b34610631575f366003190112610631576040515f6001548060011c9060018116801561385b575b6020831081146116955782855290811561167157506001146137fd57610c7f836115ff81850382613bf1565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210613841575090915081016020016115ff6115ef565b919260018160209254838588010152019101909291613829565b91607f16916137d1565b34610631575f36600319011261063157602060405167016345785d8a00008152f35b3461063157602036600319011261063157600435906001600160e01b0319821680920361063157817f4906490600000000000000000000000000000000000000000000000000000000602093149081156138e3575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561392e575b811561391d575b50836138dc565b6301ffc9a760e01b91501483613916565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061390f565b5f5b8381106139695750505f910152565b818101518382015260200161395a565b9060209161399281518092818552858086019101613958565b601f01601f1916010190565b600435906001600160a01b038216820361063157565b602435906001600160a01b038216820361063157565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501948460051b01011161063157565b6060906003190112610631576004356001600160a01b038116810361063157906024356001600160a01b0381168103610631579060443590565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501946060850201011161063157565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501948460061b01011161063157565b90602080835192838152019201905f5b818110613ab45750505090565b9091926020604082613ae3600194885164ffffffffff602080926001600160801b038151168552015116910152565b019401929101613aa7565b359064ffffffffff8216820361063157565b90602080835192838152019201905f5b818110613b1d5750505090565b9091926020606082613b60600194885164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019401929101613b10565b6060810190811067ffffffffffffffff821117613b8757604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff821117613b8757604052565b6040810190811067ffffffffffffffff821117613b8757604052565b610160810190811067ffffffffffffffff821117613b8757604052565b90601f8019910116810190811067ffffffffffffffff821117613b8757604052565b67ffffffffffffffff8111613b8757601f01601f191660200190565b35906001600160801b038216820361063157565b613c4c81614282565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161058c57565b3d15613caf573d90613c9682613c13565b91613ca46040519384613bf1565b82523d5f602084013e565b606090565b91906001600160a01b03168015610dec57815f5260036020526001600160a01b0360405f205416151580613ede575b80613ec1575b613eae577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613df9575b6001600160a01b03935085613dc2575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303613daa57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613de1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613d49565b9192905080613e57575b15613e1057828291613d39565b8284613e2857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613e85575b80613e035750825f526005602052336001600160a01b0360405f20541614613e03565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613e62565b506349d74b1160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613ce9565b506001613ce3565b90816020910312610631575180151581036106315790565b67ffffffffffffffff8111613b875760051b60200190565b51906001600160801b038216820361063157565b519064ffffffffff8216820361063157565b359067ffffffffffffffff8216820361063157565b6004356001600160a01b03811681036106315790565b6024356001600160a01b03811681036106315790565b6044356001600160801b03811681036106315790565b6064356001600160a01b03811681036106315790565b60843580151581036106315790565b60a43580151581036106315790565b8051821015613fdb5760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b60409060c3190112610631576040519061400882613bb8565b8160c4356001600160a01b0381168103610631578152602060e435910152565b9190811015613fdb5760051b0190565b906101406003198301126106315760405161405281613b9b565b80926004356001600160a01b03811681036106315782526024356001600160a01b03811681036106315760208301526044356001600160801b03811681036106315760408301526064356001600160a01b0381168103610631576060830152608435801515810361063157608083015260a43580151581036106315760a083015260c43564ffffffffff811681036106315760c083015260e43564ffffffffff811681036106315760e0830152604061010480920312610631576040519161411983613bb8565b81356001600160a01b038116810361063157610100926020918552013560208401520152565b6040519061414c82613b6b565b5f6040838281528260208201520152565b6101043564ffffffffff811681036106315790565b9061417e838284613cb4565b803b61418b575b50505050565b6020916141d16001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613979565b03815f865af15f9181614241575b5061420d57506141ed613c85565b805190816142085782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361422f57505f808080614185565b633250574960e11b5f5260045260245ffd5b61425b91925060203d602011610532576105248183613bf1565b905f6141df565b9081602091031261063157516001600160e01b0319811681036106315790565b805f5260036020526001600160a01b0360405f205416908115612eb3575090565b5f64ffffffffff421690825f52600a6020528164ffffffffff60405f205460a01c16101561468457825f52600a6020528164ffffffffff60405f205460c81c16111561466757825f52600a60205260ff600160405f20015460b81c166003811015610afa57600103614451575050805f52600c60205260405f2090805f52600a602052600260405f20015460801c905f52600a60205264ffffffffff60405f205460a01c16906040519283917f6d0434810000000000000000000000000000000000000000000000000000000083526064830160606004850152825480915260848401925f5260205f20905f5b81811061440b575050509060209383926024840152604483015203817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b90506020813d602011614403575b816143ef60209383613bf1565b810103126106315761440090613f16565b90565b3d91506143e2565b82546001600160801b0381168652608081901c67ffffffffffffffff16602087015260c01c64ffffffffff16604086015287955060609094019360019283019201614390565b825f52600a60205260ff600160405f20015460b81c166003811015610afa576145355750815f52600b60205264ffffffffff60405f20541611614530575f908152600a60209081526040918290206002810154905492517ea57c350000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260809190911c602482015264ffffffffff60a084901c8116604483015260c89390931c9092166064830152816084817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b505f90565b92918091505f52600a60205260ff600160405f20015460b81c166003811015610afa576002146145625750565b9091505f52600d60205260405f2080549061457c82613efe565b9161458a6040519384613bf1565b8083526020830180925f5260205f205f915b83831061462b5750505050815115613fdb5764ffffffffff60204292510151161161453057602061460191604051809381927f5515a8160000000000000000000000000000000000000000000000000000000083528460048401526024830190613a97565b03817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b60016020819260405161463d81613bb8565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061459c565b50505f52600a6020526001600160801b03600260405f2001541690565b5050505f90565b805f52600a60205260ff600160405f20015460a01c165f146146ad5750600490565b805f52600a60205260405f205460f81c61471457805f52600a60205264ffffffffff60405f205460a01c164210614530576146e7816142a3565b905f52600a6020526001600160801b0380600260405f200154169116105f1461470f57600190565b600290565b50600390565b90805f5260036020526001600160a01b0360405f205416151580614842575b80614825575b612efc577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836147ee575b16806147d6575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055614792565b61480d835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561478b565b50805f52600a60205260ff600160405f20015460b01c161561473f565b506001600160a01b0382161515614739565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361488657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b906040516148bb81613b6b565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b906001600160a01b03169081331491821561491a575b508115614901575090565b90506001600160a01b036149153392613c43565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6148f6565b908160409103126106315761497460206040519261496384613bb8565b61496c81613f16565b845201613f16565b602082015290565b8054821015613fdb575f5260205f2001905f90565b91906001600160a01b038351169060c084019164ffffffffff8351169160e086019364ffffffffff855116936001600160801b0360408901511690610100890194602086510151926040519788937f8d86721600000000000000000000000000000000000000000000000000000000855261010485019360048601526024850152604484015260648301526101006084830152845180915261012482019060208601905f5b8181106150165750505081906040937f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af49182156105395787945f93614fe5575b506007549185516001600160a01b031696815164ffffffffff1691815164ffffffffff16986080890199868b5115159160608c019b8c516001600160a01b03169060a0019788511515928c516001600160801b03169560405196614b0a88613b6b565b8752602087015f9052604087015f905260405197614b2789613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860018a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b191617178955511515614c0090899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57614d34876001600160a01b039261471a565b16614fb957614d5c6001600160a01b038a51166001600160801b038951169030903390615c40565b6001600160801b0360208801511680614f90575b5060018601600755859b85515f5b818110614e7e57505092614e7994926001600160a01b03614e5f9364ffffffffff808380807fe4b2b82a71eaf8e03605924b1a288d8ea6d28734c85f6aec6f58f27f1473d1629f9e9d9b51169f51169f51169f5115159751151594511694511660405194614deb86613b6b565b85525f6020860152604085015251511693614e2c604051998a998a523360208b015260408a01906001600160801b0360208092828151168552015116910152565b608088015260a087015260c086019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120840152610160610140840152610160830190613b00565b0390a4565b885f52600c60205260405f2090614e95818a613fc7565b5191805468010000000000000000811015613b8757614eb99160018201815561497c565b614f7d57826001600160801b03806001955116166001600160801b03198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501614d7e565b634e487b7160e01b5f525f60045260245ffd5b614fb3906001600160a01b038b51166001600160a01b0384515116903390615c40565b5f614d70565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b61500891935060403d60401161500f575b6150008183613bf1565b810190614946565b915f614aa7565b503d614ff6565b9194935091602060608261505b600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b01950191019188939492614a36565b805f52600a602052615081600260405f20016148ae565b90805f52600a60205260ff600160405f20015460a01c165f146150af5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6150ce5750614400906142a3565b61440091506001600160801b036040818351169201511690613c65565b91906001600160a01b038351169060c084019164ffffffffff8351169160e0860193604064ffffffffff865116946001600160801b03828a015116946101008a019560208751015190845198899485947f87edd65700000000000000000000000000000000000000000000000000000000865260048601526024850152604484015260648301526101006084830152615188610104830187613a97565b907f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af49182156105395787945f9361561d575b506007549185516001600160a01b031696815164ffffffffff1691815164ffffffffff16986080890199868b5115159160608c019b8c516001600160a01b03169060a0019788511515928c516001600160801b0316956040519661524e88613b6b565b8752602087015f9052604087015f90526040519761526b89613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860028a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561534490899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57615478876001600160a01b039261471a565b16614fb9576154a06001600160a01b038a51166001600160801b038951169030903390615c40565b6001600160801b03602088015116806155f4575b5060018601600755859b85515f5b81811061554957505092614e7994926001600160a01b0361552f9364ffffffffff808380807f3fbf4970c1a9f5fd9b4d744372d4e920f7f6283b4af7175bd002c6a063dfde539f9e9d9b51169f51169f51169f5115159751151594511694511660405194614deb86613b6b565b610120840152610160610140840152610160830190613a97565b885f52600d60205260405f2090615560818a613fc7565b5191805468010000000000000000811015613b87576155849160018201815561497c565b614f7d576020836001600160801b03806001965116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016154c2565b615617906001600160a01b038b51166001600160a01b0384515116903390615c40565b5f6154b4565b61563791935060403d60401161500f576150008183613bf1565b915f6151eb565b91906001600160a01b0383511660c0840164ffffffffff8151169060e0860164ffffffffff815116926001600160801b0360408901511664ffffffffff6101008a019760208951015193604051987f55572bf4000000000000000000000000000000000000000000000000000000008a5260048a0152602489015216948560448801526064870152608486015260a485015267016345785d8a000060c485015260408460e481737715be116061e014bb721b46dc78dd57c91fdf9b5af49081156105395787945f92615b1d575b506007549285516001600160a01b031696815164ffffffffff1690835164ffffffffff16986080890199878b5115159160608c019b8c516001600160a01b03169060a0019687511515928b516001600160801b0316956040519661576e88613b6b565b8752602087015f9052604087015f90526040519761578b89613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b01985f8a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561586390899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57615997886001600160a01b039261471a565b16614fb9576159bf6001600160a01b038a51166001600160801b038851169030903390615c40565b6001600160801b0360208701511680615af4575b5060018701600755869b81615ad5575b516001600160a01b031697516001600160a01b031698516001600160a01b03169951151592511515935164ffffffffff16945164ffffffffff169060405195615a2b87613b6b565b86526020860152604085015251516001600160a01b03169360405195865233602087015260408601615a71916001600160801b0360208092828151168552015116910152565b608085015260a084015260c08301615aa79164ffffffffff60408092828151168552826020820151166020860152015116910152565b6101208201526101407f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c91a4565b875f52600b60205260405f208264ffffffffff198254161790556159e3565b615b17906001600160a01b038b51166001600160a01b0385515116903390615c40565b5f6159d3565b615b3791925060403d60401161500f576150008183613bf1565b905f61570b565b61440090615b4b8161506a565b905f52600a602052600260405f20015460801c90613c65565b615bb9926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252615bb4606483613bf1565b615bbb565b565b5f806001600160a01b03615be493169360208151910182865af1615bdd613c85565b9083615c9a565b8051908115159182615c25575b5050615bfa5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b615c389250602080918301019101613ee6565b155f80615bf1565b9091926001600160a01b03615bb99481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252615bb4608483613bf1565b90615cd75750805115615caf57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615d1d575b615ce8575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615ce056fea164736f6c634300081a000a"; + hex"60c0604052346103ce57615f836060813803918261001c816103d2565b9384928339810103126103ce5780516001600160a01b038116908190036103ce5760208201516001600160a01b03811692908390036103ce576040015161006360406103d2565b92601284527114d8589b1a595c88131bd8dadd5c0813919560721b602085015261008d60406103d2565b600a81526905341422d4c4f434b55560b41b6020820152306080525f80546001600160a01b031916851781559093907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a383516001600160401b0381116102df57600154600181811c911680156103c4575b60208210146102c157601f8111610361575b50602094601f82116001146102fe579481929394955f926102f3575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102df57600254600181811c911680156102d5575b60208210146102c157601f811161025e575b506020601f82116001146101fb57819293945f926101f0575b50508160011b915f199060031b1c1916176002555b600880546001600160a01b03191691909117905560a0526001600755604051615b8b90816103f8823960805181614584015260a051818181612108015281816146d401526150450152f35b015190505f80610190565b601f1982169060025f52805f20915f5b8181106102465750958360019596971061022e575b505050811b016002556101a5565b01515f1960f88460031b161c191690555f8080610220565b9192602060018192868b01518155019401920161020b565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102b7575b601f0160051c01905b8181106102ac5750610177565b5f815560010161029f565b9091508190610296565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610165565b634e487b7160e01b5f52604160045260245ffd5b015190505f8061012f565b601f1982169560015f52805f20915f5b88811061034957508360019596979810610331575b505050811b01600155610144565b01515f1960f88460031b161c191690555f8080610323565b9192602060018192868501518155019401920161030e565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ba575b601f0160051c01905b8181106103af5750610113565b5f81556001016103a2565b9091508190610399565b90607f1690610101565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102df5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146137e057508063027b6744146137be57806306fdde0314613703578063081812fc146136e5578063095ea7b3146135e05780631400ecec1461352f5780631b1a433f1461344f5780631c1cdd4c146133eb5780631e897afb146133065780631e99d569146132e957806323b872dd146132d2578063303acc8514613295578063406887cb1461312657806340e58ee514612e4f578063425d30dd14612dff57806342842e0e14612dd657806342966c6814612bfc57806342e94a7b14612935578063442675701461290f5780634857501f1461289e5780634869e12d146128645780634cc55e11146124bd5780636352211e146122035780636611ceab146122325780636d0cee751461220357806370a082311461219957806375829def1461212b57806377163c1d146120f1578063780a82c8146120525780637cad6cd114611f755780637de6b1db14611e285780637f5799f914611d145780638222b69414611be55780638659c2701461182d5780638f69b993146117ad5780639067b6771461175e57806395d89b4114611656578063a22cb465146115a2578063a80fc07114611551578063ab605ced14611508578063ad35efd4146114bd578063b25645691461146d578063b637b86514611346578063b88d4fde146112bc578063b8a3be6614611287578063b971302a14611239578063bc2be1be146111ea578063c156a11d14610dcb578063c87b56dd14610cc0578063d4dbd20b14610c6f578063d511609f14610c24578063d6a03d3114610b4e578063d975dfed14610b03578063e6c417eb14610a98578063e985e9c514610a3f578063ea5ead19146106fc578063eac8f5b8146106ab578063f590c1761461064f578063f851a4401461062a5763fdd46d60146102b0575f80fd5b34610626576060366003190112610626576004356102cc61390d565b906044356001600160801b038116809103610626576102e961457a565b815f52600a60205260ff600160405f20015460a81c161561061357815f52600a60205260ff600160405f20015460a01c16610600576001600160a01b03831680156105ed57825f5260036020526001600160a01b0360405f2054169384821415806105dc575b6105c25782156105af576001600160801b0361036a85615996565b168084116105955750835f52600a60205282600260405f20015460801c016001600160801b038111610581576103c990855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526103e0600260405f2001614e77565b6001600160801b036104048160208401511692826040818351169201511690613bcc565b16111561054f575b835f52600a602052610430836001600160a01b03600160405f2001541692836159bc565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610539575b61049657005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af190811561052e576392b9102b60e01b916001600160e01b0319915f916104ff575b5016036104ed57005b635f3a039d60e01b5f5260045260245ffd5b610521915060203d602011610527575b6105198183613b4a565b8101906141c4565b5f6104e4565b503d61050f565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f205416610490565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b1916905561040c565b634e487b7160e01b5f52601160045260245ffd5b8385632176546160e01b5f5260045260245260445260645ffd5b83633dd1eadf60e21b5f5260045260245ffd5b50826297d0a360e61b5f526004523360245260445260645ffd5b506105e78585614ea9565b1561034f565b826316c90d2760e21b5f5260045260245ffd5b5063449491f560e11b5f5260045260245ffd5b50631643770160e21b5f5260045260245ffd5b5f80fd5b34610626575f3660031901126106265760206001600160a01b035f5416604051908152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a602052602060405f205460f81c6040519015158152f35b631643770160e21b5f5260045260245ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346106265760403660031901126106265760043561071861390d565b61072182615996565b9161072a61457a565b805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460a01c16610a2d576001600160a01b0382168015610a1a57815f5260036020526001600160a01b0360405f205416938482141580610a09575b6109ef576001600160801b03169283156109dc576001600160801b036107b584615996565b168085116109c25750825f52600a60205283600260405f20015460801c016001600160801b0381116105815761081490845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261082b600260405f2001614e77565b6001600160801b0361084f8160208401511692826040818351169201511690613bcc565b161115610990575b825f52600a60205261087b846001600160a01b03600160405f2001541692836159bc565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1833314158061097a575b6108eb575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af190811561052e576392b9102b60e01b916001600160e01b0319915f9161095b575b5016036109485781806108e0565b50635f3a039d60e01b5f5260045260245ffd5b610974915060203d602011610527576105198183613b4a565b8561093a565b50835f52600960205260ff60405f2054166108db565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610857565b8484632176546160e01b5f5260045260245260445260645ffd5b82633dd1eadf60e21b5f5260045260245ffd5b50906297d0a360e61b5f526004523360245260445260645ffd5b50610a148584614ea9565b15610790565b506316c90d2760e21b5f5260045260245ffd5b63449491f560e11b5f5260045260245ffd5b3461062657604036600319011261062657610a586138f7565b6001600160a01b03610a6861390d565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a60205260ff600160405f20015460b81c166040516003821015610aef576020918152f35b634e487b7160e01b5f52602160045260245ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c161561069957610b3d602091615996565b6001600160801b0360405191168152f35b3461062657366003190161016081126106265761014013610626576101443567ffffffffffffffff811161062657610b8a9036906004016139bf565b610b9261457a565b610b9b36613c25565b90610ba581613d45565b92610bb36040519485613b4a565b818452602084019160061b81019036821161062657915b818310610be5576020610bdd8686614f90565b604051908152f35b6040833603126106265760206040918251610bff81613af4565b610c0886613b96565b8152610c15838701613a47565b83820152815201920191610bca565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a6020526020600260405f20015460801c604051908152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a60205260206001600160801b03600360405f20015416604051908152f35b3461062657602036600319011261062657600435610cdd816141e4565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa801561052e575f90610d4e575b610d4a906040519182916020835260208301906138d2565b0390f35b503d805f833e610d5e8183613b4a565b8101906020818303126106265780519067ffffffffffffffff821161062657019080601f8301121561062657815191610d9683613b6c565b91610da46040519384613b4a565b8383526020848301011161062657610d4a92610dc691602080850191016138b1565b610d32565b3461062657604036600319011261062657600435610de761390d565b610def61457a565b815f52600a60205260ff600160405f20015460a81c161561061357815f5260036020526001600160a01b0360405f20541690610e2b8284614ea9565b156111d3576001600160801b03610e4184615996565b169081158015610eca575b506001600160a01b03811615610eb757610e6e846001600160a01b0392614d3d565b169182610e885783637e27328960e01b5f5260045260245ffd5b8084918403610e9c57602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610ed261457a565b845f52600a60205260ff600160405f20015460a81c16156111c057845f52600a60205260ff600160405f20015460a01c166111ad57831561119a57845f5260036020526001600160a01b0360405f205416908185141580611189575b61116f5761115c576001600160801b03610f4786615996565b168084116111425750845f52600a60205282600260405f20015460801c016001600160801b03811161058157610fa690865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610fbd600260405f2001614e77565b6001600160801b03610fe18160208401511692826040818351169201511690613bcc565b161115611110575b845f52600a6020526001600160a01b03600160405f2001541661100d8486836159bc565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a180331415806110fa575b15610e4c576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af190811561052e576392b9102b60e01b916001600160e01b0319915f916110db575b501614610e4c57635f3a039d60e01b5f5260045260245ffd5b6110f4915060203d602011610527576105198183613b4a565b886110c2565b50805f52600960205260ff60405f20541661106d565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610fe9565b8386632176546160e01b5f5260045260245260445260645ffd5b84633dd1eadf60e21b5f5260045260245ffd5b84866297d0a360e61b5f526004523360245260445260645ffd5b506111948287614ea9565b15610f2e565b846316c90d2760e21b5f5260045260245ffd5b8463449491f560e11b5f5260045260245ffd5b84631643770160e21b5f5260045260245ffd5b82634dda2c3960e11b5f526004523360245260445ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a60205260206001600160a01b0360405f205416604051908152f35b34610626576020366003190112610626576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b34610626576080366003190112610626576112d56138f7565b6112dd61390d565b6064359167ffffffffffffffff831161062657366023840112156106265782600401359161130a83613b6c565b926113186040519485613b4a565b8084523660248287010111610626576020815f92602461134498018388013785010152604435916140d4565b005b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460b81c166003811015610aef5760010361143c575f52600c60205260405f2080546113b181613d45565b916113bf6040519384613b4a565b81835260208301905f5260205f205f915b8383106113ed5760405160208082528190610d4a90820188613a59565b6001602081926040516113ff81613ac4565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c1660408201528152019201920191906113d0565b5f52600a60205261146360ff600160405f20015460b81c16637382cd8b60e01b5f52613b88565b600160245260445ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699576114f590614ca9565b6040516005821015610aef576020918152f35b3461062657366003190161016081126106265761014013610626576101443564ffffffffff8116810361062657610bdd60209161154361457a565b61154c36613c25565b6154c3565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a60205260206001600160801b03600260405f20015416604051908152f35b34610626576040366003190112610626576115bb6138f7565b60243590811515809203610626576001600160a01b031690811561162a57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b34610626575f366003190112610626576040515f6002548060011c90600181168015611754575b6020831081146117405782855290811561171c57506001146116be575b610d4a836116aa81850382613b4a565b6040519182916020835260208301906138d2565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210611702575090915081016020016116aa61169a565b9192600181602092548385880101520191019092916116ea565b60ff191660208086019190915291151560051b840190910191506116aa905061169a565b634e487b7160e01b5f52602260045260245ffd5b91607f169161167d565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699576117e590614ca9565b600581101580610aef5760028214908115611821575b811561180f575b6020826040519015158152f35b9050610aef5760046020911482611802565b5050600381145f6117fb565b346106265760203660031901126106265760043567ffffffffffffffff81116106265761185e903690600401613954565b9061186761457a565b5f915b80831061187357005b61187e8382846140af565b359261188861457a565b835f52600a60205260ff600160405f20015460a81c1615611bd257835f52600a60205260ff600160405f20015460a01c165f146118d2578363449491f560e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611bc057611907815f52600a6020526001600160a01b0360405f205416331490565b15611baa5761191581614205565b90805f52600a60205261192d600260405f2001614e77565b916001600160801b038351166001600160801b0382161015611b9757815f52600a60205260ff60405f205460f01c1615611b8457806001600160801b03602081611981948188511603169501511690613bcc565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611b5f575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa50611a936001600160a01b03600160405f2001541694611a6b8885886159bc565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611ae4575b5050505050600101919061186a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561052e57630d4af11f60e31b916001600160e01b0319915f91611b41575b5016036104ed5780808080611ad5565b611b59915060203d8111610527576105198183613b4a565b87611b31565b825f52600a602052600160405f2001600160a01b60ff60a01b198254161790556119cb565b50635c7470b760e01b5f5260045260245ffd5b5063fa36c71760e01b5f5260045260245ffd5b634dda2c3960e11b5f526004523360245260445ffd5b63e707ae4f60e01b5f5260045260245ffd5b83631643770160e21b5f5260045260245ffd5b34610626573660031901610140811261062657610100136106265760403661010319011261062657611c1561457a565b64ffffffffff4216604051611c2981613af4565b8181525f602082018181529164ffffffffff611c436140bf565b16611cfb575b610124359264ffffffffff841684036106265764ffffffffff84602096610bdd965001169052611c77614039565b90611c8061404f565b611c88614065565b6001600160a01b03611c9861407b565b6001600160801b03611ca8614091565b9383611cb26140a0565b96816040519a611cc18c613b10565b168a52168b89015216604087015216606085015215156080840152151560a083015260c0820152611cf136613bec565b60e08201526154c3565b905064ffffffffff611d0b6140bf565b84011690611c49565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460b81c166003811015610aef57600203611df7575f52600d60205260405f208054611d7f81613d45565b91611d8d6040519384613b4a565b81835260208301905f5260205f205f915b838310611dbb5760405160208082528190610d4a908201886139f0565b600160208192604051611dcd81613af4565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190611d9e565b5f52600a602052611e1e60ff600160405f20015460b81c16637382cd8b60e01b5f52613b88565b600260245260445ffd5b3461062657602036600319011261062657600435611e4461457a565b805f52600a60205260ff600160405f20015460a81c161561069957611e6881614ca9565b6005811015610aef5760048103611e8c575063449491f560e11b5f5260045260245ffd5b60038103611ea7575063e707ae4f60e01b5f5260045260245ffd5b600214611f6357611ecc815f52600a6020526001600160a01b0360405f205416331490565b15611baa57805f52600a60205260ff60405f205460f01c1615611f51576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635c7470b760e01b5f5260045260245ffd5b63fa36c71760e01b5f5260045260245ffd5b34610626576020366003190112610626576004356001600160a01b038116809103610626576001600160a01b035f541633810361203c575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116105815760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460b81c166003811015610aef576120c1575f52600b602052602064ffffffffff60405f205416604051908152f35b5f52600a6020526120e860ff600160405f20015460b81c16637382cd8b60e01b5f52613b88565b5f60245260445ffd5b34610626575f3660031901126106265760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610626576020366003190112610626576121446138f7565b5f546001600160a01b03811633810361203c57506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b34610626576020366003190112610626576001600160a01b036121ba6138f7565b1680156121d7575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346106265760203660031901126106265760206122216004356141e4565b6001600160a01b0360405191168152f35b3461062657366003190161012081126106265761010013610626576101043567ffffffffffffffff81116106265761226e9036906004016139bf565b61227661457a565b6040519182917f66f401dd000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b81811061247957845f8180870381737715be116061e014bb721b46dc78dd57c91fdf9b5af490811561052e575f916123b7575b5080515f198101908111610581578164ffffffffff602061230c610bdd948296614011565b510151166040519061231d82613af4565b64ffffffffff4216825284820152612333614039565b9061233c61404f565b612344614065565b6001600160a01b0361235461407b565b6001600160801b03612364614091565b938361236e6140a0565b96816040519a61237d8c613b10565b168a52168b89015216604087015216606085015215156080840152151560a083015260c08201526123ad36613bec565b60e0820152614f90565b90503d805f833e6123c88183613b4a565b8101906020818303126106265780519067ffffffffffffffff8211610626570181601f82011215610626578051906123ff82613d45565b9261240d6040519485613b4a565b82845260208085019360061b8301019181831161062657602001925b82841061243a5750505050816122e7565b604084830312610626576020604091825161245481613af4565b61245d87613feb565b815261246a838801613fff565b83820152815201930192612429565b919350916040806001926001600160801b0361249488613b96565b16815264ffffffffff6124a960208901613a47565b1660208201520194019101918493926122b4565b346106265760403660031901126106265760043567ffffffffffffffff8111610626576124ee903690600401613954565b60243567ffffffffffffffff81116106265761250e903690600401613954565b61251993919361457a565b808303612835575f5b83811061252b57005b6125368185856140af565b356125428286866140af565b355f5260036020526001600160a01b0360405f205416906125648385896140af565b356001600160801b03811690818103610626575061258061457a565b815f52600a60205260ff600160405f20015460a81c161561061357815f52600a60205260ff600160405f20015460a01c16610600578215610a1a57815f5260036020526001600160a01b0360405f205416928381141580612824575b61280b5781156109dc576001600160801b036125f784615996565b168083116127f15750825f52600a60205281600260405f20015460801c016001600160801b0381116105815761265690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a60205261266d600260405f2001614e77565b6001600160801b036126918160208401511692826040818351169201511690613bcc565b1611156127bf575b825f52600a6020526001600160a01b03600160405f200154166126bd8383836159bc565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806127a9575b61272e575b50505050600101612522565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af190811561052e576392b9102b60e01b916001600160e01b0319915f9161278b575b5016036104ed57808080612722565b6127a3915060203d8111610527576105198183613b4a565b8961277c565b50835f52600960205260ff60405f20541661271d565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612699565b8284632176546160e01b5f5260045260245260445260645ffd5b826297d0a360e61b5f526004523360245260445260645ffd5b5061282f8484614ea9565b156125dc565b827fc0a1a35a000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c161561069957610b3d602091614f0f565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f6128d782614ca9565b6005811015610aef576002036128f5575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c166128e8565b34610626575f3660031901126106265760206001600160a01b0360085416604051908152f35b3461062657366003190161012081126106265761010013610626576101043567ffffffffffffffff811161062657612971903690600401613923565b61297961457a565b6040519182917fca31a854000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b818110612b9d57845f8180870381737715be116061e014bb721b46dc78dd57c91fdf9b5af490811561052e575f91612abb575b5080515f198101908111610581578164ffffffffff6040612a10610bdd94602096614011565b5101511660405190612a2182613af4565b64ffffffffff4216825284820152612a37614039565b90612a4061404f565b612a48614065565b6001600160a01b03612a5861407b565b6001600160801b03612a68614091565b9383612a726140a0565b96816040519a612a818c613b10565b168a52168b89015216604087015216606085015215156080840152151560a083015260c0820152612ab136613bec565b60e082015261461f565b90503d805f833e612acc8183613b4a565b8101906020818303126106265780519067ffffffffffffffff8211610626570181601f8201121561062657805190612b0382613d45565b92612b116040519485613b4a565b8284526020606081860194028301019181831161062657602001925b828410612b3e5750505050816129ea565b6060848303126106265760405190612b5582613ac4565b612b5e85613feb565b825260208501519067ffffffffffffffff821682036106265782602092836060950152612b8d60408801613fff565b6040820152815201930192612b2d565b919350916060806001926001600160801b03612bb888613b96565b16815267ffffffffffffffff612bd060208901613d5d565b16602082015264ffffffffff612be860408901613a47565b1660408201520194019101918493926129b7565b3461062657602036600319011261062657600435612c1861457a565b805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460a01c1615612dab57805f526003602052612c6d6001600160a01b0360405f20541682614ea9565b15611baa57805f5260036020526001600160a01b0360405f205416151580612da4575b80612d87575b612d75577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612d3e575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612d2c57005b637e27328960e01b5f5260045260245ffd5b612d5d835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612ce4565b6349d74b1160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615612c96565b505f612c90565b7fa6ba32da000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461062657611344612de736613985565b9060405192612df7602085613b4a565b5f84526140d4565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b3461062657602036600319011261062657600435612e6b61457a565b805f52600a60205260ff600160405f20015460a81c161561069957805f52600a60205260ff600160405f20015460a01c165f14612eb45763449491f560e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611bc057612ee6815f52600a6020526001600160a01b0360405f205416331490565b15611baa57612ef481614205565b90805f52600a602052612f0c600260405f2001614e77565b916001600160801b038351166001600160801b0382161015611b9757815f52600a60205260ff60405f205460f01c1615611b8457806001600160801b03602081612f60948188511603169501511690613bcc565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115613101575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061304a6001600160a01b03600160405f2001541694611a6b8885886159bc565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f20541661308d57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561052e57630d4af11f60e31b916001600160e01b0319915f916130e2575016036104ed57005b6130fb915060203d602011610527576105198183613b4a565b846104e4565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612faa565b346106265760203660031901126106265761313f6138f7565b6001600160a01b035f54169033820361327e57806001600160a01b03913b1561325257166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa90811561052e575f91613223575b50156131f857805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f976c0d64000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b613245915060203d60201161324b575b61323d8183613b4a565b810190613fd3565b826131ad565b503d613233565b7f65453b0d000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b34610626576020366003190112610626576001600160a01b036132b66138f7565b165f526009602052602060ff60405f2054166040519015158152f35b34610626576113446132e336613985565b91613da1565b34610626575f366003190112610626576020600754604051908152f35b346106265760203660031901126106265760043567ffffffffffffffff811161062657613337903690600401613954565b9036819003601e1901905f5b83811015611344578060051b8201358381121561062657820180359067ffffffffffffffff821161062657602001813603811361062657815f92918392604051928392833781018381520390305af461339a613d72565b90156133a95750600101613343565b6133e7906040519182917fd93544850000000000000000000000000000000000000000000000000000000083526020600484015260248301906138d2565b0390fd5b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c16156106995761342390614ca9565b6005811015610aef578060209115908115613444575b506040519015158152f35b600191501482613439565b3461062657366003190161016081126106265761014013610626576101443567ffffffffffffffff81116106265761348b903690600401613923565b61349361457a565b61349c36613c25565b906134a681613d45565b926134b46040519485613b4a565b818452606060208501920281019036821161062657915b8183106134de576020610bdd868661461f565b6060833603126106265760206060916040516134f981613ac4565b61350286613b96565b815261350f838701613d5d565b8382015261351f60408701613a47565b60408201528152019201916134cb565b3461062657602036600319011261062657600435805f52600a60205260ff600160405f20015460a81c1615610699576020905f90805f52600a835260ff60405f205460f01c16806135c4575b613592575b506001600160801b0360405191168152f35b6135be9150805f52600a83526135b86001600160801b03600260405f2001541691614205565b90613bcc565b82613580565b50805f52600a835260ff600160405f20015460a01c161561357b565b34610626576040366003190112610626576135f96138f7565b602435613605816141e4565b331515806136d2575b8061369f575b6136735781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f20541615613614565b50336001600160a01b038216141561360e565b34610626576020366003190112610626576020612221600435613baa565b34610626575f366003190112610626576040515f6001548060011c906001811680156137b4575b6020831081146117405782855290811561171c575060011461375657610d4a836116aa81850382613b4a565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061379a575090915081016020016116aa61169a565b919260018160209254838588010152019101909291613782565b91607f169161372a565b34610626575f36600319011261062657602060405167016345785d8a00008152f35b3461062657602036600319011261062657600435906001600160e01b0319821680920361062657817f49064906000000000000000000000000000000000000000000000000000000006020931490811561383c575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115613887575b8115613876575b5083613835565b6301ffc9a760e01b9150148361386f565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150613868565b5f5b8381106138c25750505f910152565b81810151838201526020016138b3565b906020916138eb815180928185528580860191016138b1565b601f01601f1916010190565b600435906001600160a01b038216820361062657565b602435906001600160a01b038216820361062657565b9181601f840112156106265782359167ffffffffffffffff8311610626576020808501946060850201011161062657565b9181601f840112156106265782359167ffffffffffffffff8311610626576020808501948460051b01011161062657565b6060906003190112610626576004356001600160a01b038116810361062657906024356001600160a01b0381168103610626579060443590565b9181601f840112156106265782359167ffffffffffffffff8311610626576020808501948460061b01011161062657565b90602080835192838152019201905f5b818110613a0d5750505090565b9091926020604082613a3c600194885164ffffffffff602080926001600160801b038151168552015116910152565b019401929101613a00565b359064ffffffffff8216820361062657565b90602080835192838152019201905f5b818110613a765750505090565b9091926020606082613ab9600194885164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019401929101613a69565b6060810190811067ffffffffffffffff821117613ae057604052565b634e487b7160e01b5f52604160045260245ffd5b6040810190811067ffffffffffffffff821117613ae057604052565b610100810190811067ffffffffffffffff821117613ae057604052565b610160810190811067ffffffffffffffff821117613ae057604052565b90601f8019910116810190811067ffffffffffffffff821117613ae057604052565b67ffffffffffffffff8111613ae057601f01601f191660200190565b6003811015610aef57600452565b35906001600160801b038216820361062657565b613bb3816141e4565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161058157565b60409060c31901126106265760405190613c0582613af4565b8160c4356001600160a01b0381168103610626578152602060e435910152565b9061014060031983011261062657604051613c3f81613b10565b80926004356001600160a01b03811681036106265782526024356001600160a01b03811681036106265760208301526044356001600160801b03811681036106265760408301526064356001600160a01b0381168103610626576060830152608435801515810361062657608083015260a43580151581036106265760a0830152604060c31982011261062657604051613cd881613af4565b60c43564ffffffffff8116810361062657815260e43564ffffffffff8116810361062657602082015260c08301526040610104809203126106265760405191613d2083613af4565b81356001600160a01b03811681036106265760e0926020918552013560208401520152565b67ffffffffffffffff8111613ae05760051b60200190565b359067ffffffffffffffff8216820361062657565b3d15613d9c573d90613d8382613b6c565b91613d916040519384613b4a565b82523d5f602084013e565b606090565b91906001600160a01b03168015610eb757815f5260036020526001600160a01b0360405f205416151580613fcb575b80613fae575b613f9b577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613ee6575b6001600160a01b03935085613eaf575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303613e9757505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613ece825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613e36565b9192905080613f44575b15613efd57828291613e26565b8284613f1557637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613f72575b80613ef05750825f526005602052336001600160a01b0360405f20541614613ef0565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613f4f565b506349d74b1160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613dd6565b506001613dd0565b90816020910312610626575180151581036106265790565b51906001600160801b038216820361062657565b519064ffffffffff8216820361062657565b80518210156140255760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b6004356001600160a01b03811681036106265790565b6024356001600160a01b03811681036106265790565b6044356001600160801b03811681036106265790565b6064356001600160a01b03811681036106265790565b60843580151581036106265790565b60a43580151581036106265790565b91908110156140255760051b0190565b6101043564ffffffffff811681036106265790565b906140e0838284613da1565b803b6140ed575b50505050565b6020916141336001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906138d2565b03815f865af15f91816141a3575b5061416f575061414f613d72565b8051908161416a5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361419157505f8080806140e7565b633250574960e11b5f5260045260245ffd5b6141bd91925060203d602011610527576105198183613b4a565b905f614141565b9081602091031261062657516001600160e01b0319811681036106265790565b805f5260036020526001600160a01b0360405f205416908115612d2c575090565b64ffffffffff421690805f52600a60205264ffffffffff60405f205460a01c169180831015614573575f828152600a6020526040902080546002909101546001600160801b03169160c89190911c64ffffffffff169081111561456c575f835f52600a60205260ff600160405f20015460b81c166003811015610aef57600181036143bc575050505090815f52600c60205260405f20915f52600a602052600260405f20015460801c906040519283917f63ec2f5a0000000000000000000000000000000000000000000000000000000083526064830160606004850152825480915260848401925f5260205f20905f5b818110614376575050509060209383926024840152604483015203817326f9d826bded47fc472526ae8095b75ac336963c5af490811561052e575f9161433c575b505b90565b90506020813d60201161436e575b8161435760209383613b4a565b810103126106265761436890613feb565b5f614337565b3d915061434a565b82546001600160801b0381168652608081901c67ffffffffffffffff16602087015260c01c64ffffffffff166040860152879550606090940193600192830192016142f6565b92949391928061445e575050805f52600b60205264ffffffffff60405f205416905f52600a602052600260405f20015460801c92604051947f24d5ab3e0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401526064830152608482015260208160a4817326f9d826bded47fc472526ae8095b75ac336963c5af490811561052e575f9161433c575090565b91935093506002915014614470575090565b90505f52600d60205260405f2060405180917f5515a8160000000000000000000000000000000000000000000000000000000082526024820160206004840152815480915260448301915f5260205f20905f5b81811061453a57505050908060209203817326f9d826bded47fc472526ae8095b75ac336963c5af490811561052e575f91614500575b505f614337565b90506020813d602011614532575b8161451b60209383613b4a565b810103126106265761452c90613feb565b5f6144f9565b3d915061450e565b82546001600160801b038116855260801c64ffffffffff166020850152859450604090930192600192830192016144c3565b5091505090565b5050505f90565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001630036145ac57565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b90816040910312610626576146026020604051926145f184613af4565b6145fa81613feb565b845201613feb565b602082015290565b8054821015614025575f5260205f2001905f90565b906146a492916001600160a01b038151169160c082019182516001600160801b036040830151169060e083019560208751015192604051998a937ffb6164dd0000000000000000000000000000000000000000000000000000000085526101048501936004860152602485019064ffffffffff60208092828151168552015116910152565b60648301526101006084830152845180915261012482019060208601905f5b818110614c555750505081906040937f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af495861561052e575f96614c24575b506007549582515f5b818110614b125750508151948451805164ffffffffff16906020015164ffffffffff16956080850197885115158b60608801998a516001600160a01b031660a08a019687511515928a516001600160801b0316956040519661479c88613ac4565b8752602087015f9052604087015f9052604051976147b989613b2d565b6001600160a01b0316885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860018a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561489b90899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610aef5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208501956001600160a01b038751168015610eb7576149cf8c6001600160a01b0392614d3d565b16614ae657614aab8b94614abf936001600160a01b038080807f37ba529dbe2c0eff025dc0325f5f31b6298126095fecc31e6c785a9a58b520209c8f6001600160801b0360208f8f600101600755614a3286855116848351169030903390615a13565b01511680614acb575b505051169c51169c51169c5115159651151591519251511695614a84604051998a998a523360208b015260408a01906001600160801b0360208092828151168552015116910152565b608088015260a087015260c086019064ffffffffff60208092828151168552015116910152565b610140610100850152610140840190613a59565b906101208301520390a4565b83614adf925116848a515116903390615a13565b8f5f614a3b565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600c60205260405f2090614b298187614011565b5191805468010000000000000000811015613ae057614b4d9160018201815561460a565b614c1157826001600160801b03806001955116166001600160801b03198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b169216171790550161473b565b634e487b7160e01b5f525f60045260245ffd5b614c4791965060403d604011614c4e575b614c3f8183613b4a565b8101906145d4565b945f614732565b503d614c35565b91949350916020606082614c9a600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b0195019101918a9394926146c3565b805f52600a60205260ff600160405f20015460a01c165f14614ccb5750600490565b805f52600a60205260405f205460f81c614d3757805f52600a60205264ffffffffff60405f205460a01c164210614d3257614d0581614205565b905f52600a6020526001600160801b0380600260405f200154169116105f14614d2d57600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f205416151580614e65575b80614e48575b612d75577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f2054169283614e11575b1680614df9575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055614db5565b614e30835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055614dae565b50805f52600a60205260ff600160405f20015460b01c1615614d62565b506001600160a01b0382161515614d5c565b90604051614e8481613ac4565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b906001600160a01b031690813314918215614ee3575b508115614eca575090565b90506001600160a01b03614ede3392613baa565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614ebf565b805f52600a602052614f26600260405f2001614e77565b90805f52600a60205260ff600160405f20015460a01c165f14614f545750602001516001600160801b031690565b90815f52600a60205260405f205460f81c614f73575061433990614205565b61433991506001600160801b036040818351169201511690613bcc565b9061501592916001600160a01b038151169160c082019182516001600160801b036040830151169060e083019560208751015192604051998a937f07aaee4b0000000000000000000000000000000000000000000000000000000085526101048501936004860152602485019064ffffffffff60208092828151168552015116910152565b60648301526101006084830152845180915261012482019060208601905f5b8181106154835750505081906040937f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af495861561052e575f96615462575b506007549582515f5b8181106153b75750508151948451805164ffffffffff16906020015164ffffffffff16956080850197885115158b60608801998a516001600160a01b031660a08a019687511515928a516001600160801b0316956040519661510d88613ac4565b8752602087015f9052604087015f90526040519761512a89613b2d565b6001600160a01b0316885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860028a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561520c90899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610aef5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208501956001600160a01b038751168015610eb7576153408c6001600160a01b0392614d3d565b16614ae6576153a38b94614abf936001600160a01b038080807f698bb53308d5520596fa20e0bd6e16c29eb8b8115f6e987397278c6c0757be089c8f6001600160801b0360208f8f600101600755614a3286855116848351169030903390615a13565b6101406101008501526101408401906139f0565b885f52600d60205260405f20906153ce8187614011565b5191805468010000000000000000811015613ae0576153f29160018201815561460a565b614c11576020836001600160801b03806001965116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016150ac565b61547c91965060403d604011614c4e57614c3f8183613b4a565b945f6150a3565b919493509160206040826154b4600194895164ffffffffff602080926001600160801b038151168552015116910152565b0195019101918a939492615034565b91906001600160a01b0383511660c08401516001600160801b03604086015116615539602060e0880151015192604051947f21e1a4bb0000000000000000000000000000000000000000000000000000000086526004860152602485019064ffffffffff60208092828151168552015116910152565b64ffffffffff84166064840152608483015260a482015267016345785d8a000060c482015260408160e481737715be116061e014bb721b46dc78dd57c91fdf9b5af490811561052e575f91615977575b506007549364ffffffffff8316615951575b80516001600160a01b03169260c082015192835164ffffffffff16936020015164ffffffffff1694608084019588875115159160608701516001600160a01b031660a0880198895115159287516001600160801b031695604051966155ff88613ac4565b8752602087015f9052604087015f90526040519761561c89613b2d565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b01985f8a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b1916171789555115156156f490899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610aef5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b03198254161790556001600160a01b036020840151168015610eb757615826886001600160a01b0392614d3d565b16614ae657866101409164ffffffffff7fcf9ef6a106311d590d4fb2ae5a0963a0b5e399f8e1e8280d8e80b262feea1b0f94600184016007556158856001600160a01b036060890151166001600160801b038551169030903390615a13565b6001600160801b0360208401511680615922575b506159126001600160a01b03885116976001600160a01b03602082015116996001600160a01b036060830151169b5115159051151590614a846001600160a01b0360e060c0860151950151511697604051998a523360208b015260408a01906001600160801b0360208092828151168552015116910152565b16610100830152610120820152a4565b61594b906001600160a01b0360608a0151166001600160a01b0360e08b01515116903390615a13565b5f615899565b845f52600b60205260405f2064ffffffffff841664ffffffffff1982541617905561559b565b615990915060403d604011614c4e57614c3f8183613b4a565b5f615589565b614339906159a381614f0f565b905f52600a602052600260405f20015460801c90613bcc565b615a11926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252615a0c606483613b4a565b615a6d565b565b9091926001600160a01b03615a119481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252615a0c608483613b4a565b5f806001600160a01b03615a9693169360208151910182865af1615a8f613d72565b9083615af2565b8051908115159182615ad7575b5050615aac5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b615aea9250602080918301019101613fd3565b155f80615aa3565b90615b2f5750805115615b0757805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615b75575b615b40575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615b3856fea164736f6c634300081a000a"; bytes public constant BYTECODE_MERKLE_FACTORY = - hex"608034609357601f615a8a38819003918201601f19168301916001600160401b03831184841017609757808492602094604052833981010312609357516001600160a01b038116908190036093575f80546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36159de90816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063070a6b8414610d0e5780631134f19414610cf157806345aa9357146109735780634d7c0f11146108a05780636f71d8f41461083057806375829def146107aa5780638af96dfe14610723578063b3ee17cc146102f9578063d498fcf514610265578063f255527814610135578063f851a440146101105763f946eef21461009d575f80fd5b3461010c57602036600319011261010c576004356001600160a01b035f54163381036100f65750806001556040519081527f7d41b7bcff330c958826f81c5de08357f286914f0758727ca23717d24f158fcc60203392a2005b6331b339a960e21b5f526004523360245260445ffd5b5f80fd5b3461010c575f36600319011261010c5760206001600160a01b035f5416604051908152f35b3461010c57604036600319011261010c576004356001600160a01b03811680910361010c57602435906001600160a01b03821680920361010c576001600160a01b035f54163381036100f65750801561023d576040517f164e68de0000000000000000000000000000000000000000000000000000000081528160048201526020816024815f875af1908115610232575f91610200575b5060405191825260208201527ff65e64e219c3199240f0fe17a71d01821ed2dd08283833094e12a9ad6883786560403392a3005b90506020813d60201161022a575b8161021b60209383610f14565b8101031261010c5751836101cc565b3d915061020e565b6040513d5f823e3d90fd5b7f38da7036000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461010c57604036600319011261010c5761027e610f5c565b602435906001600160a01b035f54163381036100f657506001600160a01b031690815f52600260205280600160405f20805460ff8116156102eb575b5001556040519081527f314737fce28d10af73c184056111a030c8124d005478d4a11f5978545779ed9a60203392a3005b60ff191682178155856102ba565b3461010c5761010036600319011261010c5760043567ffffffffffffffff811161010c5761032b903690600401610fc8565b610333611089565b9061033c61109f565b906103456110ae565b9061034e610f36565b60a4359167ffffffffffffffff831161010c573660238401121561010c57826004013567ffffffffffffffff8111610683576040519361039460208360051b0186610f14565b8185526024602086019260061b8201019036821161010c57602401915b8183106106d65750505082515f905f905b808210610697575050336103d5906111e3565b825160208401516040850151908760608701519a604051809c602082016020905260408201610403916110de565b03601f1981018d52610415908d610f14565b6080880151908d60a08a015160405181819251908160208401916020019161043c926110bd565b81010380825261044f9060200182610f14565b61045890611103565b6040519e8f806020810197602089526040820161047491611193565b03601f198101825261048591610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d880152805190816061890191602001916104ee926110bd565b860193606185015260818401526001600160a01b03169d6bffffffffffffffffffffffff199060601b1660a183015215159a8b60f81b60b583015215159b8c60f81b60b683015264ffffffffff8a169960d81b6001600160d81b03191660b783015251918260bc8301610560926110bd565b0160610103605b01601f19810182526105799082610f14565b519020604051611e7b80820182811067ffffffffffffffff821117610683578460c06105de8e8e8e8897613b57893960e087526105ba8d60e0890190611125565b926020880152604087015260608601528b608086015284810360a08601528c611193565b92015203905ff58015610232576020987f4507eb2a4efc5eacd7bf717901bdc881a42a88f0e7c45a050d6d1375521883649661063a966001600160a01b0361065b94169a8b9a604051998a996101408b526101408b0190611125565b948e8a015260408901526060880152608087015285820360a0870152611193565b9160c084015260c43560e084015260e4356101008401526101208301520390a2604051908152f35b634e487b7160e01b5f52604160045260245ffd5b909185518310156106c25760019064ffffffffff6020808660051b8a010151015116019201906103c2565b634e487b7160e01b5f52603260045260245ffd5b60408336031261010c57604051906106ed82610ef8565b83359067ffffffffffffffff8216820361010c578260209260409452610714838701610f4a565b838201528152019201916103b1565b3461010c57602036600319011261010c5761073c610f5c565b6001600160a01b035f541690338203610793576001600160a01b0316805f5260026020525f6001604082208281550155337f8cebf46c84bf401fa7816b701dfac1f1fdf41e6e601b9a501e7639d2aff5582f5f80a3005b506331b339a960e21b5f526004523360245260445ffd5b3461010c57602036600319011261010c576107c3610f5c565b5f546001600160a01b0381163381036100f657506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b3461010c57602036600319011261010c576001600160a01b03610851610f5c565b5f602060405161086081610ef8565b8281520152165f5260026020526040805f20815161087d81610ef8565b6020600160ff845416151593848452015491019081528251918252516020820152f35b3461010c57602036600319011261010c5760043567ffffffffffffffff811161010c573660238201121561010c5780600401359067ffffffffffffffff821161010c573660248360061b8301011161010c575f90815b838310156109545760248360061b830101359067ffffffffffffffff821680920361010c5767ffffffffffffffff160167ffffffffffffffff8111610940576001909201916108f6565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461010c5761012036600319011261010c5760043567ffffffffffffffff811161010c576109a5903690600401610fc8565b6109ad611089565b6109b561109f565b906109be6110ae565b90606036608319011261010c576040516060810181811067ffffffffffffffff821117610683576040526109f0610f36565b815260a43564ffffffffff8116810361010c57602082015260c43564ffffffffff8116810361010c576040820152845160208601516040870151906060880151966040519081602081019960208b5260408201610a4c916110de565b03601f1981018352610a5e9083610f14565b60808a01519060a08b0151604051818192519081602084019160200191610a84926110bd565b810103808252610a979060200182610f14565b610aa090611103565b6040519a60208c0194610ad2868b64ffffffffff60408092828151168552826020820151166020860152015116910152565b60608d52610ae160808e610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d88015251908160618801610b44926110bd565b850192606184015260818301526001600160a01b038816976bffffffffffffffffffffffff199060601b1660a18301521515978860f81b60b58301521515988960f81b60b683015251918260b78301610b9c926110bd565b0160610103605601601f1981018252610bb59082610f14565b51902094610bc2336111e3565b9560405161182380820182811067ffffffffffffffff821117610683578291612334833961010081528960e0610bfc610100840188611125565b928960208201528a60408201528b6060820152610c3b608082018a64ffffffffff60408092828151168552826020820151166020860152015116910152565b015203905ff592831561023257602096610cce610c96946001600160a01b037fe7c4d633a3f64a821f1283e2a399b368e633c17776b3cb932e4105d76ca299e397169889986040519788976101408952610140890190611125565b958c88015260408701526060860152608085019064ffffffffff60408092828151168552826020820151166020860152015116910152565b60e43560e0840152610104356101008401526101208301520390a2604051908152f35b3461010c575f36600319011261010c576020600154604051908152f35b3461010c57606036600319011261010c5760043567ffffffffffffffff811161010c57610d3f903690600401610fc8565b80516001600160d81b0319610e3e60406061602086015182870151606088015190845191610d8a83610d7c602082019360208552898301906110de565b03601f198101855284610f14565b610e2360808b015193610dcc60a08d0151610dc760208b5183610db682955180928580860191016110bd565b81010301601f198101835282610f14565b611103565b9388519a8b97602089019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348a015260d81b1660488801526bffffffffffffffffffffffff199060601b16604d870152518092878701906110bd565b83019184830152608182015203016020810184520182610f14565b51902090610e4b336111e3565b9160405161111880820182811067ffffffffffffffff82111761068357829161121c833960408152856020610e836040840188611125565b92015203905ff5918215610232577f12188a644c16704b9e77e2ecd3bb77e911693c22ffb0fcf44d9e4b36638b5d01610ed86001600160a01b0360209516938493604051928392608084526080840190611125565b9060243588840152604435604084015260608301520390a2604051908152f35b6040810190811067ffffffffffffffff82111761068357604052565b90601f8019910116810190811067ffffffffffffffff82111761068357604052565b6084359064ffffffffff8216820361010c57565b359064ffffffffff8216820361010c57565b600435906001600160a01b038216820361010c57565b81601f8201121561010c5780359067ffffffffffffffff82116106835760405192610fa7601f8401601f191660200185610f14565b8284526020838301011161010c57815f926020809301838601378301015290565b919060c08382031261010c576040519060c0820182811067ffffffffffffffff82111761068357604052819380356001600160a01b038116810361010c57835261101460208201610f4a565b602084015260408101356001600160a01b038116810361010c576040840152606081013567ffffffffffffffff811161010c5782611053918301610f72565b60608401526080810135608084015260a08101359167ffffffffffffffff831161010c5760a0926110849201610f72565b910152565b602435906001600160a01b038216820361010c57565b60443590811515820361010c57565b60643590811515820361010c57565b5f5b8381106110ce5750505f910152565b81810151838201526020016110bf565b906020916110f7815180928185528580860191016110bd565b601f01601f1916010190565b602081519101519060208110611117575090565b5f199060200360031b1b1690565b611190916001600160a01b03825116815264ffffffffff60208301511660208201526001600160a01b03604083015116604082015260a0611175606084015160c0606085015260c08401906110de565b926080810151608084015201519060a08184039101526110de565b90565b90602080835192838152019201905f5b8181106111b05750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152604090940193909201916001016111a3565b6001600160a01b0316805f52600260205260ff60405f2054165f14611214575f526002602052600160405f20015490565b506001549056fe61014080604052346103d457611118803803809161001d82856103d8565b83398101906040818303126103d45780516001600160401b0381116103d45781019060c0828403126103d4576040519160c083016001600160401b038111848210176103a95760405280516001600160a01b03811681036103d4578352602081015164ffffffffff811681036103d457602084019081526040820151936001600160a01b03851685036103d4576040810194855260608301516001600160401b0381116103d457866100d091850161041c565b92606082019384526080810151966080830197885260a082015160018060401b0381116103d457610101920161041c565b60a082018181526020959095015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a351602081116103bd5750516001600160a01b03166080525164ffffffffff1660a0523360c0525180519093906001600160401b0381116103a957600154600181811c9116801561039f575b602082101461038b57601f8111610328575b50602094601f82116001146102c5579481929394955f926102ba575b50508160011b915f199060031b1c1916176001555b5160e052516040516102146020828161020381830196878151938492016103fb565b81010301601f1981018352826103d8565b51905190602081106102a9575b506101005261012052604051610ca7908161047182396080518181816103f50152818161062a0152610811015260a051818181610181015281816107370152818161089f0152610b07015260c05181818161077e015261093d015260e05181818161028b01526105af015261010051816109fa01526101205181818161014101526104af0152f35b5f199060200360031b1b165f610221565b015190505f806101cc565b601f1982169560015f52805f20915f5b888110610310575083600195969798106102f8575b505050811b016001556101e1565b01515f1960f88460031b161c191690555f80806102ea565b919260206001819286850151815501940192016102d5565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610381575b601f0160051c01905b81811061037657506101b0565b5f8155600101610369565b9091508190610360565b634e487b7160e01b5f52602260045260245ffd5b90607f169061019e565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176103a957604052565b5f5b83811061040c5750505f910152565b81810151838201526020016103fd565b81601f820112156103d45780516001600160401b0381116103a9576040519261044f601f8301601f1916602001856103d8565b818452602082840101116103d45761046d91602080850191016103fb565b9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146109e457508063164e68de1461090e5780631686c909146107a25780632dd310001461075f5780633f31ae3f146104195780634800d97f146103d657806349fc73dd146102d25780634e390d3e146102ae57806351e75e8b1461027457806375829def146101bf57806390e64d13146101a5578063bb4b573414610164578063bba72cd31461012a578063ce516507146100ea5763f851a440146100c1575f80fd5b346100e6575f3660031901126100e65760206001600160a01b035f5416604051908152f35b5f80fd5b346100e65760203660031901126100e657602061012060043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e6575f3660031901126100e6576020610120610aff565b346100e65760203660031901126100e6576101d8610a74565b5f546001600160a01b03811633810361024557506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602064ffffffffff60035416604051908152f35b346100e6575f3660031901126100e6576040515f6001548060011c906001811680156103cc575b6020831081146103b8578285529081156103945750600114610336575b6103328361032681850382610a8a565b60405191829182610a2d565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061037a57509091508101602001610326610316565b919260018160209254838588010152019101909291610362565b60ff191660208086019190915291151560051b840190910191506103269050610316565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102f9565b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60803660031901126100e657600435602435906001600160a01b038216918281036100e657604435926fffffffffffffffffffffffffffffffff84168094036100e6576064359367ffffffffffffffff85116100e657366023860112156100e657846004013567ffffffffffffffff81116100e6578060051b95602487820101903682116100e6576104a9610aff565b610708577f00000000000000000000000000000000000000000000000000000000000000008034106106d957506104f78760ff6001918060081c5f526002602052161b60405f205416151590565b6106ad57604051602081019088825286604082015285606082015260608152610521608082610a8a565b519020604051602081019182526020815261053d604082610a8a565b5190209261055160206040519a018a610a8a565b8852602401602088015b82821061069d57505050925f935b86518510156105ab5760208560051b88010151908181105f1461059a575f52602052600160405f205b940193610569565b905f52602052600160405f20610592565b85907f000000000000000000000000000000000000000000000000000000000000000003610675578261064e7f1dcd2362ae467d43bf31cbcac0526c0958b23eb063e011ab49a5179c839ed9a99460409460035464ffffffffff81161561065b575b508460081c5f526002602052855f20600160ff87161b81541790557f0000000000000000000000000000000000000000000000000000000000000000610b3c565b82519182526020820152a2005b64ffffffffff19164264ffffffffff16176003558861060d565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b813581526020918201910161055b565b867febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e65760403660031901126100e6576107bb610a74565b602435906fffffffffffffffffffffffffffffffff82168092036100e6576001600160a01b035f5416338103610245575064ffffffffff60035416801515806108d9575b806108ca575b610870575061083582827f0000000000000000000000000000000000000000000000000000000000000000610b3c565b7f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b03805f5416936040519586521693a3005b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506108d3610aff565b15610805565b5062093a80810164ffffffffff81116108fa5764ffffffffff1642116107ff565b634e487b7160e01b5f52601160045260245ffd5b346100e65760203660031901126100e6576004356001600160a01b0381168091036100e6576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168033036109b5575047905f80808085855af1610977610ac0565b501561098857602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e657610332907f0000000000000000000000000000000000000000000000000000000000000000602082015260208152610326604082610a8a565b9190916020815282518060208301525f5b818110610a5e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610a3e565b600435906001600160a01b03821682036100e657565b90601f8019910116810190811067ffffffffffffffff821117610aac57604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610afa573d9067ffffffffffffffff8211610aac5760405191610aef601f8201601f191660200184610a8a565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610b34575090565b905042101590565b5f610ba9926001600160a01b038293604051968260208901947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024890152604488015260448752610b92606488610a8a565b1694519082865af1610ba2610ac0565b9083610c0e565b8051908115159182610bea575b5050610bbf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100e657602001518015908115036100e6575f80610bb6565b90610c4b5750805115610c2357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610c91575b610c5c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610c5456fea164736f6c634300081a000a6101a0806040523461049a57611823803803809161001d82856105d8565b8339810190808203610100811261049a5781516001600160401b03811161049a5782019160c08385031261049a576040519160c083016001600160401b038111848210176105ad5760405283516001600160a01b038116810361049a578352610088602085016105fb565b6020840190815260408501519091906001600160a01b038116810361049a576040850190815260608601516001600160401b03811161049a57876100cd918801610649565b95606086019687526080810151976080870198895260a082015160018060401b03811161049a576100fe9201610649565b60a0860190815260208501516001600160a01b038116979092909188840361049a5761012c6040880161068e565b92606061013a818a0161068e565b96607f19011261049a5760405196606088016001600160401b038111898210176105ad5760405261016d60808a016105fb565b885261017b60a08a016105fb565b99602089019a8b5260e061019160c08c016105fb565b60408b019081529a015194515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3835151602081116105c15750516001600160a01b03166080525164ffffffffff1660a0523360c052518051909a906001600160401b0381116105ad57600154600181811c911680156105a3575b602082101461058f57601f811161052c575b506020601f82116001146104ba57819064ffffffffff9a9b9c9d5f926104af575b50508160011b915f199060031b1c1916176001555b5160e052516040516102a7602082816102968183019687815193849201610628565b81010301601f1981018352826105d8565b519051906020811061049e575b50610100526101205261014052610160526101805251166effffffffff0000000000000000000069ffffffffff0000000000600454945160281b16925160501b169260018060781b03191617171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103406064866105d8565b84519082855af161034f61069b565b81610463575b5080610459575b15610414575b604051611087908161079c823960805181818161049e015281816107830152610c65015260a0518181816101ad01528181610abc01528181610d650152610fb9015260c051818181610b030152610e03015260e051818181610334015261065601526101005181610ec001526101205181818161016d01526105560152610140518181816107b40152610b7a01526101605181818161024401526108dd0152610180518181816107de0152610b3e0152f35b61044c610451936040519063095ea7b360e01b602083015260248201525f6044820152604481526104466064826105d8565b826106ca565b6106ca565b5f8080610362565b50803b151561035c565b8051801592508215610478575b50505f610355565b819250906020918101031261049a576020610493910161068e565b5f80610470565b5f80fd5b5f199060200360031b1b165f6102b4565b015190505f8061025f565b601f1982169c60015f52815f209d5f5b81811061050f57509164ffffffffff9b9c9d9e918460019594106104f7575b505050811b01600155610274565b01515f1960f88460031b161c191690555f80806104e9565b919e8f60016020928684930151815501940192019e91929e6104ca565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610585575b601f0160051c01905b81811061057a575061023e565b5f815560010161056d565b9091508190610564565b634e487b7160e01b5f52602260045260245ffd5b90607f169061022c565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b038211908210176105ad57604052565b519064ffffffffff8216820361049a57565b6001600160401b0381116105ad57601f01601f191660200190565b5f5b8381106106395750505f910152565b818101518382015260200161062a565b81601f8201121561049a57805161065f8161060d565b9261066d60405194856105d8565b8184526020828401011161049a5761068b9160208085019101610628565b90565b5190811515820361049a57565b3d156106c5573d906106ac8261060d565b916106ba60405193846105d8565b82523d5f602084013e565b606090565b5f806106f29260018060a01b03169360208151910182865af16106eb61069b565b908361073d565b805190811515918261071a575b50506107085750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261049a576020610735910161068e565b155f806106ff565b90610761575080511561075257805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610792575b610772575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561076a56fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610eaa57508063164e68de14610dd45780631686c90914610b9f57806316c3549d14610b635780631bfd681414610b275780632dd3100014610ae45780633f31ae3f146104c25780634800d97f1461047f57806349fc73dd1461037b5780634e390d3e1461035757806351e75e8b1461031d57806375829def14610268578063845aef4b1461022557806390e64d131461020b578063b0604a26146101d1578063bb4b573414610190578063bba72cd314610156578063ce516507146101165763f851a440146100ed575f80fd5b34610112575f3660031901126101125760206001600160a01b035f5416604051908152f35b5f80fd5b3461011257602036600319011261011257602061014c60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257606060045464ffffffffff604051918181168352818160281c16602084015260501c166040820152f35b34610112575f36600319011261011257602061014c610fb1565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461011257602036600319011261011257610281610f3a565b5f546001600160a01b0381163381036102ee57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602064ffffffffff60035416604051908152f35b34610112575f366003190112610112576040515f6001548060011c90600181168015610475575b6020831081146104615782855290811561043d57506001146103df575b6103db836103cf81850382610f50565b60405191829182610ef3565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610423575090915081016020016103cf6103bf565b91926001816020925483858801015201910190929161040b565b60ff191660208086019190915291151560051b840190910191506103cf90506103bf565b634e487b7160e01b5f52602260045260245ffd5b91607f16916103a2565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261011257600435602435906001600160a01b038216809203610112576044356fffffffffffffffffffffffffffffffff8116809103610112576064359067ffffffffffffffff8211610112573660238301121561011257816004013567ffffffffffffffff8111610112578060051b926024848201019036821161011257610550610fb1565b610a8d577f0000000000000000000000000000000000000000000000000000000000000000803410610a5e575061059e8660ff6001918060081c5f526002602052161b60405f205416151590565b610a32576040516020810190878252886040820152856060820152606081526105c8608082610f50565b51902060405160208101918252602081526105e4604082610f50565b519020926105f86020604051970187610f50565b8552602401602085015b828210610a2257505050935f945b83518610156106525760208660051b85010151908181105f14610641575f52602052600160405f205b950194610610565b905f52602052600160405f20610639565b84907f0000000000000000000000000000000000000000000000000000000000000000036109fa5760035464ffffffffff8116156109e0575b508060081c5f52600260205260405f20600160ff83161b815417905560405192606084019380851067ffffffffffffffff8611176109b057604094855260208101905f82526004549064ffffffffff821680155f146109d9575064ffffffffff421681525b64ffffffffff8260281c16806109c4575b5064ffffffffff80808351169360501c1683011696879101526001600160a01b035f541695604051916040830183811067ffffffffffffffff8211176109b0576040525f83525f602084015260405197610120890189811067ffffffffffffffff8211176109b057604052885260208801938785526040890186815260608a017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808b01917f00000000000000000000000000000000000000000000000000000000000000001515835260a08c01937f00000000000000000000000000000000000000000000000000000000000000001515855260c08d0195865260e08d019687526101008d019788525164ffffffffff1697604051809d7f9e7f5dbb000000000000000000000000000000000000000000000000000000008252516001600160a01b03169060040152516001600160a01b031660248d0152516fffffffffffffffffffffffffffffffff1660448c0152516001600160a01b031660648b015251151560848a015251151560a48901525164ffffffffff1660c48801525164ffffffffff1660e48701525180516001600160a01b03166101048701526020015161012486015261014485015283807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61016492602095f19384156109a5575f94610951575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d60201161099d575b8161096d60209383610f50565b810103126101125751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d61091e565b3d9150610960565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff90818351160116835287610701565b81526106f0565b64ffffffffff19164264ffffffffff16176003558361068b565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610602565b857febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461011257604036600319011261011257610bb8610f3a565b6024356fffffffffffffffffffffffffffffffff8116809103610112576001600160a01b035f54163381036102ee575064ffffffffff6003541680151580610d9f575b80610d90575b610d365750604051610c9b5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610c5b606486610f50565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610c94610f72565b9083610fee565b8051908115159182610d12575b5050610ce757507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101125760200151801590811503610112578480610ca8565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610d99610fb1565b15610c01565b5062093a80810164ffffffffff8111610dc05764ffffffffff164211610bfb565b634e487b7160e01b5f52601160045260245ffd5b34610112576020366003190112610112576004356001600160a01b038116809103610112576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303610e7b575047905f80808085855af1610e3d610f72565b5015610e4e57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f366003190112610112576103db907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103cf604082610f50565b9190916020815282518060208301525f5b818110610f24575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610f04565b600435906001600160a01b038216820361011257565b90601f8019910116810190811067ffffffffffffffff8211176109b057604052565b3d15610fac573d9067ffffffffffffffff82116109b05760405191610fa1601f8201601f191660200184610f50565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610fe6575090565b905042101590565b9061102b575080511561100357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611071575b61103c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561103456fea164736f6c634300081a000a6101e080604052346104ba57611e7b803803809161001d828561071d565b833981019060e0818303126104ba5780516001600160401b0381116104ba5781019060c0828403126104ba576040519160c083016001600160401b038111848210176105745760405280516001600160a01b03811681036104ba57835261008660208201610740565b6020840190815260408201516001600160a01b03811681036104ba576040850190815260608301516001600160401b0381116104ba57866100c891850161078e565b6060860190815260808085015190870190815260a085015191949091906001600160401b0382116104ba576100ff9189910161078e565b60a087019081526020860151949091906001600160a01b03861686036104ba5761012b604088016107d3565b94610138606089016107d3565b9861014560808a01610740565b60a08a01519099906001600160401b0381116104ba5781018c601f820112156104ba578051906001600160401b038211610574576040519d8e8360051b60200161018f908261071d565b8381526020019260061b8201602001918183116104ba57602001925b8284106106c1575050505060c0015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3845151602081116106aa5750516001600160a01b03166080525164ffffffffff1660a0523360c052518051906001600160401b0382116105745760015490600182811c921680156106a0575b602083101461068c5781601f84931161061e575b50602090601f83116001146105b8575f926105ad575b50508160011b915f199060031b1c1916176001555b5160e052516040516102bc602082816102ab818301968781519384920161076d565b81010301601f19810183528261071d565b519051906020811061059c575b5061010052610120526101405261016052610180526101c0528051905f915f915b8183106104be57836101a05260018060a01b036080511660018060a01b03610160511690604051905f806020840163095ea7b360e01b8152856024860152811960448601526044855261033e60648661071d565b84519082855af161034d6107f4565b81610483575b5080610479575b15610434575b60405161158690816108f58239608051818181610578015281816109440152610f74015260a05181818161027d01528181610dd40152818161107401526112fc015260c051818181610e1b0152611112015260e05181818161040e015261072e015261010051816111cf01526101205181818161023d01526106270152610140518181816109740152610e9201526101605181818161031e0152610ac601526101805181818161018901526107bc01526101a0518181816102c1015261078a01526101c05181818161099e0152610e560152f35b61046c610471936040519063095ea7b360e01b602083015260248201525f60448201526044815261046660648261071d565b82610823565b610823565b808080610360565b50803b151561035a565b8051801592508215610498575b505084610353565b81925090602091810103126104ba5760206104b391016107d3565b8480610490565b5f80fd5b91929091906001600160401b036104d585846107e0565b5151166001600160401b039182160190811161058857926104f681836107e0565b519060045491680100000000000000008310156105745760018301806004558310156105605760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ea565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f6102c9565b015190505f80610274565b60015f9081528281209350601f198516905b81811061060657509084600195949392106105ee575b505050811b01600155610289565b01515f1960f88460031b161c191690555f80806105e0565b929360206001819287860151815501950193016105ca565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610682575b90601f859493920160051c01905b818110610674575061025e565b5f8155849350600101610667565b9091508190610659565b634e487b7160e01b5f52602260045260245ffd5b91607f169161024a565b6371935f2960e11b5f52600452602060245260445ffd5b6040848303126104ba5760408051919082016001600160401b03811183821017610574576040528451906001600160401b03821682036104ba57826020926040945261070e838801610740565b838201528152019301926101ab565b601f909101601f19168101906001600160401b0382119082101761057457604052565b519064ffffffffff821682036104ba57565b6001600160401b03811161057457601f01601f191660200190565b5f5b83811061077e5750505f910152565b818101518382015260200161076f565b81601f820112156104ba5780516107a481610752565b926107b2604051948561071d565b818452602082840101116104ba576107d0916020808501910161076d565b90565b519081151582036104ba57565b80518210156105605760209160051b010190565b3d1561081e573d9061080582610752565b91610813604051938461071d565b82523d5f602084013e565b606090565b5f8061084b9260018060a01b03169360208151910182865af16108446107f4565b9083610896565b8051908115159182610873575b50506108615750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104ba57602061088e91016107d3565b155f80610858565b906108ba57508051156108ab57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806108eb575b6108cb575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156108c356fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146111b957508063164e68de146110e35780631686c90914610eb757806316c3549d14610e7b5780631bfd681414610e3f5780632dd3100014610dfc5780633f31ae3f1461059c5780634800d97f1461055957806349fc73dd146104555780634e390d3e1461043157806351e75e8b146103f757806375829def14610342578063845aef4b146102ff57806390e64d13146102e5578063936c63d9146102a1578063bb4b573414610260578063bba72cd314610226578063bf4ed03f146101ad578063ce36b3351461016c578063ce5165071461012c5763f851a44014610103575f80fd5b34610128575f3660031901126101285760206001600160a01b035f5416604051908152f35b5f80fd5b3461012857602036600319011261012857602061016260043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f366003190112610128576101c5611331565b6040518091602082016020835281518091526020604084019201905f5b8181106101f0575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152869550604090940193909201916001016101e2565b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206101626112f4565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101285760203660031901126101285761035b611249565b5f546001600160a01b0381163381036103c857506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602064ffffffffff60035416604051908152f35b34610128575f366003190112610128576040515f6001548060011c9060018116801561054f575b60208310811461053b5782855290811561051757506001146104b9575b6104b5836104a98185038261127b565b60405191829182611202565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104fd575090915081016020016104a9610499565b9192600181602092548385880101520191019092916104e5565b60ff191660208086019190915291151560051b840190910191506104a99050610499565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047c565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261012857600435602435906001600160a01b03821680920361012857604435906001600160801b03821691828103610128576064359367ffffffffffffffff851161012857366023860112156101285784600401359467ffffffffffffffff86116101285760248660051b820101368111610128576106216112f4565b610da5577f0000000000000000000000000000000000000000000000000000000000000000803410610d76575061066f8560ff6001918060081c5f526002602052161b60405f205416151590565b610d4a5760405160208101908682528460408201528760608201526060815261069960808261127b565b51902060405160208101918252602081526106b560408261127b565b519020916106c2886112dc565b976106d0604051998a61127b565b8852602401602088015b828210610d3a57505050925f935b865185101561072a576106fb85886113e6565b519081811015610719575f52602052600160405f205b9401936106e8565b905f52602052600160405f20610711565b85907f000000000000000000000000000000000000000000000000000000000000000003610d125760035464ffffffffff811615610cf8575b508160081c5f52600260205260405f20600160ff84161b815417905567ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ccd57507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff8116610cc7575064ffffffffff4216935b6107fa611331565b90815191610807836112dc565b92610815604051948561127b565b808452601f19610824826112dc565b015f5b818110610ca457505061085661085167ffffffffffffffff610848856113c5565b5151168761143f565b6113fa565b64ffffffffff806020610868866113c5565b510151168a0116906001600160801b03604051916108858361125f565b16918282526020820152610898866113c5565b526108a2856113c5565b50916001905b828210610c105750506001600160801b038216858111610bfc578511610bd1575b50505064ffffffffff60206108e25f19845101846113e6565b510151166001600160a01b035f541690604051906108ff8261125f565b5f82525f602083015260405192610120840184811067ffffffffffffffff821117610bbd576040959493929552825260208201938785526040830198868a52606084017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152608085017f00000000000000000000000000000000000000000000000000000000000000001515815260a08601917f00000000000000000000000000000000000000000000000000000000000000001515835260c087019364ffffffffff16845260e0870194855261010087019586526040519c8d997f56b955e8000000000000000000000000000000000000000000000000000000008b526101648b0198516001600160a01b031660048c0152516001600160a01b031660248b0152516001600160801b031660448a0152516001600160a01b03166064890152511515608488015251151560a48701525164ffffffffff1660c48601525164ffffffffff1660e48501525180516001600160a01b031661010485015260200151610124840152610144830161016090528151809152610184830191602001905f5b818110610b8857505050908060209203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1938415610b7d575f94610b29575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610b75575b81610b456020938361127b565b810103126101285751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af6565b3d9150610b38565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610aaa565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610be883925f1901866113e6565b5193031681835116011690528580806108c9565b634e487b7160e01b5f52600160045260245ffd5b90926001600160801b03600191610c3f61085167ffffffffffffffff610c3689886113e6565b5151168b61143f565b9064ffffffffff806020610c565f198b018d6113e6565b51015116816020610c678b8a6113e6565b51015116011660405190610c7a8261125f565b84841682526020820152610c8e888b6113e6565b52610c99878a6113e6565b5001169301906108a8565b602090604051610cb38161125f565b5f81525f8382015282828901015201610827565b936107f2565b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b64ffffffffff19164264ffffffffff161760035584610763565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106da565b847febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012857604036600319011261012857610ed0611249565b6024356001600160801b038116809103610128576001600160a01b035f54163381036103c8575064ffffffffff60035416801515806110ae575b8061109f575b6110455750604051610faa5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610f6a60648661127b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610fa361129d565b90836114ed565b8051908115159182611021575b5050610ff657507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101285760200151801590811503610128578480610fb7565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506110a86112f4565b15610f10565b5062093a80810164ffffffffff81116110cf5764ffffffffff164211610f0a565b634e487b7160e01b5f52601160045260245ffd5b34610128576020366003190112610128576004356001600160a01b038116809103610128576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680330361118a575047905f80808085855af161114c61129d565b501561115d57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f366003190112610128576104b5907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104a960408261127b565b9190916020815282518060208301525f5b818110611233575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611213565b600435906001600160a01b038216820361012857565b6040810190811067ffffffffffffffff821117610bbd57604052565b90601f8019910116810190811067ffffffffffffffff821117610bbd57604052565b3d156112d7573d9067ffffffffffffffff8211610bbd57604051916112cc601f8201601f19166020018461127b565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610bbd5760051b60200190565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611329575090565b905042101590565b6004549061133e826112dc565b9161134c604051938461127b565b80835260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602085015b8383106113885750505050565b60016020819260405161139a8161125f565b64ffffffffff865467ffffffffffffffff8116835260401c168382015281520192019201919061137b565b8051156113d25760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156113d25760209160051b010190565b6001600160801b038111611414576001600160801b031690565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f19838209838202918280831092039180830392146114dc57670de0b6b3a76400008210156114ac577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061152a575080511561150257805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611570575b61153b575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561153356fea164736f6c634300081a000aa164736f6c634300081a000a"; + hex"608034609357601f615a8138819003918201601f19168301916001600160401b03831184841017609757808492602094604052833981010312609357516001600160a01b038116908190036093575f80546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36159d590816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063070a6b8414610d0e5780631134f19414610cf157806345aa9357146109735780634d7c0f11146108a05780636f71d8f41461083057806375829def146107aa5780638af96dfe14610723578063b3ee17cc146102f9578063d498fcf514610265578063f255527814610135578063f851a440146101105763f946eef21461009d575f80fd5b3461010c57602036600319011261010c576004356001600160a01b035f54163381036100f65750806001556040519081527f7d41b7bcff330c958826f81c5de08357f286914f0758727ca23717d24f158fcc60203392a2005b6331b339a960e21b5f526004523360245260445ffd5b5f80fd5b3461010c575f36600319011261010c5760206001600160a01b035f5416604051908152f35b3461010c57604036600319011261010c576004356001600160a01b03811680910361010c57602435906001600160a01b03821680920361010c576001600160a01b035f54163381036100f65750801561023d576040517f164e68de0000000000000000000000000000000000000000000000000000000081528160048201526020816024815f875af1908115610232575f91610200575b5060405191825260208201527ff65e64e219c3199240f0fe17a71d01821ed2dd08283833094e12a9ad6883786560403392a3005b90506020813d60201161022a575b8161021b60209383610f14565b8101031261010c5751836101cc565b3d915061020e565b6040513d5f823e3d90fd5b7f38da7036000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461010c57604036600319011261010c5761027e610f5c565b602435906001600160a01b035f54163381036100f657506001600160a01b031690815f52600260205280600160405f20805460ff8116156102eb575b5001556040519081527f314737fce28d10af73c184056111a030c8124d005478d4a11f5978545779ed9a60203392a3005b60ff191682178155856102ba565b3461010c5761010036600319011261010c5760043567ffffffffffffffff811161010c5761032b903690600401610fc8565b610333611089565b9061033c61109f565b906103456110ae565b9061034e610f36565b60a4359167ffffffffffffffff831161010c573660238401121561010c57826004013567ffffffffffffffff8111610683576040519361039460208360051b0186610f14565b8185526024602086019260061b8201019036821161010c57602401915b8183106106d65750505082515f905f905b808210610697575050336103d5906111e3565b825160208401516040850151908760608701519a604051809c602082016020905260408201610403916110de565b03601f1981018d52610415908d610f14565b6080880151908d60a08a015160405181819251908160208401916020019161043c926110bd565b81010380825261044f9060200182610f14565b61045890611103565b6040519e8f806020810197602089526040820161047491611193565b03601f198101825261048591610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d880152805190816061890191602001916104ee926110bd565b860193606185015260818401526001600160a01b03169d6bffffffffffffffffffffffff199060601b1660a183015215159a8b60f81b60b583015215159b8c60f81b60b683015264ffffffffff8a169960d81b6001600160d81b03191660b783015251918260bc8301610560926110bd565b0160610103605b01601f19810182526105799082610f14565b519020604051611e8a80820182811067ffffffffffffffff821117610683578460c06105de8e8e8e8897613b3f893960e087526105ba8d60e0890190611125565b926020880152604087015260608601528b608086015284810360a08601528c611193565b92015203905ff58015610232576020987f4507eb2a4efc5eacd7bf717901bdc881a42a88f0e7c45a050d6d1375521883649661063a966001600160a01b0361065b94169a8b9a604051998a996101408b526101408b0190611125565b948e8a015260408901526060880152608087015285820360a0870152611193565b9160c084015260c43560e084015260e4356101008401526101208301520390a2604051908152f35b634e487b7160e01b5f52604160045260245ffd5b909185518310156106c25760019064ffffffffff6020808660051b8a010151015116019201906103c2565b634e487b7160e01b5f52603260045260245ffd5b60408336031261010c57604051906106ed82610ef8565b83359067ffffffffffffffff8216820361010c578260209260409452610714838701610f4a565b838201528152019201916103b1565b3461010c57602036600319011261010c5761073c610f5c565b6001600160a01b035f541690338203610793576001600160a01b0316805f5260026020525f6001604082208281550155337f8cebf46c84bf401fa7816b701dfac1f1fdf41e6e601b9a501e7639d2aff5582f5f80a3005b506331b339a960e21b5f526004523360245260445ffd5b3461010c57602036600319011261010c576107c3610f5c565b5f546001600160a01b0381163381036100f657506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b3461010c57602036600319011261010c576001600160a01b03610851610f5c565b5f602060405161086081610ef8565b8281520152165f5260026020526040805f20815161087d81610ef8565b6020600160ff845416151593848452015491019081528251918252516020820152f35b3461010c57602036600319011261010c5760043567ffffffffffffffff811161010c573660238201121561010c5780600401359067ffffffffffffffff821161010c573660248360061b8301011161010c575f90815b838310156109545760248360061b830101359067ffffffffffffffff821680920361010c5767ffffffffffffffff160167ffffffffffffffff8111610940576001909201916108f6565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461010c5761012036600319011261010c5760043567ffffffffffffffff811161010c576109a5903690600401610fc8565b6109ad611089565b6109b561109f565b906109be6110ae565b90606036608319011261010c576040516060810181811067ffffffffffffffff821117610683576040526109f0610f36565b815260a43564ffffffffff8116810361010c57602082015260c43564ffffffffff8116810361010c576040820152845160208601516040870151906060880151966040519081602081019960208b5260408201610a4c916110de565b03601f1981018352610a5e9083610f14565b60808a01519060a08b0151604051818192519081602084019160200191610a84926110bd565b810103808252610a979060200182610f14565b610aa090611103565b6040519a60208c0194610ad2868b64ffffffffff60408092828151168552826020820151166020860152015116910152565b60608d52610ae160808e610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d88015251908160618801610b44926110bd565b850192606184015260818301526001600160a01b038816976bffffffffffffffffffffffff199060601b1660a18301521515978860f81b60b58301521515988960f81b60b683015251918260b78301610b9c926110bd565b0160610103605601601f1981018252610bb59082610f14565b51902094610bc2336111e3565b9560405161180b80820182811067ffffffffffffffff821117610683578291612334833961010081528960e0610bfc610100840188611125565b928960208201528a60408201528b6060820152610c3b608082018a64ffffffffff60408092828151168552826020820151166020860152015116910152565b015203905ff592831561023257602096610cce610c96946001600160a01b037fe7c4d633a3f64a821f1283e2a399b368e633c17776b3cb932e4105d76ca299e397169889986040519788976101408952610140890190611125565b958c88015260408701526060860152608085019064ffffffffff60408092828151168552826020820151166020860152015116910152565b60e43560e0840152610104356101008401526101208301520390a2604051908152f35b3461010c575f36600319011261010c576020600154604051908152f35b3461010c57606036600319011261010c5760043567ffffffffffffffff811161010c57610d3f903690600401610fc8565b80516001600160d81b0319610e3e60406061602086015182870151606088015190845191610d8a83610d7c602082019360208552898301906110de565b03601f198101855284610f14565b610e2360808b015193610dcc60a08d0151610dc760208b5183610db682955180928580860191016110bd565b81010301601f198101835282610f14565b611103565b9388519a8b97602089019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348a015260d81b1660488801526bffffffffffffffffffffffff199060601b16604d870152518092878701906110bd565b83019184830152608182015203016020810184520182610f14565b51902090610e4b336111e3565b9160405161111880820182811067ffffffffffffffff82111761068357829161121c833960408152856020610e836040840188611125565b92015203905ff5918215610232577f12188a644c16704b9e77e2ecd3bb77e911693c22ffb0fcf44d9e4b36638b5d01610ed86001600160a01b0360209516938493604051928392608084526080840190611125565b9060243588840152604435604084015260608301520390a2604051908152f35b6040810190811067ffffffffffffffff82111761068357604052565b90601f8019910116810190811067ffffffffffffffff82111761068357604052565b6084359064ffffffffff8216820361010c57565b359064ffffffffff8216820361010c57565b600435906001600160a01b038216820361010c57565b81601f8201121561010c5780359067ffffffffffffffff82116106835760405192610fa7601f8401601f191660200185610f14565b8284526020838301011161010c57815f926020809301838601378301015290565b919060c08382031261010c576040519060c0820182811067ffffffffffffffff82111761068357604052819380356001600160a01b038116810361010c57835261101460208201610f4a565b602084015260408101356001600160a01b038116810361010c576040840152606081013567ffffffffffffffff811161010c5782611053918301610f72565b60608401526080810135608084015260a08101359167ffffffffffffffff831161010c5760a0926110849201610f72565b910152565b602435906001600160a01b038216820361010c57565b60443590811515820361010c57565b60643590811515820361010c57565b5f5b8381106110ce5750505f910152565b81810151838201526020016110bf565b906020916110f7815180928185528580860191016110bd565b601f01601f1916010190565b602081519101519060208110611117575090565b5f199060200360031b1b1690565b611190916001600160a01b03825116815264ffffffffff60208301511660208201526001600160a01b03604083015116604082015260a0611175606084015160c0606085015260c08401906110de565b926080810151608084015201519060a08184039101526110de565b90565b90602080835192838152019201905f5b8181106111b05750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152604090940193909201916001016111a3565b6001600160a01b0316805f52600260205260ff60405f2054165f14611214575f526002602052600160405f20015490565b506001549056fe61014080604052346103d457611118803803809161001d82856103d8565b83398101906040818303126103d45780516001600160401b0381116103d45781019060c0828403126103d4576040519160c083016001600160401b038111848210176103a95760405280516001600160a01b03811681036103d4578352602081015164ffffffffff811681036103d457602084019081526040820151936001600160a01b03851685036103d4576040810194855260608301516001600160401b0381116103d457866100d091850161041c565b92606082019384526080810151966080830197885260a082015160018060401b0381116103d457610101920161041c565b60a082018181526020959095015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a351602081116103bd5750516001600160a01b03166080525164ffffffffff1660a0523360c0525180519093906001600160401b0381116103a957600154600181811c9116801561039f575b602082101461038b57601f8111610328575b50602094601f82116001146102c5579481929394955f926102ba575b50508160011b915f199060031b1c1916176001555b5160e052516040516102146020828161020381830196878151938492016103fb565b81010301601f1981018352826103d8565b51905190602081106102a9575b506101005261012052604051610ca7908161047182396080518181816103f50152818161062a0152610811015260a051818181610181015281816107370152818161089f0152610b07015260c05181818161077e015261093d015260e05181818161028b01526105af015261010051816109fa01526101205181818161014101526104af0152f35b5f199060200360031b1b165f610221565b015190505f806101cc565b601f1982169560015f52805f20915f5b888110610310575083600195969798106102f8575b505050811b016001556101e1565b01515f1960f88460031b161c191690555f80806102ea565b919260206001819286850151815501940192016102d5565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610381575b601f0160051c01905b81811061037657506101b0565b5f8155600101610369565b9091508190610360565b634e487b7160e01b5f52602260045260245ffd5b90607f169061019e565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176103a957604052565b5f5b83811061040c5750505f910152565b81810151838201526020016103fd565b81601f820112156103d45780516001600160401b0381116103a9576040519261044f601f8301601f1916602001856103d8565b818452602082840101116103d45761046d91602080850191016103fb565b9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146109e457508063164e68de1461090e5780631686c909146107a25780632dd310001461075f5780633f31ae3f146104195780634800d97f146103d657806349fc73dd146102d25780634e390d3e146102ae57806351e75e8b1461027457806375829def146101bf57806390e64d13146101a5578063bb4b573414610164578063bba72cd31461012a578063ce516507146100ea5763f851a440146100c1575f80fd5b346100e6575f3660031901126100e65760206001600160a01b035f5416604051908152f35b5f80fd5b346100e65760203660031901126100e657602061012060043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e6575f3660031901126100e6576020610120610aff565b346100e65760203660031901126100e6576101d8610a74565b5f546001600160a01b03811633810361024557506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602064ffffffffff60035416604051908152f35b346100e6575f3660031901126100e6576040515f6001548060011c906001811680156103cc575b6020831081146103b8578285529081156103945750600114610336575b6103328361032681850382610a8a565b60405191829182610a2d565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061037a57509091508101602001610326610316565b919260018160209254838588010152019101909291610362565b60ff191660208086019190915291151560051b840190910191506103269050610316565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102f9565b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60803660031901126100e657600435602435906001600160a01b038216918281036100e657604435926fffffffffffffffffffffffffffffffff84168094036100e6576064359367ffffffffffffffff85116100e657366023860112156100e657846004013567ffffffffffffffff81116100e6578060051b95602487820101903682116100e6576104a9610aff565b610708577f00000000000000000000000000000000000000000000000000000000000000008034106106d957506104f78760ff6001918060081c5f526002602052161b60405f205416151590565b6106ad57604051602081019088825286604082015285606082015260608152610521608082610a8a565b519020604051602081019182526020815261053d604082610a8a565b5190209261055160206040519a018a610a8a565b8852602401602088015b82821061069d57505050925f935b86518510156105ab5760208560051b88010151908181105f1461059a575f52602052600160405f205b940193610569565b905f52602052600160405f20610592565b85907f000000000000000000000000000000000000000000000000000000000000000003610675578261064e7f1dcd2362ae467d43bf31cbcac0526c0958b23eb063e011ab49a5179c839ed9a99460409460035464ffffffffff81161561065b575b508460081c5f526002602052855f20600160ff87161b81541790557f0000000000000000000000000000000000000000000000000000000000000000610b3c565b82519182526020820152a2005b64ffffffffff19164264ffffffffff16176003558861060d565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b813581526020918201910161055b565b867febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e65760403660031901126100e6576107bb610a74565b602435906fffffffffffffffffffffffffffffffff82168092036100e6576001600160a01b035f5416338103610245575064ffffffffff60035416801515806108d9575b806108ca575b610870575061083582827f0000000000000000000000000000000000000000000000000000000000000000610b3c565b7f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b03805f5416936040519586521693a3005b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506108d3610aff565b15610805565b5062093a80810164ffffffffff81116108fa5764ffffffffff1642116107ff565b634e487b7160e01b5f52601160045260245ffd5b346100e65760203660031901126100e6576004356001600160a01b0381168091036100e6576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168033036109b5575047905f80808085855af1610977610ac0565b501561098857602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e657610332907f0000000000000000000000000000000000000000000000000000000000000000602082015260208152610326604082610a8a565b9190916020815282518060208301525f5b818110610a5e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610a3e565b600435906001600160a01b03821682036100e657565b90601f8019910116810190811067ffffffffffffffff821117610aac57604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610afa573d9067ffffffffffffffff8211610aac5760405191610aef601f8201601f191660200184610a8a565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610b34575090565b905042101590565b5f610ba9926001600160a01b038293604051968260208901947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024890152604488015260448752610b92606488610a8a565b1694519082865af1610ba2610ac0565b9083610c0e565b8051908115159182610bea575b5050610bbf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100e657602001518015908115036100e6575f80610bb6565b90610c4b5750805115610c2357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610c91575b610c5c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610c5456fea164736f6c634300081a000a6101a0806040523461049a5761180b803803809161001d82856105d8565b8339810190808203610100811261049a5781516001600160401b03811161049a5782019160c08385031261049a576040519160c083016001600160401b038111848210176105ad5760405283516001600160a01b038116810361049a578352610088602085016105fb565b6020840190815260408501519091906001600160a01b038116810361049a576040850190815260608601516001600160401b03811161049a57876100cd918801610649565b95606086019687526080810151976080870198895260a082015160018060401b03811161049a576100fe9201610649565b60a0860190815260208501516001600160a01b038116979092909188840361049a5761012c6040880161068e565b92606061013a818a0161068e565b96607f19011261049a5760405196606088016001600160401b038111898210176105ad5760405261016d60808a016105fb565b885261017b60a08a016105fb565b99602089019a8b5260e061019160c08c016105fb565b60408b019081529a015194515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3835151602081116105c15750516001600160a01b03166080525164ffffffffff1660a0523360c052518051909a906001600160401b0381116105ad57600154600181811c911680156105a3575b602082101461058f57601f811161052c575b506020601f82116001146104ba57819064ffffffffff9a9b9c9d5f926104af575b50508160011b915f199060031b1c1916176001555b5160e052516040516102a7602082816102968183019687815193849201610628565b81010301601f1981018352826105d8565b519051906020811061049e575b50610100526101205261014052610160526101805251166effffffffff0000000000000000000069ffffffffff0000000000600454945160281b16925160501b169260018060781b03191617171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103406064866105d8565b84519082855af161034f61069b565b81610463575b5080610459575b15610414575b60405161106f908161079c823960805181818161049e015281816107530152610c31015260a0518181816101ad01528181610a8801528181610d310152610fa1015260c051818181610acf0152610dcf015260e051818181610334015261065601526101005181610e8c01526101205181818161016d01526105560152610140518181816107840152610b4601526101605181818161024401526108a70152610180518181816107ae0152610b0a0152f35b61044c610451936040519063095ea7b360e01b602083015260248201525f6044820152604481526104466064826105d8565b826106ca565b6106ca565b5f8080610362565b50803b151561035c565b8051801592508215610478575b50505f610355565b819250906020918101031261049a576020610493910161068e565b5f80610470565b5f80fd5b5f199060200360031b1b165f6102b4565b015190505f8061025f565b601f1982169c60015f52815f209d5f5b81811061050f57509164ffffffffff9b9c9d9e918460019594106104f7575b505050811b01600155610274565b01515f1960f88460031b161c191690555f80806104e9565b919e8f60016020928684930151815501940192019e91929e6104ca565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610585575b601f0160051c01905b81811061057a575061023e565b5f815560010161056d565b9091508190610564565b634e487b7160e01b5f52602260045260245ffd5b90607f169061022c565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b038211908210176105ad57604052565b519064ffffffffff8216820361049a57565b6001600160401b0381116105ad57601f01601f191660200190565b5f5b8381106106395750505f910152565b818101518382015260200161062a565b81601f8201121561049a57805161065f8161060d565b9261066d60405194856105d8565b8184526020828401011161049a5761068b9160208085019101610628565b90565b5190811515820361049a57565b3d156106c5573d906106ac8261060d565b916106ba60405193846105d8565b82523d5f602084013e565b606090565b5f806106f29260018060a01b03169360208151910182865af16106eb61069b565b908361073d565b805190811515918261071a575b50506107085750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261049a576020610735910161068e565b155f806106ff565b90610761575080511561075257805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610792575b610772575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561076a56fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610e7657508063164e68de14610da05780631686c90914610b6b57806316c3549d14610b2f5780631bfd681414610af35780632dd3100014610ab05780633f31ae3f146104c25780634800d97f1461047f57806349fc73dd1461037b5780634e390d3e1461035757806351e75e8b1461031d57806375829def14610268578063845aef4b1461022557806390e64d131461020b578063b0604a26146101d1578063bb4b573414610190578063bba72cd314610156578063ce516507146101165763f851a440146100ed575f80fd5b34610112575f3660031901126101125760206001600160a01b035f5416604051908152f35b5f80fd5b3461011257602036600319011261011257602061014c60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257606060045464ffffffffff604051918181168352818160281c16602084015260501c166040820152f35b34610112575f36600319011261011257602061014c610f99565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461011257602036600319011261011257610281610f06565b5f546001600160a01b0381163381036102ee57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602064ffffffffff60035416604051908152f35b34610112575f366003190112610112576040515f6001548060011c90600181168015610475575b6020831081146104615782855290811561043d57506001146103df575b6103db836103cf81850382610f38565b60405191829182610ebf565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610423575090915081016020016103cf6103bf565b91926001816020925483858801015201910190929161040b565b60ff191660208086019190915291151560051b840190910191506103cf90506103bf565b634e487b7160e01b5f52602260045260245ffd5b91607f16916103a2565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261011257600435602435906001600160a01b038216809203610112576044356fffffffffffffffffffffffffffffffff8116809103610112576064359067ffffffffffffffff8211610112573660238301121561011257816004013567ffffffffffffffff8111610112578060051b926024848201019036821161011257610550610f99565b610a59577f0000000000000000000000000000000000000000000000000000000000000000803410610a2a575061059e8660ff6001918060081c5f526002602052161b60405f205416151590565b6109fe576040516020810190878252886040820152856060820152606081526105c8608082610f38565b51902060405160208101918252602081526105e4604082610f38565b519020926105f86020604051970187610f38565b8552602401602085015b8282106109ee57505050935f945b83518610156106525760208660051b85010151908181105f14610641575f52602052600160405f205b950194610610565b905f52602052600160405f20610639565b84907f0000000000000000000000000000000000000000000000000000000000000000036109c65760035464ffffffffff8116156109ac575b508060081c5f52600260205260405f20600160ff83161b8154179055604051926106b484610f1c565b60045464ffffffffff8116806109a5575064ffffffffff421685525b5f9064ffffffffff8160281c168061098e575b5064ffffffffff9081808851169160501c16011660208601526001600160a01b035f5416946040519061071582610f1c565b5f82525f602083015260405196610100880188811067ffffffffffffffff82111761097a5760405287526020870186815260408801858152606089017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808a01917f00000000000000000000000000000000000000000000000000000000000000001515835260a08b01937f00000000000000000000000000000000000000000000000000000000000000001515855260c08c0195865260e08c019687526040519b7fab605ced000000000000000000000000000000000000000000000000000000008d52516001600160a01b031660048d0152516001600160a01b031660248c0152516fffffffffffffffffffffffffffffffff1660448b0152516001600160a01b031660648a0152511515608489015251151560a488015251805164ffffffffff1660c48801526020015164ffffffffff1660e48701525180516001600160a01b03166101048701526020015161012486015264ffffffffff1661014485015283807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61016492602095f193841561096f575f9461091b575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610967575b8161093760209383610f38565b810103126101125751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d6108e8565b3d915061092a565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b865164ffffffffff908116909101811692506106e3565b85526106d0565b64ffffffffff19164264ffffffffff16176003558361068b565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610602565b857febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461011257604036600319011261011257610b84610f06565b6024356fffffffffffffffffffffffffffffffff8116809103610112576001600160a01b035f54163381036102ee575064ffffffffff6003541680151580610d6b575b80610d5c575b610d025750604051610c675f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610c27606486610f38565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610c60610f5a565b9083610fd6565b8051908115159182610cde575b5050610cb357507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101125760200151801590811503610112578480610c74565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610d65610f99565b15610bcd565b5062093a80810164ffffffffff8111610d8c5764ffffffffff164211610bc7565b634e487b7160e01b5f52601160045260245ffd5b34610112576020366003190112610112576004356001600160a01b038116809103610112576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303610e47575047905f80808085855af1610e09610f5a565b5015610e1a57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f366003190112610112576103db907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103cf604082610f38565b9190916020815282518060208301525f5b818110610ef0575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610ed0565b600435906001600160a01b038216820361011257565b6040810190811067ffffffffffffffff82111761097a57604052565b90601f8019910116810190811067ffffffffffffffff82111761097a57604052565b3d15610f94573d9067ffffffffffffffff821161097a5760405191610f89601f8201601f191660200184610f38565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610fce575090565b905042101590565b906110135750805115610feb57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611059575b611024575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561101c56fea164736f6c634300081a000a6101e080604052346104ba57611e8a803803809161001d828561071d565b833981019060e0818303126104ba5780516001600160401b0381116104ba5781019060c0828403126104ba576040519160c083016001600160401b038111848210176105745760405280516001600160a01b03811681036104ba57835261008660208201610740565b6020840190815260408201516001600160a01b03811681036104ba576040850190815260608301516001600160401b0381116104ba57866100c891850161078e565b6060860190815260808085015190870190815260a085015191949091906001600160401b0382116104ba576100ff9189910161078e565b60a087019081526020860151949091906001600160a01b03861686036104ba5761012b604088016107d3565b94610138606089016107d3565b9861014560808a01610740565b60a08a01519099906001600160401b0381116104ba5781018c601f820112156104ba578051906001600160401b038211610574576040519d8e8360051b60200161018f908261071d565b8381526020019260061b8201602001918183116104ba57602001925b8284106106c1575050505060c0015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3845151602081116106aa5750516001600160a01b03166080525164ffffffffff1660a0523360c052518051906001600160401b0382116105745760015490600182811c921680156106a0575b602083101461068c5781601f84931161061e575b50602090601f83116001146105b8575f926105ad575b50508160011b915f199060031b1c1916176001555b5160e052516040516102bc602082816102ab818301968781519384920161076d565b81010301601f19810183528261071d565b519051906020811061059c575b5061010052610120526101405261016052610180526101c0528051905f915f915b8183106104be57836101a05260018060a01b036080511660018060a01b03610160511690604051905f806020840163095ea7b360e01b8152856024860152811960448601526044855261033e60648661071d565b84519082855af161034d6107f4565b81610483575b5080610479575b15610434575b60405161159590816108f582396080518181816105780152818161095d0152610f83015260a05181818161027d01528181610de301528181611083015261130b015260c051818181610e2a0152611121015260e05181818161040e015261072e015261010051816111de01526101205181818161023d015261062701526101405181818161098d0152610ea101526101605181818161031e0152610ad501526101805181818161018901526107bc01526101a0518181816102c1015261078a01526101c0518181816109b70152610e650152f35b61046c610471936040519063095ea7b360e01b602083015260248201525f60448201526044815261046660648261071d565b82610823565b610823565b808080610360565b50803b151561035a565b8051801592508215610498575b505084610353565b81925090602091810103126104ba5760206104b391016107d3565b8480610490565b5f80fd5b91929091906001600160401b036104d585846107e0565b5151166001600160401b039182160190811161058857926104f681836107e0565b519060045491680100000000000000008310156105745760018301806004558310156105605760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ea565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f6102c9565b015190505f80610274565b60015f9081528281209350601f198516905b81811061060657509084600195949392106105ee575b505050811b01600155610289565b01515f1960f88460031b161c191690555f80806105e0565b929360206001819287860151815501950193016105ca565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610682575b90601f859493920160051c01905b818110610674575061025e565b5f8155849350600101610667565b9091508190610659565b634e487b7160e01b5f52602260045260245ffd5b91607f169161024a565b6371935f2960e11b5f52600452602060245260445ffd5b6040848303126104ba5760408051919082016001600160401b03811183821017610574576040528451906001600160401b03821682036104ba57826020926040945261070e838801610740565b838201528152019301926101ab565b601f909101601f19168101906001600160401b0382119082101761057457604052565b519064ffffffffff821682036104ba57565b6001600160401b03811161057457601f01601f191660200190565b5f5b83811061077e5750505f910152565b818101518382015260200161076f565b81601f820112156104ba5780516107a481610752565b926107b2604051948561071d565b818452602082840101116104ba576107d0916020808501910161076d565b90565b519081151582036104ba57565b80518210156105605760209160051b010190565b3d1561081e573d9061080582610752565b91610813604051938461071d565b82523d5f602084013e565b606090565b5f8061084b9260018060a01b03169360208151910182865af16108446107f4565b9083610896565b8051908115159182610873575b50506108615750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104ba57602061088e91016107d3565b155f80610858565b906108ba57508051156108ab57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806108eb575b6108cb575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156108c356fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146111c857508063164e68de146110f25780631686c90914610ec657806316c3549d14610e8a5780631bfd681414610e4e5780632dd3100014610e0b5780633f31ae3f1461059c5780634800d97f1461055957806349fc73dd146104555780634e390d3e1461043157806351e75e8b146103f757806375829def14610342578063845aef4b146102ff57806390e64d13146102e5578063936c63d9146102a1578063bb4b573414610260578063bba72cd314610226578063bf4ed03f146101ad578063ce36b3351461016c578063ce5165071461012c5763f851a44014610103575f80fd5b34610128575f3660031901126101285760206001600160a01b035f5416604051908152f35b5f80fd5b3461012857602036600319011261012857602061016260043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f366003190112610128576101c5611340565b6040518091602082016020835281518091526020604084019201905f5b8181106101f0575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152869550604090940193909201916001016101e2565b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f366003190112610128576020610162611303565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101285760203660031901126101285761035b611258565b5f546001600160a01b0381163381036103c857506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602064ffffffffff60035416604051908152f35b34610128575f366003190112610128576040515f6001548060011c9060018116801561054f575b60208310811461053b5782855290811561051757506001146104b9575b6104b5836104a98185038261128a565b60405191829182611211565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104fd575090915081016020016104a9610499565b9192600181602092548385880101520191019092916104e5565b60ff191660208086019190915291151560051b840190910191506104a99050610499565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047c565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261012857600435602435906001600160a01b03821680920361012857604435906001600160801b03821691828103610128576064359367ffffffffffffffff851161012857366023860112156101285784600401359467ffffffffffffffff86116101285760248660051b82010136811161012857610621611303565b610db4577f0000000000000000000000000000000000000000000000000000000000000000803410610d85575061066f8560ff6001918060081c5f526002602052161b60405f205416151590565b610d595760405160208101908682528460408201528760608201526060815261069960808261128a565b51902060405160208101918252602081526106b560408261128a565b519020916106c2886112eb565b976106d0604051998a61128a565b8852602401602088015b828210610d4957505050925f935b865185101561072a576106fb85886113f5565b519081811015610719575f52602052600160405f205b9401936106e8565b905f52602052600160405f20610711565b85907f000000000000000000000000000000000000000000000000000000000000000003610d215760035464ffffffffff811615610d07575b508160081c5f52600260205260405f20600160ff84161b815417905567ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610cdc57507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff8116610cd6575064ffffffffff4216935b6107fa611340565b90815191610807836112eb565b92610815604051948561128a565b808452601f19610824826112eb565b015f5b818110610cb357505061085661085167ffffffffffffffff610848856113d4565b5151168761144e565b611409565b64ffffffffff806020610868866113d4565b510151168a0116906001600160801b03604051916108858361126e565b16918282526020820152610898866113d4565b526108a2856113d4565b50916001905b828210610c1f5750506001600160801b038216858111610c0b578511610be0575b50505064ffffffffff60206108e25f19845101846113f5565b510151166001600160a01b035f54169064ffffffffff604051976109058961126e565b16875260208701526040516109198161126e565b5f81525f602082015260405191610100830183811067ffffffffffffffff821117610bcc5760409493929452815260208101928684526040820197858952606083017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152608084017f00000000000000000000000000000000000000000000000000000000000000001515815260a08501917f00000000000000000000000000000000000000000000000000000000000000001515835260c0860193845260e086019485526040519b8c987fd6a03d31000000000000000000000000000000000000000000000000000000008a526101648a0197516001600160a01b031660048b0152516001600160a01b031660248a0152516001600160801b03166044890152516001600160a01b03166064880152511515608487015251151560a486015251805164ffffffffff1660c48601526020015164ffffffffff1660e48501525180516001600160a01b031661010485015260200151610124840152610144830161016090528151809152610184830191602001905f5b818110610b9757505050908060209203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1938415610b8c575f94610b38575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610b84575b81610b546020938361128a565b810103126101285751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610b05565b3d9150610b47565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610ab9565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610bf783925f1901866113f5565b5193031681835116011690528580806108c9565b634e487b7160e01b5f52600160045260245ffd5b90926001600160801b03600191610c4e61085167ffffffffffffffff610c4589886113f5565b5151168b61144e565b9064ffffffffff806020610c655f198b018d6113f5565b51015116816020610c768b8a6113f5565b51015116011660405190610c898261126e565b84841682526020820152610c9d888b6113f5565b52610ca8878a6113f5565b5001169301906108a8565b602090604051610cc28161126e565b5f81525f8382015282828901015201610827565b936107f2565b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b64ffffffffff19164264ffffffffff161760035584610763565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106da565b847febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012857604036600319011261012857610edf611258565b6024356001600160801b038116809103610128576001600160a01b035f54163381036103c8575064ffffffffff60035416801515806110bd575b806110ae575b6110545750604051610fb95f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610f7960648661128a565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610fb26112ac565b90836114fc565b8051908115159182611030575b505061100557507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101285760200151801590811503610128578480610fc6565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506110b7611303565b15610f1f565b5062093a80810164ffffffffff81116110de5764ffffffffff164211610f19565b634e487b7160e01b5f52601160045260245ffd5b34610128576020366003190112610128576004356001600160a01b038116809103610128576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303611199575047905f80808085855af161115b6112ac565b501561116c57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f366003190112610128576104b5907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104a960408261128a565b9190916020815282518060208301525f5b818110611242575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611222565b600435906001600160a01b038216820361012857565b6040810190811067ffffffffffffffff821117610bcc57604052565b90601f8019910116810190811067ffffffffffffffff821117610bcc57604052565b3d156112e6573d9067ffffffffffffffff8211610bcc57604051916112db601f8201601f19166020018461128a565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610bcc5760051b60200190565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611338575090565b905042101590565b6004549061134d826112eb565b9161135b604051938461128a565b80835260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602085015b8383106113975750505050565b6001602081926040516113a98161126e565b64ffffffffff865467ffffffffffffffff8116835260401c168382015281520192019201919061138a565b8051156113e15760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156113e15760209160051b010190565b6001600160801b038111611423576001600160801b031690565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f19838209838202918280831092039180830392146114eb57670de0b6b3a76400008210156114bb577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b90611539575080511561151157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061157f575b61154a575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561154256fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = hex"6080806040523460155761600c908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c0819052610300819052610320819052610340819052610360819052610380526103a08190526103c0526102e08190526100b6906100ad600435614824565b61030052614b9d565b610320526102e0516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c99565b610260526102e0516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b5016610280526102e0516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614e3b565b610360526102e0516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615568565b970116615568565b980116615568565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614f3b565b16906150a1565b9061045a6001600160a01b036102405116614b9d565b906020610240015190602460206001600160a01b0360a0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360a0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610522945f91614589575b50169116615397565b610320516103a051939091906105ac600161054a6064610543818a06615a13565b9804615568565b602060405198826105648b945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810188520186614710565b61016061024001519561012061024001519760c061024001519560405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260e06101605101516108ec6109cb60046007602760586106e3610100610160510151610160515190615b14565b60b76106ee5f615e04565b985f6102205260206102205261071660405161070d6102205182614710565b5f815284615832565b1561456b57601b60909a5b61072a8c615568565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161077081846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d382518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109868251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ad82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108ec610a3960046007602760586040516109fe6102205182614710565b5f815260b7610a0d6001615e04565b98601b6028610a1b8c615f0f565b610a2484615f87565b8082111561456457505b019a61072a8c615568565b61016083015261018082015260206101605101516108ec610a7a6004600760276058604051610a6b6102205182614710565b5f815260b7610a0d6002615e04565b8252602082015260286080610160510151604051610a9b6102205182614710565b5f81526108ec610ae56004600760276058610ab66003615e04565b9660b7610ac289615f0f565b610acb8b615f87565b8082111561455c5750995b601b8c8c019a61072a8c615568565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7461010082015161016083015183519060a085015192615034565b60608201526101006101208190526040516101a0819052610b959190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf7610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d638183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119426118bd6073606b60405196610eec6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113516101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193d6014602261140a615ad9565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153f6025603589605e87519561022051890196611480818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e382518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165685602361154d615ad9565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d6818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161f82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117e060726023611665615ad9565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f4815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173882609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e8615ad9565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119068251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b615034565b60e052611956611950614dc5565b85615832565b938415614541575b5060c061010081905260405191906119769083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a538160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dce6102205182614710565b5f8152955b156141d957604051611de76101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b604051926120206107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ef9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0d926146ca565b016032018082518093610220510191612a25926146ca565b018082518093610220510191612a3a926146ca565b018082518093610220510191612a4f926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6f9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abf926146ca565b60805101815191826026830191610220510191612adb926146ca565b016026018082518093610220510191612af3926146ca565b0160a051519080826102205160a0510191612b0d926146ca565b0160e051519080826102205160e0510191612b27926146ca565b018082518093610220510191612b3c926146ca565b01610140515190808261022051610140510191612b58926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9a91614710565b6101605160a00151906101605160c00151916101605160400151906101605160600151612bc78583615d58565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615d58565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615dbf565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615dbf565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d90615568565b916134a790615568565b906134b190615568565b936134bb90615568565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b610380526102e0518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b610340819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516102e05182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b9d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103005161026051610320516102405191939291613afc906001600160a01b0316614b9d565b613b07602435615568565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61030051613e3e602435615568565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed6906156c7565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c0819052614076906156c7565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101205182015290612010565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd3565b61455591945061454f614e00565b90615832565b925f61195e565b905099610ad6565b9050610a2e565b601b60d09a610721565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610519565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104ba565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614b79575b5060409161489483516148648582614710565b600a81527f5341422d4c4f434b555000000000000000000000000000000000000000000000602082015282615832565b156148d45750506148a781519182614710565b600e81527f5361626c696572204c6f636b7570000000000000000000000000000000000000602082015290565b61491383516148e38582614710565b600e81527f5341422d4c4f434b55502d4c494e000000000000000000000000000000000000602082015282615832565b8015614b34575b1561495a57505061492d81519182614710565b601581527f5361626c696572204c6f636b7570204c696e6561720000000000000000000000602082015290565b61499983516149698582614710565b600e81527f5341422d4c4f434b55502d44594e000000000000000000000000000000000000602082015282615832565b8015614aef575b156149e05750506149b381519182614710565b601681527f5361626c696572204c6f636b75702044796e616d696300000000000000000000602082015290565b614a1f83516149ef8582614710565b600e81527f5341422d4c4f434b55502d545241000000000000000000000000000000000000602082015282615832565b8015614aaa575b15614a66575050614a3981519182614710565b601781527f5361626c696572204c6f636b7570205472616e63686564000000000000000000602082015290565b614aa69083519384937f16ee429d0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614aea8351614aba8582614710565b601181527f5341422d56322d4c4f434b55502d545241000000000000000000000000000000602082015282615832565b614a26565b50614b2f8351614aff8582614710565b601181527f5341422d56322d4c4f434b55502d44594e000000000000000000000000000000602082015282615832565b6149a0565b50614b748351614b448582614710565b601181527f5341422d56322d4c4f434b55502d4c494e000000000000000000000000000000602082015282615832565b61491a565b614b969192503d805f833e614b8e8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614bb6606084614710565b602a8352602083016040368237835115614c855760309053825160011015614c85576078602184015360295b60018111614c235750614bf3575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c85577f3031323334353637383961626364656600000000000000000000000000000000901a614c5e838661585f565b5360041c908015614c71575f1901614be2565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614cbd602482614710565b51915afa614cc9614793565b90158015614db9575b614d7d5780602080614ce9935183010191016147c2565b601e8151115f14614d305750604051614d03604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614d3981615870565b15614d415790565b50604051614d50604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d8c604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614cd2565b60405190614dd4604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614e0f604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614f275760048103614e555750614821614e00565b60038103614e995750604051614e6c604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614edd5750604051614eb0604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614eec57614821614dc5565b604051614efa604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614f78602482614710565b51915afa614f84614793565b9080614fb3575b15614fae576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f8b565b60405190614fcd604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615008604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b9061505f9493615090602061509f95615082828096816040519c8d8b83829d519485930191016146ca565b8901615073825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b908115615376578061536657505b8060018110156151185750506150c3614ff9565b61482160026020604051846150e182965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615308576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516151548482614710565b5f8152815260409182516151688482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151a18482614710565b600181527f4d00000000000000000000000000000000000000000000000000000000000000858201528383015282516151da8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516152148482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e88210156152ee5784519461525e8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b600781106152db575050600160fd1b602786015250600884526152c2906152bc906152b7602887614710565b615568565b91615a13565b916005851015614c85576148219460051b015192615034565b818101830151878201840152820161528b565b9490915060016103e86064600a8504069304910194615247565b50615311614fbe565b614821600860206040518461532f82965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e257046150af565b5050604051615386604082614710565b60018152600360fc1b602082015290565b620151809103048061540157506153ac614ff9565b61482160066020604051846153ca82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154d8576001810361549457614821615456604051615426604082614710565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615568565b6020604051938261547086945180928580880191016146ca565b8301615484825180938580850191016146ca565b010103601f198101835282614710565b6148216154566040516154a8604082614710565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615568565b506154e1614fbe565b614821600a6020604051846154ff82965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b9061554082614777565b61554d6040519182614710565b828152809261555e601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561569f575b806d04ee2d6d415b85acef8100000000600a921015615684575b662386f26fc10000811015615670575b6305f5e10081101561565f575b612710811015615650575b6064811015615642575b1015615637575b600a60216155f260018501615536565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a835304801561563257600a90916155f7565b505090565b6001909101906155e2565b6064600291049301926155db565b612710600491049301926155d1565b6305f5e100600891049301926155c6565b662386f26fc10000601091049301926155b9565b6d04ee2d6d415b85acef8100000000602091049301926155a9565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461558f565b9081511561581c57604051916156de606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614c7157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614c71576157749060021b615536565b90602082019080815182019560208701908151925f83525b8881106157ce57505060039394959650525106806001146157bc576002146157b2575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761578c565b905060405161582c602082614710565b5f815290565b9081518151908181149384615849575b5050505090565b602092939450820120920120145f808080615842565b908151811015614c85570160200190565b8051905f5b82811061588457505050600190565b7fff000000000000000000000000000000000000000000000000000000000000006158af828461585f565b5116600160fd1b811490600360fc1b811015806159e9575b7f410000000000000000000000000000000000000000000000000000000000000082101590816159be575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615993575b8415615969575b508315615961575b508215615959575b508115615951575b501561594a57600101615875565b5050505f90565b90505f61593c565b91505f615934565b92505f61592c565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f615924565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061591d565b7f5a0000000000000000000000000000000000000000000000000000000000000083111591506158f2565b507f39000000000000000000000000000000000000000000000000000000000000008111156158c7565b80615a27575060405161582c602082614710565b600a811015615a8d57615a3990615568565b614821602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7c81518092602086860191016146ca565b81010301601f198101835282614710565b615a9690615568565b614821602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a7c81518092602086860191016146ca565b60405190615ae8604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d4857615b22615ad9565b9061271003906127108211614c7157602e6061916050615b4461482195615568565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615bd1815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c5882518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615cb9825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b505060405161582c602082614710565b600d61509f9193929360206040519582615d7b88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615dae8251809385602d850191016146ca565b01010301601f198101845283614710565b600561509f9193929360206040519582615de288945180928580880191016146ca565b830164010714051160dd1b83820152615dae82518093856025850191016146ca565b6004811015614f275780615e4e5750604051615e21604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e925750604051615e65604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615ed457604051615ea7604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615ee2604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f908051801561594a5790600d915f925f925b828410615f355750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f69888561585f565b511614615f7f575b820194600101929190615f22565b859450615f71565b5f908051801561594a57906010915f925f925b828410615fad575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615fe1888561585f565b511614615ff7575b820194600101929190615f9a565b859450615fe956fea164736f6c634300081a000a"; diff --git a/script/Base.s.sol b/script/Base.s.sol index 206ff9f85..0c0e40857 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -91,7 +91,7 @@ contract BaseScript is Script { maxCountMap[43114] = 490; // Base chain ID. - maxCountMap[8453] = 2020; + maxCountMap[8453] = 2010; // Blast chain ID. maxCountMap[81457] = 1010; diff --git a/script/protocol/DeploymentLogger.s.sol b/script/protocol/DeploymentLogger.s.sol index f3ec7d0bf..0fb49c7d2 100644 --- a/script/protocol/DeploymentLogger.s.sol +++ b/script/protocol/DeploymentLogger.s.sol @@ -44,7 +44,7 @@ abstract contract DeploymentLogger is BaseScript { // If there is no explorer URL set for a specific chain, use a placeholder. if (explorerMap[block.chainid].equal("")) { - explorerMap[block.chainid] = "N/A"; + explorerMap[block.chainid] = ""; } // If there is no chain name set for a specific chain, use the chain ID. diff --git a/shell/update-counts.sh b/shell/update-counts.sh index 395bd1ffa..f9c0cd97f 100755 --- a/shell/update-counts.sh +++ b/shell/update-counts.sh @@ -16,8 +16,8 @@ bun run build:optimized # Generalized function to update counts update_counts() { - local test_name=$1 - local map_name=$2 + local test_name="Segments" + local map_name="maxCountMap" echo -e "\nRunning forge test for estimating $test_name..." local output=$(FOUNDRY_PROFILE=benchmark forge t --mt "test_Estimate${test_name}" -vv) echo -e "\nParsing output for $test_name..." @@ -43,7 +43,7 @@ update_counts() { } # Call the function with specific parameters for segments and tranches -update_counts "Segments" "maxCountMap" +update_counts # Reformat the code with Forge forge fmt $BASE_SCRIPT diff --git a/test/Base.t.sol b/test/Base.t.sol index 747e54f69..e8ad70126 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -18,6 +18,7 @@ import { SablierMerkleFactory } from "src/periphery/SablierMerkleFactory.sol"; import { ERC20MissingReturn } from "./mocks/erc20/ERC20MissingReturn.sol"; import { ERC20Mock } from "./mocks/erc20/ERC20Mock.sol"; import { RecipientGood } from "./mocks/Hooks.sol"; +import { NFTDescriptorMock } from "./mocks/NFTDescriptorMock.sol"; import { Noop } from "./mocks/Noop.sol"; import { Assertions } from "./utils/Assertions.sol"; import { Calculations } from "./utils/Calculations.sol"; @@ -47,6 +48,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi ISablierMerkleLL internal merkleLL; ISablierMerkleLT internal merkleLT; ILockupNFTDescriptor internal nftDescriptor; + NFTDescriptorMock internal nftDescriptorMock; Noop internal noop; RecipientGood internal recipientGood; ERC20MissingReturn internal usdt; @@ -58,8 +60,8 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi function setUp() public virtual { // Deploy the base test contracts. dai = new ERC20Mock("Dai Stablecoin", "DAI"); - recipientGood = new RecipientGood(); noop = new Noop(); + recipientGood = new RecipientGood(); usdt = new ERC20MissingReturn("Tether USD", "USDT", 6); // Label the base test contracts. @@ -153,11 +155,14 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi if (!isBenchmarkProfile() && !isTestOptimizedProfile()) { batchLockup = new SablierBatchLockup(); nftDescriptor = new LockupNFTDescriptor(); + nftDescriptorMock = new NFTDescriptorMock(); lockup = new SablierLockup(users.admin, nftDescriptor, defaults.MAX_COUNT()); merkleFactory = new SablierMerkleFactory(users.admin); } else { (nftDescriptor, lockup, batchLockup, merkleFactory) = deployOptimizedProtocol(users.admin, defaults.MAX_COUNT()); + nftDescriptorMock = + NFTDescriptorMock(deployCode("out-optimized/NFTDescriptorMock.sol/NFTDescriptorMock.json")); } vm.label({ account: address(batchLockup), newLabel: "BatchLockup" }); vm.label({ account: address(lockup), newLabel: "Lockup" }); diff --git a/test/core/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol index c018f3d8e..a8660d16b 100644 --- a/test/core/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -138,11 +138,8 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test { vars.initialBrokerBalance = vars.balances[1]; vars.streamId = lockup.nextStreamId(); - vars.timestamps = Lockup.Timestamps({ - start: params.startTime, - cliff: 0, - end: params.segments[params.segments.length - 1].timestamp - }); + vars.timestamps = + Lockup.Timestamps({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -171,8 +168,7 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.startTime, - endTime: vars.timestamps.end, + timestamps: vars.timestamps, broker: params.broker }), params.segments @@ -188,13 +184,13 @@ abstract contract Lockup_Dynamic_Fork_Test is Fork_Test { assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset"); assertEq(lockup.getEndTime(vars.streamId), vars.timestamps.end, "endTime"); assertEq(lockup.isCancelable(vars.streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(vars.streamId), false, "isDepleted"); - assertEq(lockup.isStream(vars.streamId), true, "isStream"); - assertEq(lockup.isTransferable(vars.streamId), true, "isTransferable"); + assertTrue(lockup.isStream(vars.streamId), "isStream"); + assertTrue(lockup.isTransferable(vars.streamId), "isTransferable"); assertEq(lockup.getRecipient(vars.streamId), params.recipient, "recipient"); assertEq(lockup.getSender(vars.streamId), params.sender, "sender"); assertEq(lockup.getStartTime(vars.streamId), params.startTime, "startTime"); - assertEq(lockup.wasCanceled(vars.streamId), false, "wasCanceled"); + assertFalse(lockup.isDepleted(vars.streamId), "isDepleted"); + assertFalse(lockup.wasCanceled(vars.streamId), "wasCanceled"); assertEq(lockup.getSegments(vars.streamId), params.segments, "segments"); // Assert that the stream's status is correct. diff --git a/test/core/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol index 016ab2972..f4521b0ab 100644 --- a/test/core/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -41,6 +41,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { uint128 withdrawAmount; uint40 warpTimestamp; Lockup.Timestamps timestamps; + uint40 cliffTime; Broker broker; } @@ -124,14 +125,13 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { params.totalAmount = boundUint128(params.totalAmount, 1, uint128(initialHolderBalance)); // The cliff time must be either zero or greater than the start time. - vars.hasCliff = params.timestamps.cliff > 0; + vars.hasCliff = params.cliffTime > 0; if (vars.hasCliff) { - params.timestamps.cliff = boundUint40( - params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks - ); + params.cliffTime = + boundUint40(params.cliffTime, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks); } // 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); + vars.endTimeLowerBound = maxOfTwo(params.timestamps.start, params.cliffTime); params.timestamps.end = boundUint40(params.timestamps.end, vars.endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); @@ -168,6 +168,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { cancelable: true, transferable: true, timestamps: params.timestamps, + cliffTime: params.cliffTime, broker: params.broker.account }); @@ -180,11 +181,10 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.timestamps.start, - endTime: params.timestamps.end, + timestamps: params.timestamps, broker: params.broker }), - params.timestamps.cliff + params.cliffTime ); // Check if the stream is settled. It is possible for a Lockup Linear stream to settle at the time of creation @@ -195,16 +195,16 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { // Assert that the stream has been created. assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount"); assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset"); - assertEq(lockup.getCliffTime(vars.streamId), params.timestamps.cliff, "cliffTime"); + assertEq(lockup.getCliffTime(vars.streamId), params.cliffTime, "cliffTime"); assertEq(lockup.getEndTime(vars.streamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(vars.streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(vars.streamId), false, "isDepleted"); - assertEq(lockup.isStream(vars.streamId), true, "isStream"); - assertEq(lockup.isTransferable(vars.streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(vars.streamId), "isDepleted"); + assertTrue(lockup.isStream(vars.streamId), "isStream"); + assertTrue(lockup.isTransferable(vars.streamId), "isTransferable"); assertEq(lockup.getRecipient(vars.streamId), params.recipient, "recipient"); assertEq(lockup.getSender(vars.streamId), params.sender, "sender"); assertEq(lockup.getStartTime(vars.streamId), params.timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(vars.streamId), false, "wasCanceled"); + assertFalse(lockup.wasCanceled(vars.streamId), "wasCanceled"); // Assert that the stream's status is correct. vars.actualStatus = lockup.statusOf(vars.streamId); @@ -254,7 +254,7 @@ abstract contract Lockup_Linear_Fork_Test is Fork_Test { // Simulate the passage of time. params.warpTimestamp = boundUint40( params.warpTimestamp, - vars.hasCliff ? params.timestamps.cliff : params.timestamps.start + 1 seconds, + vars.hasCliff ? params.cliffTime : params.timestamps.start + 1 seconds, params.timestamps.end + 100 seconds ); vm.warp({ newTimestamp: params.warpTimestamp }); diff --git a/test/core/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol index 3fc7f3100..353b29982 100644 --- a/test/core/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -138,11 +138,8 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test { vars.initialBrokerBalance = vars.balances[1]; vars.streamId = lockup.nextStreamId(); - vars.timestamps = Lockup.Timestamps({ - start: params.startTime, - cliff: 0, - end: params.tranches[params.tranches.length - 1].timestamp - }); + vars.timestamps = + Lockup.Timestamps({ start: params.startTime, end: params.tranches[params.tranches.length - 1].timestamp }); // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); @@ -171,8 +168,7 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.startTime, - endTime: vars.timestamps.end, + timestamps: vars.timestamps, broker: params.broker }), params.tranches @@ -188,13 +184,13 @@ abstract contract Lockup_Tranched_Fork_Test is Fork_Test { assertEq(lockup.getAsset(vars.streamId), FORK_ASSET, "asset"); assertEq(lockup.getEndTime(vars.streamId), vars.timestamps.end, "endTime"); assertEq(lockup.isCancelable(vars.streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(vars.streamId), false, "isDepleted"); - assertEq(lockup.isStream(vars.streamId), true, "isStream"); - assertEq(lockup.isTransferable(vars.streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(vars.streamId), "isDepleted"); + assertTrue(lockup.isStream(vars.streamId), "isStream"); + assertTrue(lockup.isTransferable(vars.streamId), "isTransferable"); assertEq(lockup.getRecipient(vars.streamId), params.recipient, "recipient"); assertEq(lockup.getSender(vars.streamId), params.sender, "sender"); assertEq(lockup.getStartTime(vars.streamId), params.startTime, "startTime"); - assertEq(lockup.wasCanceled(vars.streamId), false, "wasCanceled"); + assertFalse(lockup.wasCanceled(vars.streamId), "wasCanceled"); assertEq(lockup.getTranches(vars.streamId), params.tranches, "tranches"); // Assert that the stream's status is correct. diff --git a/test/core/integration/Integration.t.sol b/test/core/integration/Integration.t.sol index 30ee41a56..ef8143667 100644 --- a/test/core/integration/Integration.t.sol +++ b/test/core/integration/Integration.t.sol @@ -2,6 +2,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { Base_Test } from "../../Base.t.sol"; import { @@ -13,22 +14,20 @@ import { } from "../../mocks/Hooks.sol"; /// @notice Common logic needed by all integration tests, both concrete and fuzz tests. + abstract contract Integration_Test is Base_Test { /*////////////////////////////////////////////////////////////////////////// VARIABLES //////////////////////////////////////////////////////////////////////////*/ + Lockup.Model internal lockupModel; + // Various stream IDs to be used across the tests. - // An array of stream IDs to be canceled. - uint256[] internal cancelMultipleStreamIds; + // Default stream ID. uint256 internal defaultStreamId; // A stream ID with a different sender and recipient. - uint256 internal differentSenderRecipientStreamId; - // A stream ID with an early end time. - uint256 internal earlyEndtimeStreamId; - // A stream ID with the same sender and recipient. - uint256 internal identicalSenderRecipientStreamId; + uint256 internal differentRecipientStreamId; // A non-cancelable stream ID. uint256 internal notCancelableStreamId; // A non-transferable stream ID. @@ -43,11 +42,19 @@ abstract contract Integration_Test is Base_Test { uint256 internal recipientReentrantStreamId; // Astream with a reverting contract as the stream's recipient. uint256 internal recipientRevertStreamId; - // An array of stream IDs to be withdrawn from. - uint256[] internal withdrawMultipleStreamIds; - // An array of amounts to be used in `withdrawMultiple` tests. - uint128[] internal withdrawAmounts; + struct CreateParams { + Lockup.CreateWithTimestamps createWithTimestamps; + Lockup.CreateWithDurations createWithDurations; + uint40 cliffTime; + LockupLinear.Durations durations; + LockupDynamic.Segment[] segments; + LockupDynamic.SegmentWithDuration[] segmentsWithDurations; + LockupTranched.Tranche[] tranches; + LockupTranched.TrancheWithDuration[] tranchesWithDurations; + } + + CreateParams internal _defaultParams; /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS @@ -77,18 +84,181 @@ abstract contract Integration_Test is Base_Test { vm.label({ account: address(recipientReentrant), newLabel: "Recipient Reentrant" }); vm.label({ account: address(recipientReverting), newLabel: "Recipient Reverting" }); - withdrawAmounts.push(defaults.WITHDRAW_AMOUNT()); - withdrawAmounts.push(defaults.DEPOSIT_AMOUNT()); - withdrawAmounts.push(defaults.WITHDRAW_AMOUNT() / 2); + _defaultParams.createWithTimestamps = defaults.createWithTimestamps(); + _defaultParams.createWithDurations = defaults.createWithDurations(); + _defaultParams.cliffTime = defaults.CLIFF_TIME(); + _defaultParams.durations = defaults.durations(); + + // See https://github.com/ethereum/solidity/issues/12783 + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); + LockupDynamic.Segment[] memory segments = defaults.segments(); + for (uint256 i; i < defaults.SEGMENT_COUNT(); ++i) { + _defaultParams.segments.push(segments[i]); + _defaultParams.segmentsWithDurations.push(segmentsWithDurations[i]); + } + LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + for (uint256 i; i < defaults.TRANCHE_COUNT(); ++i) { + _defaultParams.tranches.push(tranches[i]); + _defaultParams.tranchesWithDurations.push(tranchesWithDurations[i]); + } + + // Set the default Lockup model as Dynamic, we will override the default stream IDs where necessary. + lockupModel = Lockup.Model.LOCKUP_DYNAMIC; + + // Initialize streams IDs. + createDefaultStreamIds(); + } + + /*////////////////////////////////////////////////////////////////////////// + CREATE-DEFAULT + //////////////////////////////////////////////////////////////////////////*/ + + function createDefaultStreamIds() internal { + defaultStreamId = createDefaultStream(); + differentRecipientStreamId = createDefaultStreamWithRecipient(address(recipientGood)); + notCancelableStreamId = createDefaultStreamNonCancelable(); + notTransferableStreamId = createDefaultStreamNonTransferable(); + recipientGoodStreamId = createDefaultStreamWithRecipient(address(recipientGood)); + recipientInvalidSelectorStreamId = createDefaultStreamWithRecipient(address(recipientInvalidSelector)); + recipientReentrantStreamId = createDefaultStreamWithRecipient(address(recipientReentrant)); + recipientRevertStreamId = createDefaultStreamWithRecipient(address(recipientReverting)); + } + + function createDefaultStream(Lockup.CreateWithTimestamps memory params) internal returns (uint256 streamId) { + if (lockupModel == Lockup.Model.LOCKUP_DYNAMIC) { + streamId = lockup.createWithTimestampsLD(params, _defaultParams.segments); + } else if (lockupModel == Lockup.Model.LOCKUP_LINEAR) { + streamId = lockup.createWithTimestampsLL(params, _defaultParams.cliffTime); + } else if (lockupModel == Lockup.Model.LOCKUP_TRANCHED) { + streamId = lockup.createWithTimestampsLT(params, _defaultParams.tranches); + } + } + + function createDefaultStream() internal returns (uint256 streamId) { + streamId = createDefaultStream(_defaultParams.createWithTimestamps); + } + + function createDefaultStreamNonCancelable() internal returns (uint256 streamId) { + Lockup.CreateWithTimestamps memory params = _defaultParams.createWithTimestamps; + params.cancelable = false; + streamId = createDefaultStream(params); + } + + function createDefaultStreamNonTransferable() internal returns (uint256 streamId) { + Lockup.CreateWithTimestamps memory params = _defaultParams.createWithTimestamps; + params.transferable = false; + streamId = createDefaultStream(params); + } + + function createDefaultStreamWithDurations() internal returns (uint256 streamId) { + if (lockupModel == Lockup.Model.LOCKUP_DYNAMIC) { + streamId = + lockup.createWithDurationsLD(_defaultParams.createWithDurations, _defaultParams.segmentsWithDurations); + } else if (lockupModel == Lockup.Model.LOCKUP_LINEAR) { + streamId = lockup.createWithDurationsLL(_defaultParams.createWithDurations, _defaultParams.durations); + } else if (lockupModel == Lockup.Model.LOCKUP_TRANCHED) { + streamId = + lockup.createWithDurationsLT(_defaultParams.createWithDurations, _defaultParams.tranchesWithDurations); + } + } + + function createDefaultStreamWithEndTimeLD(uint40 endTime) internal returns (uint256 streamId) { + Lockup.CreateWithTimestamps memory params = _defaultParams.createWithTimestamps; + LockupDynamic.Segment[] memory segments = _defaultParams.segments; + params.timestamps.end = endTime; + segments[1].timestamp = endTime; + streamId = lockup.createWithTimestampsLD(params, segments); + } + + function createDefaultStreamWithRecipient(address recipient) internal returns (uint256 streamId) { + streamId = createDefaultStreamWithUsers(recipient, users.sender); + } + + function createDefaultStreamWithUsers(address recipient, address sender) internal returns (uint256 streamId) { + Lockup.CreateWithTimestamps memory params = _defaultParams.createWithTimestamps; + params.recipient = recipient; + params.sender = sender; + streamId = createDefaultStream(params); } /*////////////////////////////////////////////////////////////////////////// - EXPECT CALLS + COMMON-REVERT-TESTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Expects a delegate call error. - function expectRevertDueToDelegateCall(bool success, bytes memory returnData) internal pure { + function expectRevert_CallerMaliciousThirdParty(bytes memory callData) internal { + resetPrank({ msgSender: users.eve }); + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "malicious call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve), + "malicious call return data" + ); + } + + function expectRevert_CallerRecipient(bytes memory callData) internal { + resetPrank({ msgSender: users.recipient }); + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "recipient call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.recipient), + "recipient call return data" + ); + } + + function expectRevert_CANCELEDStatus(bytes memory callData) internal { + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + lockup.cancel(defaultStreamId); + + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "canceled status call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_StreamCanceled.selector, defaultStreamId), + "canceled status call return data" + ); + } + + function expectRevert_DelegateCall(bytes memory callData) internal { + (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); assertFalse(success, "delegatecall success"); assertEq(returnData, abi.encodeWithSelector(Errors.DelegateCall.selector), "delegatecall return data"); } + + function expectRevert_DEPLETEDStatus(bytes memory callData) internal { + vm.warp({ newTimestamp: defaults.END_TIME() }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "depleted status call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId), + "depleted status call return data" + ); + } + + function expectRevert_Null(bytes memory callData) internal { + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "null call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId), + "null call return data" + ); + } + + function expectRevert_SETTLEDStatus(bytes memory callData) internal { + vm.warp({ newTimestamp: defaults.END_TIME() }); + + (bool success, bytes memory returnData) = address(lockup).call(callData); + assertFalse(success, "settled status call success"); + assertEq( + returnData, + abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, defaultStreamId), + "settled status call return data" + ); + } } diff --git a/test/core/integration/concrete/constructor.t.sol b/test/core/integration/concrete/constructor.t.sol index d016095c7..1fe56e3e6 100644 --- a/test/core/integration/concrete/constructor.t.sol +++ b/test/core/integration/concrete/constructor.t.sol @@ -21,25 +21,27 @@ contract Constructor_Integration_Concrete_Test is Integration_Test { maxCount: defaults.MAX_COUNT() }); - // {SablierLockup.constant} + // {SablierLockupBase.constant} UD60x18 actualMaxBrokerFee = constructedLockup.MAX_BROKER_FEE(); UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - // {SablierLockup.constructor} + // {Adminable.constructor} address actualAdmin = constructedLockup.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); + // {SablierLockupBase.constructor} uint256 actualStreamId = constructedLockup.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); + // {SablierLockupBase.constructor} address actualNFTDescriptor = address(constructedLockup.nftDescriptor()); address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - // {SablierLockup.supportsInterface} + // {SablierLockupBase.supportsInterface} assertTrue(constructedLockup.supportsInterface(0x49064906), "ERC-4906 interface ID"); // {SablierLockup.constructor} diff --git a/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol b/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol index 2e2b71d56..cbafeccf1 100644 --- a/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol +++ b/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol @@ -6,7 +6,7 @@ import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test { +contract AllowToHook_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_CallerNotAdmin() external { // Make Eve the caller in this test. resetPrank({ msgSender: users.eve }); diff --git a/test/core/integration/concrete/lockup-base/batch/batch.t.sol b/test/core/integration/concrete/lockup-base/batch/batch.t.sol index 7c30ba55b..ad2303b0f 100644 --- a/test/core/integration/concrete/lockup-base/batch/batch.t.sol +++ b/test/core/integration/concrete/lockup-base/batch/batch.t.sol @@ -5,7 +5,7 @@ import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "./../../../Integration.t.sol"; -abstract contract Batch_Integration_Concrete_Test is Integration_Test { +contract Batch_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_CallFunctionNotExist() external { bytes[] memory calls = new bytes[](1); calls[0] = abi.encodeWithSignature("nonExistentFunction()"); diff --git a/test/core/integration/concrete/lockup-base/burn/burn.t.sol b/test/core/integration/concrete/lockup-base/burn/burn.t.sol index ab8ec3ef4..0a89841e5 100644 --- a/test/core/integration/concrete/lockup-base/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup-base/burn/burn.t.sol @@ -3,20 +3,17 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; + import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "./../../../Integration.t.sol"; -abstract contract Burn_Integration_Concrete_Test is Integration_Test { +contract Burn_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockupBase.burn, defaultStreamId); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ callData: abi.encodeCall(lockup.burn, defaultStreamId) }); } function test_RevertGiven_Null() external whenNoDelegateCall { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.burn(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.burn, nullStreamId) }); } function test_RevertGiven_PENDINGStatus() external whenNoDelegateCall givenNotNull givenNotDepletedStream { @@ -53,11 +50,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test { givenDepletedStream(lockup, defaultStreamId) whenCallerNotRecipient { - resetPrank({ msgSender: users.eve }); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) - ); - lockup.burn(defaultStreamId); + expectRevert_CallerMaliciousThirdParty({ callData: abi.encodeCall(lockup.burn, defaultStreamId) }); } function test_RevertWhen_CallerSender() diff --git a/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol index 6e6c0ec0b..6816f59e5 100644 --- a/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol @@ -9,18 +9,30 @@ import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract CancelMultiple_Integration_Concrete_Test is Integration_Test { - // The original time when the tests started. - uint40 internal originalTime; +contract CancelMultiple_Integration_Concrete_Test is Integration_Test { + // An array of stream IDs to be canceled. + uint256[] internal cancelMultipleStreamIds; function setUp() public virtual override { - originalTime = getBlockTimestamp(); + Integration_Test.setUp(); + + cancelMultipleStreamIds = warpAndCreateStreams(defaults.START_TIME()); + } + + /// @dev The following two functions are used in `CancelMultiple` tests. + function warpAndCreateStreams(uint40 warpTime) internal returns (uint256[2] memory streamIds) { + vm.warp({ newTimestamp: warpTime }); + + // Create the first stream. + streamIds[0] = createDefaultStream(); + + // Create the second stream with an end time double that of the default stream so that the refund amounts are + // different. + streamIds[1] = createDefaultStreamWithEndTimeLD(defaults.END_TIME() + defaults.TOTAL_DURATION()); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockupBase.cancelMultiple, (cancelMultipleStreamIds)); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ callData: abi.encodeCall(lockup.cancelMultiple, cancelMultipleStreamIds) }); } function test_WhenZeroArrayLength() external whenNoDelegateCall { @@ -30,8 +42,9 @@ abstract contract CancelMultiple_Integration_Concrete_Test is Integration_Test { } function test_RevertGiven_AtleastOneNullStream() external whenNoDelegateCall whenNonZeroArrayLength { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.cancelMultiple({ streamIds: Solarray.uint256s(cancelMultipleStreamIds[0], nullStreamId) }); + expectRevert_Null({ + callData: abi.encodeCall(lockup.cancelMultiple, Solarray.uint256s(cancelMultipleStreamIds[0], nullStreamId)) + }); } function test_RevertGiven_AtleastOneColdStream() @@ -40,7 +53,9 @@ abstract contract CancelMultiple_Integration_Concrete_Test is Integration_Test { whenNonZeroArrayLength givenNoNullStreams { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 1 seconds }); + uint40 earlyEndTime = defaults.END_TIME() - 10; + uint256 earlyEndtimeStreamId = createDefaultStreamWithEndTimeLD(earlyEndTime); + vm.warp({ newTimestamp: earlyEndTime + 1 seconds }); vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, earlyEndtimeStreamId)); lockup.cancelMultiple({ streamIds: Solarray.uint256s(cancelMultipleStreamIds[0], earlyEndtimeStreamId) }); } diff --git a/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol b/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol index c68aaa959..c24c08c90 100644 --- a/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol @@ -12,34 +12,23 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract Cancel_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockupBase.cancel, defaultStreamId); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertGiven_Null() external whenNoDelegateCall { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.cancel(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.cancel, nullStreamId) }); } function test_RevertGiven_DEPLETEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); - lockup.cancel(defaultStreamId); + expectRevert_DEPLETEDStatus({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertGiven_CANCELEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - lockup.cancel(defaultStreamId); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamCanceled.selector, defaultStreamId)); - lockup.cancel(defaultStreamId); + expectRevert_CANCELEDStatus({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertGiven_SETTLEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, defaultStreamId)); - lockup.cancel(defaultStreamId); + expectRevert_SETTLEDStatus({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertWhen_CallerMaliciousThirdParty() @@ -49,14 +38,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { givenWarmStream whenCallerNotSender { - // Make Eve the caller in this test. - resetPrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) - ); - lockup.cancel(defaultStreamId); + expectRevert_CallerMaliciousThirdParty({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertWhen_CallerRecipient() @@ -66,14 +48,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { givenWarmStream whenCallerNotSender { - // Make the Recipient the caller in this test. - resetPrank({ msgSender: users.recipient }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.recipient) - ); - lockup.cancel(defaultStreamId); + expectRevert_CallerRecipient({ callData: abi.encodeCall(lockup.cancel, defaultStreamId) }); } function test_RevertGiven_NonCancelableStream() diff --git a/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol new file mode 100644 index 000000000..cd30622cf --- /dev/null +++ b/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.t.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Address } from "@openzeppelin/contracts/utils/Address.sol"; +import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; +import { Integration_Test } from "./../../../Integration.t.sol"; + +abstract contract CreateWithTimestamps_Integration_Concrete_Test is Integration_Test { + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Helpers function to assert the common storaged values of a stream between all Lockup models. + function assertEqStream(uint256 streamId) internal view { + assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); + assertEq(lockup.getSender(streamId), users.sender, "sender"); + assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); + assertEq(lockup.getStartTime(streamId), defaults.START_TIME(), "startTime"); + assertEq(lockup.getEndTime(streamId), defaults.END_TIME(), "endTime"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isCancelable(streamId), "isCancelable"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); + + // Assert that the stream's status is "PENDING". + Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status expectedStatus = Lockup.Status.PENDING; + assertEq(actualStatus, expectedStatus); + + // It should bump the next stream ID. + uint256 actualNextStreamId = lockup.nextStreamId(); + uint256 expectedNextStreamId = streamId + 1; + assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); + + // It should mint the NFT. + address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); + address expectedNFTOwner = users.recipient; + assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); + } + + /*////////////////////////////////////////////////////////////////////////// + COMMON-TESTS + //////////////////////////////////////////////////////////////////////////*/ + + function test_RevertWhen_DelegateCall() external { + bytes memory callData; + + if (lockupModel == Lockup.Model.LOCKUP_DYNAMIC) { + callData = abi.encodeCall( + lockup.createWithTimestampsLD, (_defaultParams.createWithTimestamps, _defaultParams.segments) + ); + } else if (lockupModel == Lockup.Model.LOCKUP_LINEAR) { + callData = abi.encodeCall( + lockup.createWithTimestampsLL, (_defaultParams.createWithTimestamps, _defaultParams.cliffTime) + ); + } else if (lockupModel == Lockup.Model.LOCKUP_TRANCHED) { + callData = abi.encodeCall( + lockup.createWithTimestampsLT, (_defaultParams.createWithTimestamps, _defaultParams.tranches) + ); + } + + expectRevert_DelegateCall(callData); + } + + function test_RevertWhen_BrokerFeeExceedsMaxValue() external whenNoDelegateCall { + UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); + _defaultParams.createWithTimestamps.broker.fee = brokerFee; + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierHelpers_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) + ); + createDefaultStream(); + } + + function test_RevertWhen_SenderZeroAddress() external whenNoDelegateCall whenBrokerFeeNotExceedMaxValue { + _defaultParams.createWithTimestamps.sender = address(0); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_SenderZeroAddress.selector)); + createDefaultStream(); + } + + function test_RevertWhen_RecipientZeroAddress() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + { + _defaultParams.createWithTimestamps.recipient = address(0); + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, address(0))); + createDefaultStream(); + } + + function test_RevertWhen_DepositAmountZero() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + { + _defaultParams.createWithTimestamps.totalAmount = 0; + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_DepositAmountZero.selector)); + createDefaultStream(); + } + + function test_RevertWhen_StartTimeZero() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + { + _defaultParams.createWithTimestamps.timestamps.start = 0; + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_StartTimeZero.selector)); + createDefaultStream(); + } + + function test_RevertWhen_AssetNotContract() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + { + address nonContract = address(8128); + _defaultParams.createWithTimestamps.asset = IERC20(nonContract); + vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); + createDefaultStream(); + } +} diff --git a/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree new file mode 100644 index 000000000..ae7893ff9 --- /dev/null +++ b/test/core/integration/concrete/lockup-base/create-with-timestamps/createWithTimestamps.tree @@ -0,0 +1,21 @@ +CreateWithTimestamps_Integration_Concrete_Test +├── when delegate call +│ └── it should revert +└── when no delegate call + ├── when broker fee exceeds max value + │ └── it should revert + └── when broker fee not exceed max value + ├── when sender zero address + │ └── it should revert + └── when sender not zero address + ├── when recipient zero address + │ └── it should revert + └── when recipient not zero address + ├── when deposit amount zero + │ └── it should revert + └── when deposit amount not zero + ├── when start time zero + │ └── it should revert + └── when start time not zero + └── when asset not contract + └── it should revert \ No newline at end of file diff --git a/test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol b/test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol deleted file mode 100644 index 5c8a3dbc0..000000000 --- a/test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetAsset_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getAsset(nullStreamId); - } - - function test_GivenNotNull() external view { - IERC20 actualAsset = lockup.getAsset(defaultStreamId); - IERC20 expectedAsset = dai; - assertEq(actualAsset, expectedAsset, "asset"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-asset/getAsset.tree b/test/core/integration/concrete/lockup-base/get-asset/getAsset.tree deleted file mode 100644 index 0d4026568..000000000 --- a/test/core/integration/concrete/lockup-base/get-asset/getAsset.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetAsset_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct address of the asset diff --git a/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol b/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol deleted file mode 100644 index 54d3a320e..000000000 --- a/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetDepositedAmount_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getDepositedAmount(nullStreamId); - } - - function test_GivenNotNull() external view { - uint128 actualDepositedAmount = lockup.getDepositedAmount(defaultStreamId); - uint128 expectedDepositedAmount = defaults.DEPOSIT_AMOUNT(); - assertEq(actualDepositedAmount, expectedDepositedAmount, "depositedAmount"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.tree b/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.tree deleted file mode 100644 index 2d9162901..000000000 --- a/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetDepositedAmount_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct deposited amount diff --git a/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol b/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol deleted file mode 100644 index fd5df5b09..000000000 --- a/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetEndTime_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getEndTime(nullStreamId); - } - - function test_GivenNotNull() external view { - uint40 actualEndTime = lockup.getEndTime(defaultStreamId); - uint40 expectedEndTime = defaults.END_TIME(); - assertEq(actualEndTime, expectedEndTime, "endTime"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.tree b/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.tree deleted file mode 100644 index 064930723..000000000 --- a/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetEndTime_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct end time diff --git a/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol b/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol deleted file mode 100644 index f148c0171..000000000 --- a/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); - lockup.getRecipient(nullStreamId); - } - - function test_RevertGiven_BurnedNFT() external givenNotNull { - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.END_TIME() }); - - // Make the Recipient the caller. - resetPrank({ msgSender: users.recipient }); - - // Deplete the stream. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - - // Burn the NFT. - lockup.burn(defaultStreamId); - - // Expect the relevant error when retrieving the recipient. - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, defaultStreamId)); - lockup.getRecipient(defaultStreamId); - } - - function test_GivenNotBurnedNFT() external view givenNotNull { - address actualRecipient = lockup.getRecipient(defaultStreamId); - address expectedRecipient = users.recipient; - assertEq(actualRecipient, expectedRecipient, "recipient"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.tree b/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.tree deleted file mode 100644 index c2e2804b4..000000000 --- a/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.tree +++ /dev/null @@ -1,8 +0,0 @@ -GetRecipient_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given burned NFT - │ └── it should revert - └── given not burned NFT - └── it should return the correct recipient diff --git a/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol deleted file mode 100644 index 75b65781b..000000000 --- a/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol +++ /dev/null @@ -1,67 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getRefundedAmount(nullStreamId); - } - - function test_GivenCanceledStreamAndCANCELEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - // Cancel the stream. - lockup.cancel(defaultStreamId); - - // It should return the correct refunded amount. - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } - - function test_GivenCanceledStreamAndDEPLETEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - // Cancel the stream. - lockup.cancel(defaultStreamId); - - // Withdraw the maximum amount to deplete the stream. - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - - // It should return the correct refunded amount. - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } - - function test_GivenPENDINGStatus() external givenNotNull givenNotCanceledStream { - vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = 0; - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } - - function test_GivenSETTLEDStatus() external givenNotNull givenNotCanceledStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = 0; - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } - - function test_GivenDEPLETEDStatus() external givenNotNull givenNotCanceledStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = 0; - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } - - function test_GivenSTREAMINGStatus() external givenNotNull givenNotCanceledStream { - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); - uint128 expectedRefundedAmount = 0; - assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.tree b/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.tree deleted file mode 100644 index dd927bb90..000000000 --- a/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.tree +++ /dev/null @@ -1,17 +0,0 @@ -GetRefundedAmount_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given canceled stream and CANCELED status - │ └── it should return the correct refunded amount - ├── given canceled stream and DEPLETED status - │ └── it should return the correct refunded amount - └── given not canceled stream - ├── given PENDING status - │ └── it should return zero - ├── given SETTLED status - │ └── it should return zero - ├── given DEPLETED status - │ └── it should return zero - └── given STREAMING status - └── it should return zero diff --git a/test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol b/test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol deleted file mode 100644 index 3cb3abd80..000000000 --- a/test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetSender_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getSender(nullStreamId); - } - - function test_GivenNotNull() external view { - address actualSender = lockup.getSender(defaultStreamId); - address expectedSender = users.sender; - assertEq(actualSender, expectedSender, "sender"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-sender/getSender.tree b/test/core/integration/concrete/lockup-base/get-sender/getSender.tree deleted file mode 100644 index 589071e5b..000000000 --- a/test/core/integration/concrete/lockup-base/get-sender/getSender.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetSender_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct sender diff --git a/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol b/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol deleted file mode 100644 index 5d5d0d1aa..000000000 --- a/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetStartTime_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getStartTime(nullStreamId); - } - - function test_GivenNotNull() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getStartTime(nullStreamId); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.tree b/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.tree deleted file mode 100644 index 72d41d743..000000000 --- a/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetStartTime_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct start time diff --git a/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol deleted file mode 100644 index 4bf94239b..000000000 --- a/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract GetWithdrawnAmount_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getWithdrawnAmount(nullStreamId); - } - - function test_GivenNoPreviousWithdrawals() external givenNotNull { - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - - // It should return zero. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = 0; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); - } - - function test_GivenPreviousWithdrawal() external givenNotNull { - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - - // Set the withdraw amount to the streamed amount. - uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); - - // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); - - // It should return the correct withdrawn amount. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = withdrawAmount; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); - } -} diff --git a/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.tree b/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.tree deleted file mode 100644 index 226557886..000000000 --- a/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.tree +++ /dev/null @@ -1,8 +0,0 @@ -GetWithdrawnAmount_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given no previous withdrawals - │ └── it should return zero - └── given previous withdrawal - └── it should return the correct withdrawn amount diff --git a/test/core/integration/concrete/lockup-base/getters/getters.t.sol b/test/core/integration/concrete/lockup-base/getters/getters.t.sol new file mode 100644 index 000000000..d276ad73a --- /dev/null +++ b/test/core/integration/concrete/lockup-base/getters/getters.t.sol @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { Integration_Test } from "./../../../Integration.t.sol"; + +contract Getters_Integration_Concrete_Test is Integration_Test { + /*////////////////////////////////////////////////////////////////////////// + GET-ASSET + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetAssetRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getAsset, nullStreamId) }); + } + + function test_GetAssetGivenNotNull() external view { + IERC20 actualAsset = lockup.getAsset(defaultStreamId); + IERC20 expectedAsset = dai; + assertEq(actualAsset, expectedAsset, "asset"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-DEPOSITED-AMOUNT + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetDepositedAmountRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getDepositedAmount, nullStreamId) }); + } + + function test_GetDepositedAmountGivenNotNull() external view { + uint128 actualDepositedAmount = lockup.getDepositedAmount(defaultStreamId); + uint128 expectedDepositedAmount = defaults.DEPOSIT_AMOUNT(); + assertEq(actualDepositedAmount, expectedDepositedAmount, "depositedAmount"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-END-TIME + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetEndTimeRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getEndTime, nullStreamId) }); + } + + function test_GetEndTimeGivenNotNull() external view { + uint40 actualEndTime = lockup.getEndTime(defaultStreamId); + uint40 expectedEndTime = defaults.END_TIME(); + assertEq(actualEndTime, expectedEndTime, "endTime"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-RECIPIENT + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetRecipientRevertGiven_Null() external { + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); + lockup.getRecipient(nullStreamId); + } + + function test_GetRecipientRevertGiven_BurnedNFT() external givenNotNull { + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.END_TIME() }); + + // Make the Recipient the caller. + resetPrank({ msgSender: users.recipient }); + + // Deplete the stream. + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + + // Burn the NFT. + lockup.burn(defaultStreamId); + + // Expect the relevant error when retrieving the recipient. + vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, defaultStreamId)); + lockup.getRecipient(defaultStreamId); + } + + function test_GetRecipientGivenNotBurnedNFT() external view givenNotNull { + address actualRecipient = lockup.getRecipient(defaultStreamId); + address expectedRecipient = users.recipient; + assertEq(actualRecipient, expectedRecipient, "recipient"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-REFUNDED-AMOUNT + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetRefundedAmountRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getRefundedAmount, nullStreamId) }); + } + + function test_GetRefundedAmountGivenCanceledStreamAndCANCELEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + // Cancel the stream. + lockup.cancel(defaultStreamId); + + // It should return the correct refunded amount. + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + function test_GetRefundedAmountGivenCanceledStreamAndDEPLETEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + // Cancel the stream. + lockup.cancel(defaultStreamId); + + // Withdraw the maximum amount to deplete the stream. + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + + // It should return the correct refunded amount. + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = defaults.REFUND_AMOUNT(); + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + function test_GetRefundedAmountGivenPENDINGStatus() external givenNotNull givenNotCanceledStream { + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = 0; + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + function test_GetRefundedAmountGivenSETTLEDStatus() external givenNotNull givenNotCanceledStream { + vm.warp({ newTimestamp: defaults.END_TIME() }); + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = 0; + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + function test_GetRefundedAmountGivenDEPLETEDStatus() external givenNotNull givenNotCanceledStream { + vm.warp({ newTimestamp: defaults.END_TIME() }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = 0; + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + function test_GetRefundedAmountGivenSTREAMINGStatus() external givenNotNull givenNotCanceledStream { + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + uint128 actualRefundedAmount = lockup.getRefundedAmount(defaultStreamId); + uint128 expectedRefundedAmount = 0; + assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-SENDER + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetSenderRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getSender, nullStreamId) }); + } + + function test_GetSenderGivenNotNull() external view { + address actualSender = lockup.getSender(defaultStreamId); + address expectedSender = users.sender; + assertEq(actualSender, expectedSender, "sender"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-START-TIME + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetStartTimeRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getStartTime, nullStreamId) }); + } + + function test_GetStartTimeGivenNotNull() external view { + uint40 actualStartTime = lockup.getStartTime(defaultStreamId); + uint40 expectedStartTime = defaults.START_TIME(); + assertEq(actualStartTime, expectedStartTime, "startTime"); + } + + /*////////////////////////////////////////////////////////////////////////// + GET-WITHDRAWN-AMOUNT + //////////////////////////////////////////////////////////////////////////*/ + + function test_GetWithdrawnAmountRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.getWithdrawnAmount, nullStreamId) }); + } + + function test_GetWithdrawnAmountGivenNoPreviousWithdrawals() external givenNotNull { + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // It should return zero. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); + uint128 expectedWithdrawnAmount = 0; + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + } + + function test_GetWithdrawnAmountGivenPreviousWithdrawal() external givenNotNull { + // Simulate the passage of time. + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + + // Set the withdraw amount to the streamed amount. + uint128 withdrawAmount = lockup.streamedAmountOf(defaultStreamId); + + // Make the withdrawal. + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + + // It should return the correct withdrawn amount. + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); + uint128 expectedWithdrawnAmount = withdrawAmount; + assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-ALLOWED-TO-HOOK + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsAllowedToHookGivenProvidedAddressNotAllowedToHook() external view { + bool result = lockup.isAllowedToHook(address(recipientGood)); + assertFalse(result, "isAllowedToHook"); + } + + function test_IsAllowedToHookGivenProvidedAddressAllowedToHook() external { + resetPrank({ msgSender: users.admin }); + lockup.allowToHook(address(recipientGood)); + + bool result = lockup.isAllowedToHook(address(recipientGood)); + assertTrue(result, "isAllowedToHook"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-CANCELABLE + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsCancelableRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.isCancelable, nullStreamId) }); + } + + function test_IsCancelableGivenColdStream() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); // settled status + assertFalse(lockup.isCancelable(defaultStreamId), "isCancelable"); + } + + function test_IsCancelableGivenCancelableStream() external view givenNotNull givenWarmStream { + assertTrue(lockup.isCancelable(defaultStreamId), "isCancelable"); + } + + function test_IsCancelableGivenNonCancelableStream() external view givenNotNull givenWarmStream { + assertFalse(lockup.isCancelable(notCancelableStreamId), "isCancelable"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-COLD + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsColdRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.isCold, nullStreamId) }); + } + + function test_IsColdGivenPENDINGStatus() external givenNotNull { + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); + assertFalse(lockup.isCold(defaultStreamId), "isCold"); + } + + function test_IsColdGivenSTREAMINGStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + assertFalse(lockup.isCold(defaultStreamId), "isCold"); + } + + function test_IsColdGivenSETTLEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); + assertTrue(lockup.isCold(defaultStreamId), "isCold"); + } + + function test_IsColdGivenCANCELEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + lockup.cancel(defaultStreamId); + assertTrue(lockup.isCold(defaultStreamId), "isCold"); + } + + function test_IsColdGivenDEPLETEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + assertTrue(lockup.isCold(defaultStreamId), "isCold"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-DEPLETED + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsDepletedRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.isDepleted, nullStreamId) }); + } + + function test_IsDepletedGivenNotDepletedStream() external view givenNotNull { + assertFalse(lockup.isDepleted(defaultStreamId), "isDepleted"); + } + + function test_IsDepletedGivenDepletedStream() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + assertTrue(lockup.isDepleted(defaultStreamId), "isDepleted"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-STREAM + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsStreamGivenNull() external view { + assertFalse(lockup.isStream(nullStreamId), "isStream"); + } + + function test_IsStreamGivenNotNull() external view { + assertTrue(lockup.isStream(defaultStreamId), "isStream"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-TRANSFERABLE + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsTransferableRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.isTransferable, nullStreamId) }); + } + + function test_IsTransferableGivenNonTransferableStream() external view givenNotNull { + assertFalse(lockup.isTransferable(notTransferableStreamId), "isTransferable"); + } + + function test_IsTransferableGivenTransferableStream() external view givenNotNull { + assertTrue(lockup.isTransferable(defaultStreamId), "isTransferable"); + } + + /*////////////////////////////////////////////////////////////////////////// + IS-WARM + //////////////////////////////////////////////////////////////////////////*/ + + function test_IsWarmRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.isWarm, nullStreamId) }); + } + + function test_IsWarmGivenPENDINGStatus() external givenNotNull { + vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); + assertTrue(lockup.isWarm(defaultStreamId), "isWarm"); + } + + function test_IsWarmGivenSTREAMINGStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); + assertTrue(lockup.isWarm(defaultStreamId), "isWarm"); + } + + function test_IsWarmGivenSETTLEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); + assertFalse(lockup.isWarm(defaultStreamId), "isWarm"); + } + + function test_IsWarmGivenCANCELEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); + lockup.cancel(defaultStreamId); + assertFalse(lockup.isWarm(defaultStreamId), "isWarm"); + } + + function test_IsWarmGivenDEPLETEDStatus() external givenNotNull { + vm.warp({ newTimestamp: defaults.END_TIME() }); + lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); + assertFalse(lockup.isWarm(defaultStreamId), "isWarm"); + } + + /*////////////////////////////////////////////////////////////////////////// + WAS-CANCELED + //////////////////////////////////////////////////////////////////////////*/ + + function test_WasCanceledRevertGiven_Null() external { + expectRevert_Null({ callData: abi.encodeCall(lockup.wasCanceled, nullStreamId) }); + } + + function test_WasCanceledGivenCanceledStream() external view givenNotNull { + assertFalse(lockup.wasCanceled(defaultStreamId), "wasCanceled"); + } + + function test_WasCanceledGivenNotCanceledStream() external givenNotNull { + lockup.cancel(defaultStreamId); + assertTrue(lockup.wasCanceled(defaultStreamId), "wasCanceled"); + } +} diff --git a/test/core/integration/concrete/lockup-base/getters/getters.tree b/test/core/integration/concrete/lockup-base/getters/getters.tree new file mode 100644 index 000000000..38e902c9b --- /dev/null +++ b/test/core/integration/concrete/lockup-base/getters/getters.tree @@ -0,0 +1,148 @@ +Getters_Integration_Concrete_Test::getAsset +├── given null +│ └── it should revert +└── given not null + └── it should return the correct address of the asset + +Getters_Integration_Concrete_Test::getDepositedAmount +├── given null +│ └── it should revert +└── given not null + └── it should return the correct deposited amount + +Getters_Integration_Concrete_Test::getEndTime +├── given null +│ └── it should revert +└── given not null + └── it should return the correct end time + +Getters_Integration_Concrete_Test::getRecipient +├── given null +│ └── it should revert +└── given not null + ├── given burned NFT + │ └── it should revert + └── given not burned NFT + └── it should return the correct recipient + +Getters_Integration_Concrete_Test::getRefundedAmount +├── given null +│ └── it should revert +└── given not null + ├── given canceled stream and CANCELED status + │ └── it should return the correct refunded amount + ├── given canceled stream and DEPLETED status + │ └── it should return the correct refunded amount + └── given not canceled stream + ├── given PENDING status + │ └── it should return zero + ├── given SETTLED status + │ └── it should return zero + ├── given DEPLETED status + │ └── it should return zero + └── given STREAMING status + └── it should return zero + +Getters_Integration_Concrete_Test::getSender +├── given null +│ └── it should revert +└── given not null + └── it should return the correct sender + +Getters_Integration_Concrete_Test::getStartTime +├── given null +│ └── it should revert +└── given not null + └── it should return the correct start time + +Getters_Integration_Concrete_Test::getWithdrawnAmount +├── given null +│ └── it should revert +└── given not null + ├── given no previous withdrawals + │ └── it should return zero + └── given previous withdrawal + └── it should return the correct withdrawn amount + + +Getters_Integration_Concrete_Test::isAllowedToHook +├── given provided address not allowed to hook +│ └── it should return false +└── given provided address allowed to hook + └── it should return true + +Getters_Integration_Concrete_Test::isCancelable +├── given null +│ └── it should revert +└── given not null + ├── given cold stream + │ └── it should return true + └── given warm stream + ├── given cancelable stream + │ └── it should return true + └── given non cancelable stream + └── it should return false + +Getters_Integration_Concrete_Test::isCold +├── given null +│ └── it should revert +└── given not null + ├── given PENDING status + │ └── it should return false + ├── given STREAMING status + │ └── it should return false + ├── given SETTLED status + │ └── it should return true + ├── given CANCELED status + │ └── it should return true + └── given DEPLETED status + └── it should return true + + +Getters_Integration_Concrete_Test::isDepleted +├── given null +│ └── it should revert +└── given not null + ├── given not depleted stream + │ └── it should return false + └── given depleted stream + └── it should return true + +Getters_Integration_Concrete_Test::isStream +├── given null +│ └── it should return false +└── given not null + └── it should return true + +Getters_Integration_Concrete_Test::isTransferable +├── given null +│ └── it should revert +└── given not null + ├── given non transferable stream + │ └── it should return false + └── given transferable stream + └── it should return true + +Getters_Integration_Concrete_Test::isWarm +├── given null +│ └── it should revert +└── given not null + ├── given PENDING status + │ └── it should return true + ├── given STREAMING status + │ └── it should return true + ├── given SETTLED status + │ └── it should return false + ├── given CANCELED status + │ └── it should return false + └── given DEPLETED status + └── it should return false + +Getters_Integration_Concrete_Test::wasCanceled +├── given null +│ └── it should revert +└── given not null + ├── given canceled stream + │ └── it should return false + └── given not canceled stream + └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol b/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol deleted file mode 100644 index 286c60a0a..000000000 --- a/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsAllowedToHook_Integration_Concrete_Test is Integration_Test { - function test_GivenProvidedAddressNotAllowedToHook() external view { - bool result = lockup.isAllowedToHook(address(recipientGood)); - assertFalse(result, "isAllowedToHook"); - } - - function test_GivenProvidedAddressAllowedToHook() external { - resetPrank({ msgSender: users.admin }); - lockup.allowToHook(address(recipientGood)); - - bool result = lockup.isAllowedToHook(address(recipientGood)); - assertTrue(result, "isAllowedToHook"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.tree b/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.tree deleted file mode 100644 index 5c7c87bb6..000000000 --- a/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.tree +++ /dev/null @@ -1,5 +0,0 @@ -IsAllowedToHook_Integration_Concrete_Test -├── given provided address not allowed to hook -│ └── it should return false -└── given provided address allowed to hook - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol b/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol deleted file mode 100644 index f2e9e3635..000000000 --- a/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsCancelable_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.isCancelable(nullStreamId); - } - - function test_GivenColdStream() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); // settled status - bool isCancelable = lockup.isCancelable(defaultStreamId); - assertFalse(isCancelable, "isCancelable"); - } - - function test_GivenCancelableStream() external view givenNotNull givenWarmStream { - bool isCancelable = lockup.isCancelable(defaultStreamId); - assertTrue(isCancelable, "isCancelable"); - } - - function test_GivenNonCancelableStream() external view givenNotNull givenWarmStream { - bool isCancelable = lockup.isCancelable(notCancelableStreamId); - assertFalse(isCancelable, "isCancelable"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.tree b/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.tree deleted file mode 100644 index 179374494..000000000 --- a/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.tree +++ /dev/null @@ -1,11 +0,0 @@ -IsCancelable_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given cold stream - │ └── it should return true - └── given warm stream - ├── given cancelable stream - │ └── it should return true - └── given non cancelable stream - └── it should return false diff --git a/test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol deleted file mode 100644 index 54795e743..000000000 --- a/test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsCold_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.isCold(nullStreamId); - } - - function test_GivenPENDINGStatus() external givenNotNull { - vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); - bool isCold = lockup.isCold(defaultStreamId); - assertFalse(isCold, "isCold"); - } - - function test_GivenSTREAMINGStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - bool isCold = lockup.isCold(defaultStreamId); - assertFalse(isCold, "isCold"); - } - - function test_GivenSETTLEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - bool isCold = lockup.isCold(defaultStreamId); - assertTrue(isCold, "isCold"); - } - - function test_GivenCANCELEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - lockup.cancel(defaultStreamId); - bool isCold = lockup.isCold(defaultStreamId); - assertTrue(isCold, "isCold"); - } - - function test_GivenDEPLETEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - bool isCold = lockup.isCold(defaultStreamId); - assertTrue(isCold, "isCold"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-cold/isCold.tree b/test/core/integration/concrete/lockup-base/is-cold/isCold.tree deleted file mode 100644 index 61d1be5db..000000000 --- a/test/core/integration/concrete/lockup-base/is-cold/isCold.tree +++ /dev/null @@ -1,14 +0,0 @@ -IsCold_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given PENDING status - │ └── it should return false - ├── given STREAMING status - │ └── it should return false - ├── given SETTLED status - │ └── it should return true - ├── given CANCELED status - │ └── it should return true - └── given DEPLETED status - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol deleted file mode 100644 index 2d4e92115..000000000 --- a/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.isDepleted(nullStreamId); - } - - function test_GivenNotDepletedStream() external view givenNotNull { - bool isDepleted = lockup.isDepleted(defaultStreamId); - assertFalse(isDepleted, "isDepleted"); - } - - function test_GivenDepletedStream() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - bool isDepleted = lockup.isDepleted(defaultStreamId); - assertTrue(isDepleted, "isDepleted"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.tree b/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.tree deleted file mode 100644 index 579153174..000000000 --- a/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.tree +++ /dev/null @@ -1,8 +0,0 @@ -IsDepleted_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given not depleted stream - │ └── it should return false - └── given depleted stream - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol b/test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol deleted file mode 100644 index 76e129c59..000000000 --- a/test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsStream_Integration_Concrete_Test is Integration_Test { - function test_GivenNull() external view { - bool isStream = lockup.isStream(nullStreamId); - assertFalse(isStream, "isStream"); - } - - function test_GivenNotNull() external view { - bool isStream = lockup.isStream(defaultStreamId); - assertTrue(isStream, "isStream"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-stream/isStream.tree b/test/core/integration/concrete/lockup-base/is-stream/isStream.tree deleted file mode 100644 index 1758774dd..000000000 --- a/test/core/integration/concrete/lockup-base/is-stream/isStream.tree +++ /dev/null @@ -1,5 +0,0 @@ -IsStream_Integration_Concrete_Test -├── given null -│ └── it should return false -└── given not null - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol b/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol deleted file mode 100644 index 02a74019d..000000000 --- a/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsTransferable_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.isTransferable(nullStreamId); - } - - function test_GivenNonTransferableStream() external view givenNotNull { - bool isTransferable = lockup.isTransferable(notTransferableStreamId); - assertFalse(isTransferable, "isTransferable"); - } - - function test_GivenTransferableStream() external view givenNotNull { - bool isTransferable = lockup.isTransferable(defaultStreamId); - assertTrue(isTransferable, "isTransferable"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.tree b/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.tree deleted file mode 100644 index 562cd1982..000000000 --- a/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.tree +++ /dev/null @@ -1,8 +0,0 @@ -IsTransferable_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given non transferable stream - │ └── it should return false - └── given transferable stream - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol deleted file mode 100644 index e88dc484d..000000000 --- a/test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract IsWarm_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.isWarm(nullStreamId); - } - - function test_GivenPENDINGStatus() external givenNotNull { - vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); - bool isWarm = lockup.isWarm(defaultStreamId); - assertTrue(isWarm, "isWarm"); - } - - function test_GivenSTREAMINGStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - bool isWarm = lockup.isWarm(defaultStreamId); - assertTrue(isWarm, "isWarm"); - } - - function test_GivenSETTLEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - bool isWarm = lockup.isWarm(defaultStreamId); - assertFalse(isWarm, "isWarm"); - } - - function test_GivenCANCELEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - lockup.cancel(defaultStreamId); - bool isWarm = lockup.isWarm(defaultStreamId); - assertFalse(isWarm, "isWarm"); - } - - function test_GivenDEPLETEDStatus() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - bool isWarm = lockup.isWarm(defaultStreamId); - assertFalse(isWarm, "isWarm"); - } -} diff --git a/test/core/integration/concrete/lockup-base/is-warm/isWarm.tree b/test/core/integration/concrete/lockup-base/is-warm/isWarm.tree deleted file mode 100644 index ec6819022..000000000 --- a/test/core/integration/concrete/lockup-base/is-warm/isWarm.tree +++ /dev/null @@ -1,14 +0,0 @@ -IsWarm_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given PENDING status - │ └── it should return true - ├── given STREAMING status - │ └── it should return true - ├── given SETTLED status - │ └── it should return false - ├── given CANCELED status - │ └── it should return false - └── given DEPLETED status - └── it should return false diff --git a/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol index 46a01d520..9fa46c6e4 100644 --- a/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol @@ -1,14 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/core/libraries/Errors.sol"; - import { Integration_Test } from "../../../Integration.t.sol"; abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.refundableAmountOf(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.refundableAmountOf, nullStreamId) }); } function test_GivenNonCancelableStream() external givenNotNull { diff --git a/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol b/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol index a453a52d9..d94e5143b 100644 --- a/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol @@ -12,34 +12,23 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { uint256 internal streamId; function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockupBase.renounce, defaultStreamId); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ callData: abi.encodeCall(lockup.renounce, defaultStreamId) }); } function test_RevertGiven_Null() external whenNoDelegateCall { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.renounce(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.renounce, nullStreamId) }); } function test_RevertGiven_DEPLETEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); - lockup.renounce(defaultStreamId); + expectRevert_DEPLETEDStatus({ callData: abi.encodeCall(lockup.renounce, defaultStreamId) }); } function test_RevertGiven_CANCELEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - lockup.cancel(defaultStreamId); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamCanceled.selector, defaultStreamId)); - lockup.renounce(defaultStreamId); + expectRevert_CANCELEDStatus({ callData: abi.encodeCall(lockup.renounce, defaultStreamId) }); } function test_RevertGiven_SETTLEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { - vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, defaultStreamId)); - lockup.renounce(defaultStreamId); + expectRevert_SETTLEDStatus({ callData: abi.encodeCall(lockup.renounce, defaultStreamId) }); } modifier givenWarmStreamRenounce() { @@ -53,14 +42,7 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { } function test_RevertWhen_CallerNotSender() external whenNoDelegateCall givenNotNull givenWarmStreamRenounce { - // Make Eve the caller in this test. - resetPrank({ msgSender: users.eve }); - - // Run the test. - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) - ); - lockup.renounce(defaultStreamId); + expectRevert_CallerMaliciousThirdParty({ callData: abi.encodeCall(lockup.renounce, defaultStreamId) }); } function test_RevertGiven_NonCancelableStream() @@ -94,7 +76,6 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { lockup.renounce(streamId); // It should make stream non cancelable. - bool isCancelable = lockup.isCancelable(streamId); - assertFalse(isCancelable, "isCancelable"); + assertFalse(lockup.isCancelable(streamId), "isCancelable"); } } diff --git a/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol b/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol index 6d536317d..d0c048827 100644 --- a/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol @@ -8,7 +8,7 @@ import { Errors } from "src/core/libraries/Errors.sol"; import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; import { Integration_Test } from "./../../../Integration.t.sol"; -abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test { +contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_CallerNotAdmin() external { // Make Eve the caller in this test. resetPrank({ msgSender: users.eve }); diff --git a/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol index d1dde1c52..db35185eb 100644 --- a/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol @@ -1,15 +1,13 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract StatusOf_Integration_Concrete_Test is Integration_Test { +contract StatusOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.statusOf(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.statusOf, nullStreamId) }); } function test_GivenAssetsFullyWithdrawn() external givenNotNull { diff --git a/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol index b1d05adcf..a7a9db30b 100644 --- a/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol @@ -1,14 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/core/libraries/Errors.sol"; - import { Integration_Test } from "../../../Integration.t.sol"; abstract contract StreamedAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.streamedAmountOf(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.streamedAmountOf, nullStreamId) }); } function test_GivenCanceledStreamAndCANCELEDStatus() external givenNotNull { diff --git a/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol index c1274144a..a2f0e7558 100644 --- a/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol @@ -8,8 +8,10 @@ import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test { +contract TransferFrom_Integration_Concrete_Test is Integration_Test { function setUp() public virtual override { + Integration_Test.setUp(); + // Set recipient as caller for this test. resetPrank({ msgSender: users.recipient }); } diff --git a/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol b/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol deleted file mode 100644 index 03bd3a094..000000000 --- a/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; - -import { Integration_Test } from "../../../Integration.t.sol"; - -abstract contract WasCanceled_Integration_Concrete_Test is Integration_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.wasCanceled(nullStreamId); - } - - function test_GivenCanceledStream() external view givenNotNull { - bool wasCanceled = lockup.wasCanceled(defaultStreamId); - assertFalse(wasCanceled, "wasCanceled"); - } - - function test_GivenNotCanceledStream() external givenNotNull { - lockup.cancel(defaultStreamId); - bool wasCanceled = lockup.wasCanceled(defaultStreamId); - assertTrue(wasCanceled, "wasCanceled"); - } -} diff --git a/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.tree b/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.tree deleted file mode 100644 index a6df6e659..000000000 --- a/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.tree +++ /dev/null @@ -1,8 +0,0 @@ -WasCanceled_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given canceled stream - │ └── it should return false - └── given not canceled stream - └── it should return true diff --git a/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol b/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol index 061552860..7eadeb365 100644 --- a/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol @@ -5,10 +5,12 @@ import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecip import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { +contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { uint128 internal withdrawAmount; function setUp() public virtual override { + Integration_Test.setUp(); + withdrawAmount = defaults.WITHDRAW_AMOUNT(); // Allow the good recipient to hook. @@ -18,6 +20,8 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { } function test_GivenRecipientSameAsSender() external { + uint256 identicalSenderRecipientStreamId = createDefaultStreamWithUsers(users.sender, users.sender); + // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -48,23 +52,19 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (differentSenderRecipientStreamId, unknownCaller, address(recipientGood), withdrawAmount) + (differentRecipientStreamId, unknownCaller, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ - streamId: differentSenderRecipientStreamId, - to: address(recipientGood), - amount: withdrawAmount - }); + lockup.withdraw({ streamId: differentRecipientStreamId, to: address(recipientGood), amount: withdrawAmount }); } function test_WhenCallerApprovedThirdParty() external givenRecipientNotSameAsSender { // Approve the operator to handle the stream. resetPrank({ msgSender: address(recipientGood) }); - lockup.approve({ to: users.operator, tokenId: differentSenderRecipientStreamId }); + lockup.approve({ to: users.operator, tokenId: differentRecipientStreamId }); // Make the operator the caller in this test. resetPrank({ msgSender: users.operator }); @@ -77,17 +77,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (differentSenderRecipientStreamId, users.operator, address(recipientGood), withdrawAmount) + (differentRecipientStreamId, users.operator, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ - streamId: differentSenderRecipientStreamId, - to: address(recipientGood), - amount: withdrawAmount - }); + lockup.withdraw({ streamId: differentRecipientStreamId, to: address(recipientGood), amount: withdrawAmount }); } function test_WhenCallerSender() external givenRecipientNotSameAsSender { @@ -102,17 +98,13 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (differentSenderRecipientStreamId, users.sender, address(recipientGood), withdrawAmount) + (differentRecipientStreamId, users.sender, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ - streamId: differentSenderRecipientStreamId, - to: address(recipientGood), - amount: withdrawAmount - }); + lockup.withdraw({ streamId: differentRecipientStreamId, to: address(recipientGood), amount: withdrawAmount }); } function test_WhenCallerRecipient() external givenRecipientNotSameAsSender { @@ -127,16 +119,12 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (differentSenderRecipientStreamId, address(recipientGood), address(recipientGood), withdrawAmount) + (differentRecipientStreamId, address(recipientGood), address(recipientGood), withdrawAmount) ), count: 0 }); // Make the withdrawal. - lockup.withdraw({ - streamId: differentSenderRecipientStreamId, - to: address(recipientGood), - amount: withdrawAmount - }); + lockup.withdraw({ streamId: differentRecipientStreamId, to: address(recipientGood), amount: withdrawAmount }); } } diff --git a/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index ba2a5bd27..fe3e1c0ac 100644 --- a/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -9,17 +9,15 @@ import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "./../../../Integration.t.sol"; -abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test { +contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupBase.withdrawMaxAndTransfer, (defaultStreamId, users.alice)); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall(lockup.withdrawMaxAndTransfer, (defaultStreamId, users.alice)) + }); } function test_RevertGiven_Null() external whenNoDelegateCall { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient }); + expectRevert_Null({ callData: abi.encodeCall(lockup.withdrawMaxAndTransfer, (nullStreamId, users.alice)) }); } function test_RevertGiven_NonTransferableStream() external whenCallerRecipient whenNoDelegateCall givenNotNull { diff --git a/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol b/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol index 1d010c91f..d34366a84 100644 --- a/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol @@ -6,7 +6,7 @@ import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test { +contract WithdrawMax_Integration_Concrete_Test is Integration_Test { function test_GivenEndTimeNotInFuture() external { // Warp to the stream's end. vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds }); diff --git a/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol index 8b8391228..9d5dfdfb3 100644 --- a/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol @@ -8,21 +8,46 @@ import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; -abstract contract WithdrawMultiple_Integration_Concrete_Test is Integration_Test { +contract WithdrawMultiple_Integration_Concrete_Test is Integration_Test { address internal caller; // The original time when the tests started. uint40 internal originalTime; + // An array of amounts to be used in `withdrawMultiple` tests. + uint128[] internal withdrawAmounts; + + // An array of stream IDs to be withdrawn from. + uint256[] internal withdrawMultipleStreamIds; + function setUp() public virtual override { + Integration_Test.setUp(); + originalTime = getBlockTimestamp(); + + withdrawMultipleStreamIds = warpAndCreateStreams(defaults.START_TIME()); + + withdrawAmounts.push(defaults.WITHDRAW_AMOUNT()); + withdrawAmounts.push(defaults.DEPOSIT_AMOUNT()); + withdrawAmounts.push(defaults.WITHDRAW_AMOUNT() / 2); + } + + function warpAndCreateStreams(uint40 warpTime) internal returns (uint256[3] memory streamIds) { + vm.warp({ newTimestamp: warpTime }); + + // Create three test streams: + // 1. A default stream + // 2. A stream with an early end time + // 3. A stream meant to be canceled before the withdrawal is made + streamIds[0] = createDefaultStream(); + streamIds[1] = createDefaultStreamWithEndTimeLD(defaults.WARP_26_PERCENT()); + streamIds[2] = createDefaultStream(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupBase.withdrawMultiple, (withdrawMultipleStreamIds, withdrawAmounts)); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall(lockup.withdrawMultiple, (withdrawMultipleStreamIds, withdrawAmounts)) + }); } function test_RevertWhen_UnequalArraysLength() external whenNoDelegateCall { @@ -134,6 +159,23 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is Integration_Test lockup.withdrawMultiple({ streamIds: withdrawMultipleStreamIds, amounts: amounts }); } + /// @dev This modifier runs the test in three different modes: + /// - Stream's sender as caller + /// - Stream's recipient as caller + /// - Approved NFT operator as caller + modifier whenCallerAuthorizedForAllStreams() override { + caller = users.sender; + _; + + withdrawMultipleStreamIds = warpAndCreateStreams({ warpTime: originalTime }); + caller = users.recipient; + _; + + withdrawMultipleStreamIds = warpAndCreateStreams({ warpTime: originalTime }); + caller = users.operator; + _; + } + function test_WhenNoAmountsOverdraw() external whenNoDelegateCall diff --git a/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol index e6ed09f11..36e2dae7b 100644 --- a/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol @@ -15,25 +15,20 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - bytes memory callData = - abi.encodeCall(ISablierLockupBase.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall(lockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)) + }); } function test_RevertGiven_Null() external whenNoDelegateCall { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.withdraw({ streamId: nullStreamId, to: users.recipient, amount: withdrawAmount }); + expectRevert_Null({ callData: abi.encodeCall(lockup.withdraw, (nullStreamId, users.recipient, withdrawAmount)) }); } function test_RevertGiven_DEPLETEDStatus() external whenNoDelegateCall givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); - - uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); + expectRevert_DEPLETEDStatus({ + callData: abi.encodeCall(lockup.withdraw, (defaultStreamId, users.recipient, defaults.WITHDRAW_AMOUNT())) + }); } function test_RevertWhen_WithdrawalAddressZero() external whenNoDelegateCall givenNotNull givenNotDEPLETEDStatus { diff --git a/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol index e8ed734f0..c15deace5 100644 --- a/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -1,14 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Errors } from "src/core/libraries/Errors.sol"; - import { Integration_Test } from "../../../Integration.t.sol"; abstract contract WithdrawableAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.withdrawableAmountOf(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.withdrawableAmountOf, nullStreamId) }); } function test_GivenCanceledStreamAndCANCELEDStatus() external givenNotNull { diff --git a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index 62079c239..ab8a911db 100644 --- a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -2,366 +2,37 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup-base/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup-base/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup-base/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup-base/cancel-multiple/cancelMultiple.t.sol"; + import { Cancel_Integration_Concrete_Test } from "./../lockup-base/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup-base/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup-base/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup-base/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup-base/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup-base/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from - "./../lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup-base/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup-base/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup-base/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup-base/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup-base/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup-base/is-warm/isWarm.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup-base/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "./../lockup-base/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup-base/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup-base/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup-base/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup-base/withdraw-hooks/withdrawHooks.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from - "./../lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup-base/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup-base/withdraw-multiple/withdrawMultiple.t.sol"; import { Withdraw_Integration_Concrete_Test } from "./../lockup-base/withdraw/withdraw.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract AllowToHook_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - AllowToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract Batch_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - Batch_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract Burn_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - Burn_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract Cancel_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - Cancel_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - CancelMultiple_Integration_Concrete_Test -{ - modifier whenCallerAuthorizedForAllStreams() override { - _; - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLD({ warpTime: originalTime }); - _; - } - - function setUp() - public - virtual - override(Lockup_Dynamic_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) - { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - CancelMultiple_Integration_Concrete_Test.setUp(); - } -} - -contract GetAsset_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetAsset_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetDepositedAmount_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetDepositedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetEndTime_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetEndTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetRecipient_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetRecipient_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetRefundedAmount_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetRefundedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetSender_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetSender_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetStartTime_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetStartTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract GetWithdrawnAmount_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsAllowedToHook_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsAllowedToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsCancelable_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsCancelable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsCold_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsCold_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsDepleted_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsDepleted_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsStream_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsStream_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsTransferable_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsTransferable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract IsWarm_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - IsWarm_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract RefundableAmountOf_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - RefundableAmountOf_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract Renounce_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - Renounce_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); +contract Cancel_Lockup_Dynamic_Integration_Concrete_Test is Cancel_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); } } -contract SetNFTDescriptor_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - SetNFTDescriptor_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); +contract RefundableAmountOf_Lockup_Dynamic_Integration_Concrete_Test is RefundableAmountOf_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); } } -contract StatusOf_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - StatusOf_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); +contract Renounce_Lockup_Dynamic_Integration_Concrete_Test is Renounce_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); } } -contract TransferFrom_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - TransferFrom_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Dynamic_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) - { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - TransferFrom_Integration_Concrete_Test.setUp(); - } -} - -contract WasCanceled_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - WasCanceled_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract Withdraw_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - Withdraw_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawHooks_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawHooks_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Dynamic_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) - { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - WithdrawHooks_Integration_Concrete_Test.setUp(); - } -} - -contract WithdrawMax_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawMax_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMaxAndTransfer_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawMultiple_Integration_Concrete_Test -{ - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: originalTime }); - caller = users.operator; - _; - } - - function setUp() - public - virtual - override(Lockup_Dynamic_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) - { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - WithdrawMultiple_Integration_Concrete_Test.setUp(); +contract Withdraw_Lockup_Dynamic_Integration_Concrete_Test is Withdraw_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol similarity index 55% rename from test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol index 6191ad777..840214d5a 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.t.sol @@ -8,28 +8,44 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; - -contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { - uint256 internal streamId; +import { Integration_Test } from "./../../../Integration.t.sol"; +contract CreateWithDurationsLD_Integration_Concrete_Test is Integration_Test { function setUp() public virtual override { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); + Integration_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev We need this function as we cannot copy from memory to storage. + function createDefaultStreamWithDurations(LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations) + internal + returns (uint256 streamId) + { + streamId = lockup.createWithDurationsLD(_defaultParams.createWithDurations, segmentsWithDurations); } + /*////////////////////////////////////////////////////////////////////////// + TEST-FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall( - ISablierLockup.createWithDurationsLD, (defaults.createWithDurations(), defaults.segmentsWithDurations()) - ); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall( + lockup.createWithDurationsLD, (defaults.createWithDurations(), defaults.segmentsWithDurations()) + ) + }); } function test_RevertWhen_SegmentCountExceedsMaxValue() external whenNoDelegateCall { - LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, 25_000)); - createDefaultStreamWithDurationsLD(segments); + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = + new LockupDynamic.SegmentWithDuration[](25_000); + + // Set the default segments with duration. + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_SegmentCountTooHigh.selector, 25_000)); + createDefaultStreamWithDurations(segmentsWithDurations); } function test_RevertWhen_FirstIndexHasZeroDuration() @@ -38,18 +54,20 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ whenSegmentCountNotExceedMaxValue { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDuration[] memory segments = defaults.segmentsWithDurations(); - segments[1].duration = 0; + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = _defaultParams.segmentsWithDurations; + segmentsWithDurations[1].duration = 0; + + // Set the default segments with duration. uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, + Errors.SablierHelpers_SegmentTimestampsNotOrdered.selector, index, - startTime + segments[0].duration, - startTime + segments[0].duration + startTime + segmentsWithDurations[0].duration, + startTime + segmentsWithDurations[0].duration ) ); - createDefaultStreamWithDurationsLD(segments); + createDefaultStreamWithDurations(segmentsWithDurations); } function test_RevertWhen_StartTimeExceedsFirstTimestamp() @@ -61,16 +79,18 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ { unchecked { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDuration[] memory segments = defaults.segmentsWithDurations(); - segments[0].duration = MAX_UINT40; + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); + segmentsWithDurations[0].duration = MAX_UINT40; + + // Set the default segments with duration. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstSegmentTimestamp.selector, startTime, - startTime + segments[0].duration + startTime + segmentsWithDurations[0].duration ) ); - createDefaultStreamWithDurationsLD(segments); + createDefaultStreamWithDurations(segmentsWithDurations); } } @@ -86,28 +106,27 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ uint40 startTime = getBlockTimestamp(); // Create new segments that overflow when the timestamps are eventually calculated. - LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](2); - segments[0] = LockupDynamic.SegmentWithDuration({ + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = + new LockupDynamic.SegmentWithDuration[](2); + segmentsWithDurations[0] = LockupDynamic.SegmentWithDuration({ amount: 0, exponent: ud2x18(1e18), duration: startTime + 1 seconds }); - segments[1] = defaults.segmentsWithDurations()[0]; - segments[1].duration = MAX_UINT40; + segmentsWithDurations[1] = defaults.segmentsWithDurations()[0]; + segmentsWithDurations[1].duration = MAX_UINT40; // Expect the relevant error to be thrown. uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, + Errors.SablierHelpers_SegmentTimestampsNotOrdered.selector, index, - startTime + segments[0].duration, - startTime + segments[0].duration + segments[1].duration + startTime + segmentsWithDurations[0].duration, + startTime + segmentsWithDurations[0].duration + segmentsWithDurations[1].duration ) ); - - // Create the stream. - createDefaultStreamWithDurationsLD(segments); + createDefaultStreamWithDurations(segmentsWithDurations); } } @@ -119,17 +138,17 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ { // Make the Sender the stream's funder address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); Lockup.Timestamps memory timestamps = - Lockup.Timestamps({ start: blockTimestamp, cliff: 0, end: blockTimestamp + defaults.TOTAL_DURATION() }); + Lockup.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); // Adjust the segments. - LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].timestamp = timestamps.start + segmentsWithDurations[0].duration; - segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; + segments[0].timestamp = timestamps.start + _defaultParams.segmentsWithDurations[0].duration; + segments[1].timestamp = segments[0].timestamp + _defaultParams.segmentsWithDurations[1].duration; // It should perform the ERC-20 transfers. expectCallToTransferFrom({ from: funder, to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); @@ -139,10 +158,10 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ // It should emit {CreateLockupDynamicStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupDynamicStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: users.sender, recipient: users.recipient, @@ -156,21 +175,21 @@ contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integ }); // Create the stream. - createDefaultStreamWithDurationsLD(); + uint256 streamId = createDefaultStreamWithDurations(); // Assert that the stream has been created. assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); - assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); - assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); + assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getSegments(streamId), segments, "segments"); + assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isCancelable(streamId), "isCancelable"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); + assertEq(lockup.getAsset(streamId), dai, "asset"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC); // Assert that the stream's status is "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.tree b/test/core/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.tree similarity index 100% rename from test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.tree rename to test/core/integration/concrete/lockup-dynamic/create-with-durations-ld/createWithDurationsLD.tree diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol similarity index 52% rename from test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol index e0edc60a9..c7e726b26 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -1,104 +1,75 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; + import { stdError } from "forge-std/src/StdError.sol"; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; -import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { - uint256 internal streamId; +import { + CreateWithTimestamps_Integration_Concrete_Test, + Integration_Test +} from "../../lockup-base/create-with-timestamps/createWithTimestamps.t.sol"; +contract CreateWithTimestampsLD_Integration_Concrete_Test is CreateWithTimestamps_Integration_Concrete_Test { function setUp() public virtual override { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } - - function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall( - ISablierLockup.createWithTimestampsLD, (defaults.createWithTimestamps(), defaults.segments()) - ); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); - } - - function test_RevertWhen_SenderZeroAddress() external whenNoDelegateCall { - vm.expectRevert(Errors.SablierLockup_SenderZeroAddress.selector); - createDefaultStreamWithSenderLD(address(0)); + Integration_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_DYNAMIC; } - function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { - address recipient = address(0); - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipientLD(recipient); - } - - function test_RevertWhen_DepositAmountZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - { - // 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.SablierLockup_DepositAmountZero.selector); - uint128 totalAmount = 0; - createDefaultStreamWithTotalAmountLD(totalAmount); - } + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ - function test_RevertWhen_StartTimeZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - { - vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithStartTimeLD(0); + function createDefaultStreamWithSegments(LockupDynamic.Segment[] memory segments) internal returns (uint256) { + return lockup.createWithTimestampsLD(_defaultParams.createWithTimestamps, segments); } function test_RevertWhen_SegmentCountZero() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract { LockupDynamic.Segment[] memory segments; - vm.expectRevert(Errors.SablierLockup_SegmentCountZero.selector); - createDefaultStreamWithSegmentsLD(segments); + vm.expectRevert(Errors.SablierHelpers_SegmentCountZero.selector); + createDefaultStreamWithSegments(segments); } function test_RevertWhen_SegmentCountExceedsMaxValue() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero { uint256 segmentCount = defaults.MAX_COUNT() + 1; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); segments[segmentCount - 1].timestamp = defaults.END_TIME(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, segmentCount)); - createDefaultStreamWithSegmentsLD(segments); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_SegmentCountTooHigh.selector, segmentCount)); + createDefaultStreamWithSegments(segments); } function test_RevertWhen_SegmentAmountsSumOverflows() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero whenSegmentCountNotExceedMaxValue { @@ -106,16 +77,18 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte segments[0].amount = MAX_UINT128; segments[1].amount = 1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithSegmentsLD(segments); + createDefaultStreamWithSegments(segments); } function test_RevertWhen_StartTimeGreaterThanFirstTimestamp() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero whenSegmentCountNotExceedMaxValue whenSegmentAmountsSumNotOverflow @@ -127,23 +100,23 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) ); - - // Create the stream. - createDefaultStreamWithSegmentsLD(segments); + createDefaultStreamWithSegments(segments); } function test_RevertWhen_StartTimeEqualsFirstTimestamp() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero whenSegmentCountNotExceedMaxValue whenSegmentAmountsSumNotOverflow @@ -155,23 +128,23 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) ); - - // Create the stream. - createDefaultStreamWithSegmentsLD(segments); + createDefaultStreamWithSegments(segments); } function test_RevertWhen_TimestampsNotStrictlyIncreasing() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero whenSegmentCountNotExceedMaxValue whenSegmentAmountsSumNotOverflow @@ -181,21 +154,18 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte LockupDynamic.Segment[] memory segments = defaults.segments(); (segments[0].timestamp, segments[1].timestamp) = (segments[1].timestamp, segments[0].timestamp); - Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); - params.endTime = segments[1].timestamp; // Expect the relevant error to be thrown. uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, + Errors.SablierHelpers_SegmentTimestampsNotOrdered.selector, index, segments[0].timestamp, segments[1].timestamp ) ); - - // Create the stream. - lockup.createWithTimestampsLD(params, segments); + _defaultParams.createWithTimestamps.timestamps.end = segments[1].timestamp; + createDefaultStreamWithSegments(segments); } function test_RevertWhen_DepositAmountNotEqualSegmentAmountsSum() @@ -218,84 +188,35 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); - params.totalAmount = depositAmount; - - LockupDynamic.Segment[] memory segments = defaults.segments(); + _defaultParams.createWithTimestamps.broker = defaults.brokerNull(); + _defaultParams.createWithTimestamps.totalAmount = depositAmount; // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierHelpers_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) ); - - // Create the stream. - lockup.createWithTimestampsLD(params, segments); - } - - function test_RevertWhen_BrokerFeeExceedsMaxValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenSegmentCountNotZero - whenSegmentCountNotExceedMaxValue - whenSegmentAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTimestampsStrictlyIncreasing - whenDepositAmountNotEqualSegmentAmountsSum - { - UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) - ); - createDefaultStreamWithBrokerLD(Broker({ account: users.broker, fee: brokerFee })); - } - - function test_RevertWhen_AssetNotContract() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenSegmentCountNotZero - whenSegmentCountNotExceedMaxValue - whenSegmentAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTimestampsStrictlyIncreasing - whenDepositAmountNotEqualSegmentAmountsSum - whenBrokerFeeNotExceedMaxValue - { - address nonContract = address(8128); - - resetPrank({ msgSender: users.sender }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAssetLD(IERC20(nonContract)); + createDefaultStream(); } function test_WhenAssetMissesERC20ReturnValue() external whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue whenSenderNotZeroAddress whenRecipientNotZeroAddress whenDepositAmountNotZero whenStartTimeNotZero + whenAssetContract whenSegmentCountNotZero whenSegmentCountNotExceedMaxValue whenSegmentAmountsSumNotOverflow whenStartTimeLessThanFirstTimestamp whenTimestampsStrictlyIncreasing - whenDepositAmountNotEqualSegmentAmountsSum - whenBrokerFeeNotExceedMaxValue - whenAssetContract + whenDepositAmountEqualsSegmentAmountsSum { _testCreateWithTimestampsLD(address(usdt)); } @@ -323,6 +244,8 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte // Make the Sender the stream's funder. address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); + // It should perform the ERC-20 transfers. expectCallToTransferFrom({ asset: IERC20(asset), @@ -341,10 +264,10 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte // It should emit {CreateLockupDynamicStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupDynamicStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: users.sender, recipient: users.recipient, @@ -353,40 +276,18 @@ contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Inte asset: IERC20(asset), cancelable: true, transferable: true, - timestamps: defaults.lockupDynamicTimestamps(), + timestamps: defaults.lockupTimestamps(), broker: users.broker }); // Create the stream. - streamId = createDefaultStreamWithAssetLD(IERC20(asset)); + _defaultParams.createWithTimestamps.asset = IERC20(asset); + uint256 streamId = createDefaultStream(); // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); + assertEqStream(streamId); assertEq(lockup.getAsset(streamId), IERC20(asset), "asset"); - assertEq(lockup.getEndTime(streamId), defaults.END_TIME(), "endTime"); - assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); - assertEq(lockup.getSender(streamId), users.sender, "sender"); - assertEq(lockup.getStartTime(streamId), defaults.START_TIME(), "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); assertEq(lockup.getSegments(streamId), defaults.segments(), "segments"); - - // Assert that the stream's status is "PENDING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.PENDING; - assertEq(actualStatus, expectedStatus); - - // It should bump the next stream ID. - uint256 actualNextStreamId = lockup.nextStreamId(); - uint256 expectedNextStreamId = streamId + 1; - assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - - // It should mint the NFT. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; - assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC); } } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree new file mode 100644 index 000000000..997b2e331 --- /dev/null +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps-ld/createWithTimestampsLD.tree @@ -0,0 +1,34 @@ +CreateWithTimestampsLD_Integration_Concrete_Test +└── when asset contract + ├── when segment count zero + │ └── it should revert + └── when segment count not zero + ├── when segment count exceeds max value + │ └── it should revert + └── when segment count not exceed max value + ├── when segment amounts sum overflows + │ └── it should revert + └── when segment amounts sum not overflow + ├── when start time greater than first timestamp + │ └── it should revert + ├── when start time equals first timestamp + │ └── it should revert + └── when start time less than first timestamp + ├── when timestamps not strictly increasing + │ └── it should revert + └── when timestamps strictly increasing + ├── when deposit amount not equal segment amounts sum + │ └── it should revert + └── when deposit amount equals segment amounts sum + ├── when asset misses ERC20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit {CreateLockupDynamicStream} and {MetadataUpdate} events + │ └── it should perform the ERC-20 transfers + └── when asset not miss ERC20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit {CreateLockupDynamicStream} and {MetadataUpdate} events + └── it should perform the ERC-20 transfers \ No newline at end of file diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree deleted file mode 100644 index a827ea774..000000000 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree +++ /dev/null @@ -1,54 +0,0 @@ -CreateWithTimestampsLD_Integration_Concrete_Test -├── when delegate call -│ └── it should revert -└── when no delegate call - ├── when sender zero address - │ └── it should revert - └── when sender not zero address - ├── when recipient zero address - │ └── it should revert - └── when recipient not zero address - ├── when deposit amount zero - │ └── it should revert - └── when deposit amount not zero - ├── when start time zero - │ └── it should revert - └── when start time not zero - ├── when segment count zero - │ └── it should revert - └── when segment count not zero - ├── when segment count exceeds max value - │ └── it should revert - └── when segment count not exceed max value - ├── when segment amounts sum overflows - │ └── it should revert - └── when segment amounts sum not overflow - ├── when start time greater than first timestamp - │ └── it should revert - ├── when start time equals first timestamp - │ └── it should revert - └── when start time less than first timestamp - ├── when timestamps not strictly increasing - │ └── it should revert - └── when timestamps strictly increasing - ├── when deposit amount not equal segment amounts sum - │ └── it should revert - └── when deposit amount equals segment amounts sum - ├── when broker fee exceeds max value - │ └── it should revert - └── when broker fee not exceed max value - ├── when asset not contract - │ └── it should revert - └── when asset contract - ├── when asset misses ERC20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit {CreateLockupDynamicStream} and {MetadataUpdate} events - │ └── it should perform the ERC-20 transfers - └── when asset not miss ERC20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit {CreateLockupDynamicStream} and {MetadataUpdate} events - └── it should perform the ERC-20 transfers 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 8b872b286..32684db6d 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,17 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; -import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; +import { Integration_Test } from "./../../../Integration.t.sol"; -contract GetSegments_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { +contract GetSegments_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getSegments(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.getSegments, nullStreamId) }); } - function test_GivenNotNull() external { + function test_RevertGiven_NotDynamicModel() external givenNotNull { + lockupModel = Lockup.Model.LOCKUP_LINEAR; + uint256 streamId = createDefaultStream(); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierLockup_NotExpectedModel.selector, Lockup.Model.LOCKUP_LINEAR, Lockup.Model.LOCKUP_DYNAMIC + ) + ); + lockup.getSegments(streamId); + } + + function test_GivenDynamicModel() external givenNotNull { LockupDynamic.Segment[] memory actualSegments = lockup.getSegments(defaultStreamId); LockupDynamic.Segment[] memory expectedSegments = defaults.segments(); assertEq(actualSegments, expectedSegments, "segments"); diff --git a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree index 6b662caff..cfde74fef 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree +++ b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree @@ -2,4 +2,7 @@ GetSegments_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null - └── it should return the correct segments + ├── given not dynamic model + │ └── it should revert + └── given dynamic model + └── it should return the correct segments 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 deleted file mode 100644 index 98bfe1da1..000000000 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; - -import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; - -contract GetTimestamps_Lockup_Dynamic_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getTimestamps(nullStreamId); - } - - function test_GivenNotNull() external { - Lockup.Timestamps memory actualTimestamps = lockup.getTimestamps(defaultStreamId); - Lockup.Timestamps memory expectedTimestamps = defaults.lockupDynamicTimestamps(); - assertEq(actualTimestamps, expectedTimestamps); - } -} diff --git a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree deleted file mode 100644 index 245182d2b..000000000 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetTimestamps_Lockup_Dynamic_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct timestamps 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 ff7923c88..529cbb24b 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 @@ -2,16 +2,13 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { Integration_Test } from "./../../../Integration.t.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup-base/streamed-amount-of/streamedAmountOf.t.sol"; -import { Lockup_Dynamic_Integration_Shared_Test, Integration_Test } from "./../LockupDynamic.t.sol"; - -contract StreamedAmountOf_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, - StreamedAmountOf_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); + +contract StreamedAmountOf_Lockup_Dynamic_Integration_Concrete_Test is StreamedAmountOf_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { @@ -40,7 +37,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Concrete_Test is }); // Create the stream. - uint256 streamId = createDefaultStreamWithSegmentsLD(segments); + uint256 streamId = lockup.createWithTimestampsLD(_defaultParams.createWithTimestamps, segments); // It should return the correct streamed amount. uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); 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 aec623b5c..82eefe9b8 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 @@ -7,7 +7,7 @@ import { console2 } from "forge-std/src/console2.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; +import { Integration_Test } from "test/core/integration/Integration.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,7 +16,7 @@ import { Lockup_Dynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below -contract TokenURI_Lockup_Dynamic_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { +contract TokenURI_Lockup_Dynamic_Integration_Concrete_Test is Integration_Test { address internal constant LOCKUP = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; /// @dev To make these tests noninvasive, they are run only when the contract address matches the hard coded value. 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 d406d2721..34ea60863 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 @@ -1,16 +1,15 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Integration_Test } from "./../../../Integration.t.sol"; import { WithdrawableAmountOf_Integration_Concrete_Test } from "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { Lockup_Dynamic_Integration_Shared_Test, Integration_Test } from "./../LockupDynamic.t.sol"; contract WithdrawableAmountOf_Lockup_Dynamic_Integration_Concrete_Test is - Lockup_Dynamic_Integration_Shared_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override { + Integration_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { diff --git a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol index f2e8003dd..983664d90 100644 --- a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -1,367 +1,61 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Lockup } from "src/core/types/DataTypes.sol"; + import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup-base/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup-base/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup-base/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup-base/cancel-multiple/cancelMultiple.t.sol"; + import { Cancel_Integration_Concrete_Test } from "./../lockup-base/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup-base/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup-base/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup-base/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup-base/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup-base/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from - "./../lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup-base/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup-base/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup-base/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup-base/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup-base/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup-base/is-warm/isWarm.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup-base/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "./../lockup-base/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup-base/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup-base/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup-base/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup-base/withdraw-hooks/withdrawHooks.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from - "./../lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup-base/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup-base/withdraw-multiple/withdrawMultiple.t.sol"; import { Withdraw_Integration_Concrete_Test } from "./../lockup-base/withdraw/withdraw.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract AllowToHook_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - AllowToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} +contract Lockup_Linear_Integration_Concrete_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); -contract Batch_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - Batch_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract Burn_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - Burn_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_LINEAR; + createDefaultStreamIds(); } } contract Cancel_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Concrete_Test, Cancel_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - CancelMultiple_Integration_Concrete_Test -{ - modifier whenCallerAuthorizedForAllStreams() override { - _; - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLL({ warpTime: originalTime }); - _; - } - - function setUp() - public - virtual - override(Lockup_Linear_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) - { - Lockup_Linear_Integration_Shared_Test.setUp(); - CancelMultiple_Integration_Concrete_Test.setUp(); - } -} - -contract GetAsset_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetAsset_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetDepositedAmount_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetDepositedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetEndTime_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetEndTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetRecipient_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetRecipient_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetRefundedAmount_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetRefundedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetSender_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetSender_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetStartTime_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetStartTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract GetWithdrawnAmount_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsAllowedToHook_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsAllowedToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsCancelable_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsCancelable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsCold_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsCold_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsDepleted_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsDepleted_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsStream_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsStream_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsTransferable_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsTransferable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract IsWarm_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - IsWarm_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract Renounce_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - Renounce_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } } contract RefundableAmountOf_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Concrete_Test, RefundableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract SetNFTDescriptor_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - SetNFTDescriptor_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract StatusOf_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - StatusOf_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract TransferFrom_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - TransferFrom_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Linear_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) - { - Lockup_Linear_Integration_Shared_Test.setUp(); - TransferFrom_Integration_Concrete_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } } -contract WasCanceled_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - WasCanceled_Integration_Concrete_Test +contract Renounce_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Concrete_Test, + Renounce_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } } contract Withdraw_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Concrete_Test, Withdraw_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawHooks_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawHooks_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Linear_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) - { - Lockup_Linear_Integration_Shared_Test.setUp(); - WithdrawHooks_Integration_Concrete_Test.setUp(); - } -} - -contract WithdrawMax_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawMax_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMaxAndTransfer_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawMultiple_Integration_Concrete_Test -{ - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: originalTime }); - caller = users.operator; - _; - } - - function setUp() - public - virtual - override(Lockup_Linear_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) - { - Lockup_Linear_Integration_Shared_Test.setUp(); - WithdrawMultiple_Integration_Concrete_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol similarity index 62% rename from test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol rename to test/core/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol index 07b4277b7..72ae65a01 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.t.sol @@ -7,41 +7,32 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; - -contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Linear_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Lockup_Linear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; +contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integration_Concrete_Test { function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockup.createWithDurationsLL, (defaults.createWithDurations(), defaults.durations())); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall( + lockup.createWithDurationsLL, (_defaultParams.createWithDurations, _defaultParams.durations) + ) + }); } function test_RevertWhen_CliffTimeCalculationOverflows() external whenNoDelegateCall whenCliffDurationNotZero { uint40 startTime = getBlockTimestamp(); - uint40 cliffDuration = MAX_UINT40 - startTime + 2 seconds; - uint40 totalDuration = defaults.TOTAL_DURATION(); + _defaultParams.durations.cliff = MAX_UINT40 - startTime + 2 seconds; // Calculate the end time. Needs to be "unchecked" to avoid an overflow. uint40 cliffTime; unchecked { - cliffTime = startTime + cliffDuration; + cliffTime = startTime + _defaultParams.durations.cliff; } // It should revert. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) + abi.encodeWithSelector(Errors.SablierHelpers_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) ); - - // Create the stream. - createDefaultStreamWithDurationsLL(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); + createDefaultStreamWithDurations(); } function test_WhenCliffTimeCalculationNotOverflow() external whenNoDelegateCall whenCliffDurationNotZero { @@ -51,24 +42,20 @@ contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integr function test_RevertWhen_EndTimeCalculationOverflows() external whenNoDelegateCall whenCliffDurationZero { uint40 startTime = getBlockTimestamp(); - LockupLinear.Durations memory durations = - LockupLinear.Durations({ cliff: 0, total: MAX_UINT40 - startTime + 1 seconds }); + _defaultParams.durations = LockupLinear.Durations({ cliff: 0, total: MAX_UINT40 - startTime + 1 seconds }); - // Calculate the cliff time and the end time. Needs to be "unchecked" to allow an overflow. - uint40 cliffTime; + // Calculate the end time. Needs to be "unchecked" to allow an overflow. uint40 endTime; unchecked { - cliffTime = startTime + durations.cliff; - endTime = startTime + durations.total; + endTime = startTime + _defaultParams.durations.total; } // It should revert. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanEndTime.selector, startTime, endTime) + abi.encodeWithSelector(Errors.SablierHelpers_StartTimeNotLessThanEndTime.selector, startTime, endTime) ); - // Create the stream. - createDefaultStreamWithDurationsLL(durations); + createDefaultStreamWithDurations(); } function test_WhenEndTimeCalculationNotOverflow() external whenNoDelegateCall whenCliffDurationZero { @@ -80,16 +67,17 @@ contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integr function _test_CreateWithDurations(LockupLinear.Durations memory durations) private { // Make the Sender the stream's funder address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - Lockup.Timestamps memory timestamps = Lockup.Timestamps({ - start: blockTimestamp, - cliff: blockTimestamp + durations.cliff, - end: blockTimestamp + durations.total - }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: blockTimestamp, end: blockTimestamp + durations.total }); - if (durations.cliff == 0) timestamps.cliff = 0; + uint40 cliffTime; + if (durations.cliff > 0) { + cliffTime = blockTimestamp + durations.cliff; + } // It should perform the ERC-20 transfers. expectCallToTransferFrom({ from: funder, to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); @@ -99,10 +87,10 @@ contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integr // It should emit {CreateLockupLinearStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupLinearStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: users.sender, recipient: users.recipient, @@ -111,25 +99,27 @@ contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integr cancelable: true, transferable: true, timestamps: timestamps, + cliffTime: cliffTime, broker: users.broker }); // Create the stream. - createDefaultStreamWithDurationsLL(durations); + _defaultParams.durations = durations; + uint256 streamId = createDefaultStreamWithDurations(); // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); assertEq(lockup.getAsset(streamId), dai, "asset"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getCliffTime(streamId), timestamps.cliff, "cliff"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); + assertEq(lockup.getCliffTime(streamId), cliffTime, "cliffTime"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_LINEAR); // Assert that the stream's status is "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.tree b/test/core/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.tree similarity index 100% rename from test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.tree rename to test/core/integration/concrete/lockup-linear/create-with-durations-ll/createWithDurationsLL.tree diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol new file mode 100644 index 000000000..cfa7a9bf1 --- /dev/null +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.t.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.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"; + +import { + CreateWithTimestamps_Integration_Concrete_Test, + Integration_Test +} from "../../lockup-base/create-with-timestamps/createWithTimestamps.t.sol"; + +contract CreateWithTimestampsLL_Integration_Concrete_Test is CreateWithTimestamps_Integration_Concrete_Test { + function setUp() public override { + Integration_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_LINEAR; + } + + function test_RevertWhen_StartTimeNotLessThanEndTime() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeZero + { + uint40 startTime = defaults.END_TIME(); + uint40 cliffTime = 0; + uint40 endTime = defaults.START_TIME(); + _defaultParams.createWithTimestamps.timestamps.start = startTime; + _defaultParams.createWithTimestamps.timestamps.end = endTime; + + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierHelpers_StartTimeNotLessThanEndTime.selector, startTime, endTime) + ); + lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, cliffTime); + } + + function test_WhenStartTimeLessThanEndTime() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeZero + { + uint40 cliffTime = 0; + _testCreateWithTimestampsLL(address(dai), cliffTime); + } + + function test_RevertWhen_StartTimeNotLessThanCliffTime() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeNotZero + { + uint40 startTime = defaults.CLIFF_TIME(); + uint40 endTime = defaults.END_TIME(); + uint40 cliffTime = defaults.START_TIME(); + + _defaultParams.createWithTimestamps.timestamps.start = startTime; + _defaultParams.createWithTimestamps.timestamps.end = endTime; + + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierHelpers_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) + ); + lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, cliffTime); + } + + function test_RevertWhen_CliffTimeNotLessThanEndTime() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeNotZero + whenStartTimeLessThanCliffTime + { + _defaultParams.cliffTime = defaults.END_TIME() + 1; + + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierHelpers_CliffTimeNotLessThanEndTime.selector, + _defaultParams.cliffTime, + _defaultParams.createWithTimestamps.timestamps.end + ) + ); + createDefaultStream(); + } + + function test_WhenAssetMissesERC20ReturnValue() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeNotZero + whenStartTimeLessThanCliffTime + whenCliffTimeLessThanEndTime + { + _testCreateWithTimestampsLL(address(usdt), _defaultParams.cliffTime); + } + + function test_WhenAssetNotMissERC20ReturnValue() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenCliffTimeNotZero + whenStartTimeLessThanCliffTime + whenCliffTimeLessThanEndTime + { + _testCreateWithTimestampsLL(address(dai), _defaultParams.cliffTime); + } + + /// @dev Shared logic between {test_WhenStartTimeLessThanEndTime}, {test_WhenAssetMissesERC20ReturnValue} and + /// {test_WhenAssetNotMissERC20ReturnValue}. + function _testCreateWithTimestampsLL(address asset, uint40 cliffTime) private { + // Make the Sender the stream's funder. + address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); + + // It should perform the ERC-20 transfers. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: address(lockup), + value: defaults.DEPOSIT_AMOUNT() + }); + + // Expect the broker fee to be paid to the broker. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: users.broker, + value: defaults.BROKER_FEE_AMOUNT() + }); + + // It should emit {MetadataUpdate} and {CreateLockupLinearStream} events. + vm.expectEmit({ emitter: address(lockup) }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ + streamId: expectedStreamId, + funder: funder, + sender: users.sender, + recipient: users.recipient, + amounts: defaults.lockupCreateAmounts(), + asset: IERC20(asset), + cancelable: true, + transferable: true, + timestamps: defaults.lockupTimestamps(), + cliffTime: cliffTime, + broker: users.broker + }); + + // Create the stream. + _defaultParams.createWithTimestamps.asset = IERC20(asset); + _defaultParams.cliffTime = cliffTime; + uint256 streamId = createDefaultStream(); + + // It should create the stream. + assertEqStream(streamId); + assertEq(lockup.getAsset(streamId), IERC20(asset), "asset"); + assertEq(lockup.getCliffTime(streamId), cliffTime, "cliffTime"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_LINEAR); + } +} diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree b/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree new file mode 100644 index 000000000..ed04aaaa4 --- /dev/null +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps-ll/createWithTimestampsLL.tree @@ -0,0 +1,26 @@ +CreateWithTimestampsLL_Integration_Concrete_Test +└── when asset contract + ├── when cliff time zero + │ ├── when start time not less than end time + │ │ └── it should revert + │ └── when start time less than end time + │ └── it should create the stream + └── when cliff time not zero + ├── when start time not less than cliff time + │ └── it should revert + └── when start time less than cliff time + ├── when cliff time not less than end time + │ └── it should revert + └── when cliff time less than end time + ├── when asset misses ERC20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit {MetadataUpdate} and {CreateLockupLinearStream} events + │ └── it should perform the ERC-20 transfers + └── when asset not miss ERC20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit {MetadataUpdate} and {CreateLockupLinearStream} events + └── it should perform the ERC-20 transfers diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol deleted file mode 100644 index 880c92f7b..000000000 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol +++ /dev/null @@ -1,295 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; -import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Errors } from "src/core/libraries/Errors.sol"; -import { Broker, Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "./../LockupLinear.t.sol"; - -contract CreateWithTimestampsLL_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public override { - Lockup_Linear_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } - - function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall( - ISablierLockup.createWithTimestampsLT, (defaults.createWithTimestamps(), defaults.tranches()) - ); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); - } - - function test_RevertWhen_SenderZeroAddress() external whenNoDelegateCall { - vm.expectRevert(Errors.SablierLockup_SenderZeroAddress.selector); - createDefaultStreamWithSenderLL(address(0)); - } - - function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { - address recipient = address(0); - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipientLL(recipient); - } - - function test_RevertWhen_DepositAmountZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - { - vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); - createDefaultStreamWithTotalAmountLL(0); - } - - function test_RevertWhen_StartTimeZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - { - uint40 cliffTime = defaults.CLIFF_TIME(); - uint40 endTime = defaults.END_TIME(); - - vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: 0, cliff: cliffTime, end: endTime })); - } - - function test_RevertWhen_StartTimeNotLessThanEndTime() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeZero - { - uint40 startTime = defaults.END_TIME(); - uint40 endTime = defaults.START_TIME(); - - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanEndTime.selector, startTime, endTime) - ); - createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: 0, end: endTime })); - } - - function test_WhenStartTimeLessThanEndTime() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeZero - { - createDefaultStreamWithTimestampsLL( - Lockup.Timestamps({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) - ); - - // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); - assertEq(lockup.getEndTime(streamId), defaults.END_TIME(), "endTime"); - assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); - assertEq(lockup.getSender(streamId), users.sender, "sender"); - assertEq(lockup.getStartTime(streamId), defaults.START_TIME(), "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getCliffTime(streamId), 0, "cliff"); - - // Assert that the next stream ID has been bumped. - uint256 actualNextStreamId = lockup.nextStreamId(); - uint256 expectedNextStreamId = streamId + 1; - assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - - // Assert that the NFT has been minted. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; - assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); - } - - function test_RevertWhen_StartTimeNotLessThanCliffTime() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - { - uint40 startTime = defaults.CLIFF_TIME(); - uint40 cliffTime = defaults.START_TIME(); - uint40 endTime = defaults.END_TIME(); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) - ); - createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); - } - - function test_RevertWhen_CliffTimeNotLessThanEndTime() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - whenStartTimeLessThanCliffTime - { - uint40 startTime = defaults.START_TIME(); - uint40 cliffTime = defaults.END_TIME(); - uint40 endTime = defaults.CLIFF_TIME(); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) - ); - createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); - } - - function test_RevertWhen_BrokerFeeExceedsMaxValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - whenStartTimeLessThanCliffTime - whenCliffTimeLessThanEndTime - { - UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) - ); - createDefaultStreamWithBrokerLL(Broker({ account: users.broker, fee: brokerFee })); - } - - function test_RevertWhen_AssetNotContract() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - whenStartTimeLessThanCliffTime - whenCliffTimeLessThanEndTime - whenBrokerFeeNotExceedMaxValue - { - address nonContract = address(8128); - vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAssetLL(IERC20(nonContract)); - } - - function test_WhenAssetMissesERC20ReturnValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - whenStartTimeLessThanCliffTime - whenCliffTimeLessThanEndTime - whenBrokerFeeNotExceedMaxValue - whenAssetContract - { - _testCreateWithTimestamps(address(usdt)); - } - - function test_WhenAssetNotMissERC20ReturnValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenCliffTimeNotZero - whenStartTimeLessThanCliffTime - whenCliffTimeLessThanEndTime - whenBrokerFeeNotExceedMaxValue - whenAssetContract - { - _testCreateWithTimestamps(address(dai)); - } - - /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. - function _testCreateWithTimestamps(address asset) private { - // Make the Sender the stream's funder. - address funder = users.sender; - - // It should perform the ERC-20 transfers. - expectCallToTransferFrom({ - asset: IERC20(asset), - from: funder, - to: address(lockup), - value: defaults.DEPOSIT_AMOUNT() - }); - - // Expect the broker fee to be paid to the broker. - expectCallToTransferFrom({ - asset: IERC20(asset), - from: funder, - to: users.broker, - value: defaults.BROKER_FEE_AMOUNT() - }); - - // It should emit {MetadataUpdate} and {CreateLockupLinearStream} events. - vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CreateLockupLinearStream({ - streamId: streamId, - funder: funder, - sender: users.sender, - recipient: users.recipient, - amounts: defaults.lockupCreateAmounts(), - asset: IERC20(asset), - cancelable: true, - transferable: true, - timestamps: defaults.lockupLinearTimestamps(), - broker: users.broker - }); - - // Create the stream. - createDefaultStreamWithAssetLL(IERC20(asset)); - - // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); - assertEq(lockup.getAsset(streamId), IERC20(asset), "asset"); - assertEq(lockup.getEndTime(streamId), defaults.END_TIME(), "endTime"); - assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); - assertEq(lockup.getSender(streamId), users.sender, "sender"); - assertEq(lockup.getStartTime(streamId), defaults.START_TIME(), "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getCliffTime(streamId), defaults.CLIFF_TIME(), "cliff"); - - // Assert that the stream's status is "PENDING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.PENDING; - assertEq(actualStatus, expectedStatus); - - // It should bump the next stream ID. - uint256 actualNextStreamId = lockup.nextStreamId(); - uint256 expectedNextStreamId = streamId + 1; - assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - - // It should mint the NFT. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; - assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); - } -} diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree deleted file mode 100644 index f1d53bdd8..000000000 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree +++ /dev/null @@ -1,46 +0,0 @@ -CreateWithTimestampsLL_Integration_Concrete_Test -├── when delegate call -│ └── it should revert -└── when no delegate call - ├── when sender zero address - │ └── it should revert - └── when sender not zero address - ├── when recipient zero address - │ └── it should revert - └── when recipient not zero address - ├── when deposit amount zero - │ └── it should revert - └── when deposit amount not zero - ├── when start time zero - │ └── it should revert - └── when start time not zero - ├── when cliff time zero - │ ├── when start time not less than end time - │ │ └── it should revert - │ └── when start time less than end time - │ └── it should create the stream - └── when cliff time not zero - ├── when start time not less than cliff time - │ └── it should revert - └── when start time less than cliff time - ├── when cliff time not less than end time - │ └── it should revert - └── when cliff time less than end time - ├── when broker fee exceeds max value - │ └── it should revert - └── when broker fee not exceed max value - ├── when asset not contract - │ └── it should revert - └── when asset contract - ├── when asset misses ERC20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit {MetadataUpdate} and {CreateLockupLinearStream} events - │ └── it should perform the ERC-20 transfers - └── when asset not miss ERC20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit {MetadataUpdate} and {CreateLockupLinearStream} events - └── it should perform the ERC-20 transfers 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 0b30aa5df..3888145b8 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 @@ -2,16 +2,27 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Concrete_Test } from "../LockupLinear.t.sol"; -contract GetCliffTime_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { +contract GetCliffTime_Integration_Concrete_Test is Lockup_Linear_Integration_Concrete_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getCliffTime(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.getCliffTime, nullStreamId) }); } - function test_GivenNotNull() external view { + function test_RevertGiven_NotLinearModel() external givenNotNull { + lockupModel = Lockup.Model.LOCKUP_TRANCHED; + uint256 streamId = createDefaultStream(); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierLockup_NotExpectedModel.selector, Lockup.Model.LOCKUP_TRANCHED, Lockup.Model.LOCKUP_LINEAR + ) + ); + lockup.getCliffTime(streamId); + } + + function test_GivenLinearModel() external view givenNotNull { uint40 actualCliffTime = lockup.getCliffTime(defaultStreamId); uint40 expectedCliffTime = defaults.CLIFF_TIME(); assertEq(actualCliffTime, expectedCliffTime, "cliffTime"); diff --git a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree index ca19479a2..24516ef0e 100644 --- a/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree +++ b/test/core/integration/concrete/lockup-linear/get-cliff-time/getCliffTime.tree @@ -2,4 +2,7 @@ GetCliffTime_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null - └── it should return the correct cliff time + ├── given not linear model + │ └── it should revert + └── given linear model + └── it should return the correct cliff time 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 deleted file mode 100644 index 2996a3690..000000000 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; - -import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; - -contract GetTimestamps_Lockup_Linear_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getTimestamps(nullStreamId); - } - - function test_GivenNotNull() external { - Lockup.Timestamps memory actualTimestamps = lockup.getTimestamps(defaultStreamId); - Lockup.Timestamps memory expectedTimestamps = defaults.lockupLinearTimestamps(); - assertEq(actualTimestamps, expectedTimestamps); - } -} diff --git a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree deleted file mode 100644 index 68edb7c04..000000000 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetTimestamps_Lockup_Linear_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct timestamps 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 7f81584ed..00e3e51d2 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,24 +1,23 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/core/types/DataTypes.sol"; import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup-base/streamed-amount-of/streamedAmountOf.t.sol"; -import { Lockup_Linear_Integration_Shared_Test, Integration_Test } from "./../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Concrete_Test, Integration_Test } from "./../LockupLinear.t.sol"; contract StreamedAmountOf_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Concrete_Test, StreamedAmountOf_Integration_Concrete_Test { - function setUp() public override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } function test_GivenCliffTimeZero() external givenPENDINGStatus { + uint40 cliffTime = 0; + uint256 streamId = lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, cliffTime); + vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); - Lockup.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); - timestamps.cliff = 0; - uint256 streamId = createDefaultStreamWithTimestampsLL(timestamps); uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = 0; @@ -28,11 +27,7 @@ contract StreamedAmountOf_Lockup_Linear_Integration_Concrete_Test is function test_GivenCliffTimeNotZero() external givenPENDINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); - Lockup.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); - timestamps.cliff = defaults.CLIFF_TIME(); - uint256 streamId = createDefaultStreamWithTimestampsLL(timestamps); - - uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } 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 bab3f3e4e..3bb005ba1 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 @@ -7,7 +7,7 @@ import { console2 } from "forge-std/src/console2.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Integration_Test } from "../LockupLinear.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,7 +16,7 @@ import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below -contract TokenURI_Lockup_Linear_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { +contract TokenURI_Lockup_Linear_Integration_Concrete_Test is Integration_Test { address internal constant LOCKUP = 0x3381cD18e2Fb4dB236BF0525938AB6E43Db0440f; /// @dev To make these tests noninvasive, they are run only when the contract address matches the hard coded value. 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 37c18c611..2832faaf6 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 @@ -3,14 +3,14 @@ pragma solidity >=0.8.22 <0.9.0; import { WithdrawableAmountOf_Integration_Concrete_Test } from "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { Lockup_Linear_Integration_Shared_Test, Integration_Test } from "./../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Concrete_Test, Integration_Test } from "./../LockupLinear.t.sol"; contract WithdrawableAmountOf_Lockup_Linear_Integration_Concrete_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Concrete_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Concrete_Test, Integration_Test) { + Lockup_Linear_Integration_Concrete_Test.setUp(); } function test_GivenCliffTimeInFuture() external givenSTREAMINGStatus { diff --git a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol index 5c5b4e0b2..cbde94328 100644 --- a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -1,366 +1,58 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Lockup } from "src/core/types/DataTypes.sol"; + import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../../shared/lockup/LockupTranched.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup-base/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup-base/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup-base/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup-base/cancel-multiple/cancelMultiple.t.sol"; import { Cancel_Integration_Concrete_Test } from "./../lockup-base/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup-base/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup-base/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup-base/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from - "./../lockup-base/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup-base/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup-base/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from - "./../lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup-base/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup-base/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup-base/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup-base/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup-base/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup-base/is-warm/isWarm.t.sol"; import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup-base/refundable-amount-of/refundableAmountOf.t.sol"; import { Renounce_Integration_Concrete_Test } from "./../lockup-base/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup-base/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup-base/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup-base/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup-base/withdraw-hooks/withdrawHooks.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Concrete_Test } from - "./../lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup-base/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup-base/withdraw-multiple/withdrawMultiple.t.sol"; import { Withdraw_Integration_Concrete_Test } from "./../lockup-base/withdraw/withdraw.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract AllowToHook_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - AllowToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract Batch_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - Batch_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract Burn_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - Burn_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); +contract Lockup_Tranched_Integration_Concrete_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_TRANCHED; + createDefaultStreamIds(); } } contract Cancel_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, Cancel_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - CancelMultiple_Integration_Concrete_Test -{ - modifier whenCallerAuthorizedForAllStreams() override { - _; - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLT({ warpTime: originalTime }); - _; - } - - function setUp() - public - virtual - override(Lockup_Tranched_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) - { - Lockup_Tranched_Integration_Shared_Test.setUp(); - CancelMultiple_Integration_Concrete_Test.setUp(); - } -} - -contract GetAsset_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetAsset_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetDepositedAmount_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetDepositedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetEndTime_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetEndTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetRecipient_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetRecipient_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetRefundedAmount_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetRefundedAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetSender_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetSender_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetStartTime_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetStartTime_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetWithdrawnAmount_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsAllowedToHook_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsAllowedToHook_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsCancelable_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsCancelable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsCold_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsCold_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsDepleted_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsDepleted_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsStream_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsStream_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsTransferable_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsTransferable_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract IsWarm_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - IsWarm_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } } contract RefundableAmountOf_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, RefundableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } } contract Renounce_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, Renounce_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract SetNFTDescriptor_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - SetNFTDescriptor_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract StatusOf_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - StatusOf_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract TransferFrom_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - TransferFrom_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Tranched_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) - { - Lockup_Tranched_Integration_Shared_Test.setUp(); - TransferFrom_Integration_Concrete_Test.setUp(); - } -} - -contract WasCanceled_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - WasCanceled_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } } contract Withdraw_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, Withdraw_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawHooks_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawHooks_Integration_Concrete_Test -{ - function setUp() - public - virtual - override(Lockup_Tranched_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) - { - Lockup_Tranched_Integration_Shared_Test.setUp(); - WithdrawHooks_Integration_Concrete_Test.setUp(); - } -} - -contract WithdrawMax_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawMax_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMaxAndTransfer_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Concrete_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawMultiple_Integration_Concrete_Test -{ - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: originalTime }); - caller = users.operator; - _; - } - - function setUp() - public - virtual - override(Lockup_Tranched_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) - { - Lockup_Tranched_Integration_Shared_Test.setUp(); - WithdrawMultiple_Integration_Concrete_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol similarity index 72% rename from test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol rename to test/core/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol index bc5742b56..756c3aae1 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.t.sol @@ -7,28 +7,41 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../LockupTranched.t.sol"; - -contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { - uint256 internal streamId; +import { Lockup_Tranched_Integration_Concrete_Test } from "./../LockupTranched.t.sol"; +contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Integration_Concrete_Test { function setUp() public virtual override { - Lockup_Tranched_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); + Lockup_Tranched_Integration_Concrete_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev We need this function as we cannot copy from memory to storage. + function createDefaultStreamWithDurations(LockupTranched.TrancheWithDuration[] memory tranchesWithDurations) + internal + returns (uint256 streamId) + { + streamId = lockup.createWithDurationsLT(_defaultParams.createWithDurations, tranchesWithDurations); } + /*////////////////////////////////////////////////////////////////////////// + TEST-FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall( - ISablierLockup.createWithDurationsLT, (defaults.createWithDurations(), defaults.tranchesWithDurations()) - ); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); + expectRevert_DelegateCall({ + callData: abi.encodeCall( + lockup.createWithDurationsLT, (defaults.createWithDurations(), defaults.tranchesWithDurations()) + ) + }); } function test_RevertWhen_TrancheCountExceedsMaxValue() external whenNoDelegateCall { LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, 25_000)); - createDefaultStreamWithDurationsLT(tranches); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_TrancheCountTooHigh.selector, 25_000)); + createDefaultStreamWithDurations(tranches); } function test_RevertWhen_FirstIndexHasZeroDuration() @@ -42,13 +55,13 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte uint256 index = 2; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, + Errors.SablierHelpers_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration + tranches[1].duration, startTime + tranches[0].duration + tranches[1].duration ) ); - createDefaultStreamWithDurationsLT(tranches); + createDefaultStreamWithDurations(tranches); } function test_RevertWhen_StartTimeExceedsFirstTimestamp() @@ -64,12 +77,12 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte tranches[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstTrancheTimestamp.selector, startTime, startTime + tranches[0].duration ) ); - createDefaultStreamWithDurationsLT(tranches); + createDefaultStreamWithDurations(tranches); } } @@ -94,15 +107,14 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, + Errors.SablierHelpers_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration, startTime + tranches[0].duration + tranches[1].duration ) ); - // Create the stream. - createDefaultStreamWithDurationsLT(tranches); + createDefaultStreamWithDurations(tranches); } } @@ -114,11 +126,12 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte { // Make the Sender the stream's funder address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); Lockup.Timestamps memory timestamps = - Lockup.Timestamps({ start: blockTimestamp, cliff: 0, end: blockTimestamp + defaults.TOTAL_DURATION() }); + Lockup.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); LockupTranched.Tranche[] memory tranches = defaults.tranches(); @@ -134,10 +147,10 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte // It should emit {MetadataUpdate} and {CreateLockupTranchedStream} events. vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupTranchedStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: users.sender, recipient: users.recipient, @@ -151,21 +164,22 @@ contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Inte }); // Create the stream. - createDefaultStreamWithDurationsLT(); + uint256 streamId = createDefaultStreamWithDurations(tranchesWithDurations); // Assert that the stream has been created. assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); assertEq(lockup.getAsset(streamId), dai, "asset"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); assertEq(lockup.getTranches(streamId), tranches, "tranches"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_TRANCHED); // Assert that the stream's status is "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.tree b/test/core/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.tree similarity index 100% rename from test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.tree rename to test/core/integration/concrete/lockup-tranched/create-with-durations-lt/createWithDurationsLT.tree diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol new file mode 100644 index 000000000..cb8e494d6 --- /dev/null +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { stdError } from "forge-std/src/StdError.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { Errors } from "src/core/libraries/Errors.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; + +import { + CreateWithTimestamps_Integration_Concrete_Test, + Integration_Test +} from "../../lockup-base/create-with-timestamps/createWithTimestamps.t.sol"; + +contract CreateWithTimestampsLT_Integration_Concrete_Test is CreateWithTimestamps_Integration_Concrete_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_TRANCHED; + } + + function test_RevertWhen_TrancheCountZero() + external + whenNoDelegateCall + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + { + LockupTranched.Tranche[] memory tranches; + vm.expectRevert(Errors.SablierHelpers_TrancheCountZero.selector); + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); + } + + function test_RevertWhen_TrancheCountExceedsMaxValue() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + { + uint256 trancheCount = defaults.MAX_COUNT() + 1; + LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_TrancheCountTooHigh.selector, trancheCount)); + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); + } + + function test_RevertWhen_TrancheAmountsSumOverflows() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + { + _defaultParams.tranches[0].amount = MAX_UINT128; + _defaultParams.tranches[1].amount = 1; + vm.expectRevert(stdError.arithmeticError); + createDefaultStream(); + } + + function test_RevertWhen_StartTimeGreaterThanFirstTimestamp() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + { + // Change the timestamp of the first tranche. + LockupTranched.Tranche[] memory tranches = defaults.tranches(); + tranches[0].timestamp = defaults.START_TIME() - 1 seconds; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierHelpers_StartTimeNotLessThanFirstTrancheTimestamp.selector, + defaults.START_TIME(), + tranches[0].timestamp + ) + ); + + // Create the stream. + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); + } + + function test_RevertWhen_StartTimeEqualsFirstTimestamp() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + { + // Change the timestamp of the first tranche. + _defaultParams.tranches[0].timestamp = defaults.START_TIME(); + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierHelpers_StartTimeNotLessThanFirstTrancheTimestamp.selector, + defaults.START_TIME(), + _defaultParams.tranches[0].timestamp + ) + ); + createDefaultStream(); + } + + function test_RevertWhen_TimestampsNotStrictlyIncreasing() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + whenStartTimeLessThanFirstTimestamp + { + // Swap the tranche timestamps. + (_defaultParams.tranches[0].timestamp, _defaultParams.tranches[1].timestamp) = + (_defaultParams.tranches[1].timestamp, _defaultParams.tranches[0].timestamp); + + // Expect the relevant error to be thrown. + uint256 index = 1; + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierHelpers_TrancheTimestampsNotOrdered.selector, + index, + _defaultParams.tranches[0].timestamp, + _defaultParams.tranches[1].timestamp + ) + ); + createDefaultStream(); + } + + function test_RevertWhen_DepositAmountNotEqualTrancheAmountsSum() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + whenStartTimeLessThanFirstTimestamp + whenTimestampsStrictlyIncreasing + { + resetPrank({ msgSender: users.sender }); + + // Adjust the default deposit amount. + uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); + uint128 depositAmount = defaultDepositAmount + 100; + _defaultParams.createWithTimestamps.broker = defaults.brokerNull(); + _defaultParams.createWithTimestamps.totalAmount = depositAmount; + + // Expect the relevant error to be thrown. + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierHelpers_DepositAmountNotEqualToTrancheAmountsSum.selector, + depositAmount, + defaultDepositAmount + ) + ); + createDefaultStream(); + } + + function test_WhenAssetMissesERC20ReturnValue() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + whenStartTimeLessThanFirstTimestamp + whenTimestampsStrictlyIncreasing + whenDepositAmountEqualsTrancheAmountsSum + { + _testCreateWithTimestampsLT(address(usdt)); + } + + function test_WhenAssetNotMissERC20ReturnValue() + external + whenNoDelegateCall + whenBrokerFeeNotExceedMaxValue + whenSenderNotZeroAddress + whenRecipientNotZeroAddress + whenDepositAmountNotZero + whenStartTimeNotZero + whenAssetContract + whenTrancheCountNotZero + whenTrancheCountNotExceedMaxValue + whenTrancheAmountsSumNotOverflow + whenStartTimeLessThanFirstTimestamp + whenTimestampsStrictlyIncreasing + whenDepositAmountEqualsTrancheAmountsSum + { + _testCreateWithTimestampsLT(address(dai)); + } + + /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. + function _testCreateWithTimestampsLT(address asset) internal { + // Make the Sender the stream's funder. + address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); + + // It should perform the ERC-20 transfers. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: address(lockup), + value: defaults.DEPOSIT_AMOUNT() + }); + + // Expect the broker fee to be paid to the broker. + expectCallToTransferFrom({ + asset: IERC20(asset), + from: funder, + to: users.broker, + value: defaults.BROKER_FEE_AMOUNT() + }); + + // It should emit {CreateLockupTranchedStream} and {MetadataUpdate} events. + vm.expectEmit({ emitter: address(lockup) }); + emit IERC4906.MetadataUpdate({ _tokenId: expectedStreamId }); + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupTranchedStream({ + streamId: expectedStreamId, + funder: funder, + sender: users.sender, + recipient: users.recipient, + amounts: defaults.lockupCreateAmounts(), + tranches: defaults.tranches(), + asset: IERC20(asset), + cancelable: true, + transferable: true, + timestamps: defaults.lockupTimestamps(), + broker: users.broker + }); + + // It should create the stream. + _defaultParams.createWithTimestamps.asset = IERC20(asset); + uint256 streamId = createDefaultStream(); + + // It should create the stream. + assertEqStream(streamId); + assertEq(lockup.getAsset(streamId), IERC20(asset), "asset"); + assertEq(lockup.getTranches(streamId), defaults.tranches(), "tranches"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_TRANCHED); + } +} diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree b/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree new file mode 100644 index 000000000..950c52191 --- /dev/null +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps-lt/createWithTimestampsLT.tree @@ -0,0 +1,34 @@ +CreateWithTimestampsLT_Integration_Concrete_Test +└── when asset contract + ├── when tranche count zero + │ └── it should revert + └── when tranche count not zero + ├── when tranche count exceeds max value + │ └── it should revert + └── when tranche count not exceed max value + ├── when tranche amounts sum overflows + │ └── it should revert + └── when tranche amounts sum not overflow + ├── when start time greater than first timestamp + │ └── it should revert + ├── when start time equals first timestamp + │ └── it should revert + └── when start time less than first timestamp + ├── when timestamps not strictly increasing + │ └── it should revert + └── when timestamps strictly increasing + ├── when deposit amount not equal tranche amounts sum + │ └── it should revert + └── when deposit amount equals tranche amounts sum + ├── when asset misses ERC20 return value + │ ├── it should create the stream + │ ├── it should bump the next stream ID + │ ├── it should mint the NFT + │ ├── it should emit {CreateLockupTranchedStream} and {MetadataUpdate} events + │ └── it should perform the ERC-20 transfers + └── when asset not miss ERC20 return value + ├── it should create the stream + ├── it should bump the next stream ID + ├── it should mint the NFT + ├── it should emit {CreateLockupTranchedStream} and {MetadataUpdate} events + └── it should perform the ERC-20 transfers \ No newline at end of file diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol deleted file mode 100644 index ad0ec2f15..000000000 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol +++ /dev/null @@ -1,391 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093.sol"; -import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { Address } from "@openzeppelin/contracts/utils/Address.sol"; -import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Errors } from "src/core/libraries/Errors.sol"; -import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../LockupTranched.t.sol"; - -contract CreateWithTimestampsLT_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Tranched_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } - - function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall( - ISablierLockup.createWithTimestampsLT, (defaults.createWithTimestamps(), defaults.tranches()) - ); - (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); - expectRevertDueToDelegateCall(success, returnData); - } - - function test_RevertWhen_SenderZeroAddress() external whenNoDelegateCall { - vm.expectRevert(Errors.SablierLockup_SenderZeroAddress.selector); - createDefaultStreamWithSenderLT(address(0)); - } - - function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { - address recipient = address(0); - vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipientLT(recipient); - } - - function test_RevertWhen_DepositAmountZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - { - // 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.SablierLockup_DepositAmountZero.selector); - uint128 totalAmount = 0; - createDefaultStreamWithTotalAmountLT(totalAmount); - } - - function test_RevertWhen_StartTimeZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - { - vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithStartTimeLT(0); - } - - function test_RevertWhen_TrancheCountZero() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - { - LockupTranched.Tranche[] memory tranches; - vm.expectRevert(Errors.SablierLockup_TrancheCountZero.selector); - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_TrancheCountExceedsMaxValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - { - uint256 trancheCount = defaults.MAX_COUNT() + 1; - LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); - tranches[trancheCount - 1].timestamp = defaults.END_TIME(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, trancheCount)); - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_TrancheAmountsSumOverflows() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - { - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - tranches[0].amount = MAX_UINT128; - tranches[1].amount = 1; - vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_StartTimeGreaterThanFirstTimestamp() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - { - // Change the timestamp of the first tranche. - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - tranches[0].timestamp = defaults.START_TIME() - 1 seconds; - - // Expect the relevant error to be thrown. - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, - defaults.START_TIME(), - tranches[0].timestamp - ) - ); - - // Create the stream. - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_StartTimeEqualsFirstTimestamp() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - { - // Change the timestamp of the first tranche. - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - tranches[0].timestamp = defaults.START_TIME(); - - // Expect the relevant error to be thrown. - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, - defaults.START_TIME(), - tranches[0].timestamp - ) - ); - - // Create the stream. - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_TimestampsNotStrictlyIncreasing() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - { - // Swap the tranche timestamps. - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - (tranches[0].timestamp, tranches[1].timestamp) = (tranches[1].timestamp, tranches[0].timestamp); - - // Expect the relevant error to be thrown. - uint256 index = 1; - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, - index, - tranches[0].timestamp, - tranches[1].timestamp - ) - ); - - // Create the stream. - createDefaultStreamWithTranchesLT(tranches); - } - - function test_RevertWhen_DepositAmountNotEqualTrancheAmountsSum() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTrancheTimestampsAreOrdered - { - resetPrank({ msgSender: users.sender }); - - // Adjust the default deposit amount. - uint128 defaultDepositAmount = defaults.DEPOSIT_AMOUNT(); - uint128 depositAmount = defaultDepositAmount + 100; - - // Prepare the params. - Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); - params.totalAmount = depositAmount; - - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - - // Expect the relevant error to be thrown. - vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockup_DepositAmountNotEqualToTrancheAmountsSum.selector, - depositAmount, - defaultDepositAmount - ) - ); - - // Create the stream. - lockup.createWithTimestampsLT(params, tranches); - } - - function test_RevertWhen_BrokerFeeExceedsMaxValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTrancheTimestampsAreOrdered - whenDepositAmountNotEqualTrancheAmountsSum - { - UD60x18 brokerFee = MAX_BROKER_FEE + ud(1); - vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) - ); - createDefaultStreamWithBrokerLT(Broker({ account: users.broker, fee: brokerFee })); - } - - function test_RevertWhen_AssetNotContract() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTrancheTimestampsAreOrdered - whenDepositAmountNotEqualTrancheAmountsSum - whenBrokerFeeNotExceedMaxValue - { - address nonContract = address(8128); - - resetPrank({ msgSender: users.sender }); - - // Run the test. - vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAssetLT(IERC20(nonContract)); - } - - function test_WhenAssetMissesERC20ReturnValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTrancheTimestampsAreOrdered - whenDepositAmountNotEqualTrancheAmountsSum - whenBrokerFeeNotExceedMaxValue - whenAssetContract - { - testCreateWithTimestamps(address(usdt)); - } - - function test_WhenAssetNotMissERC20ReturnValue() - external - whenNoDelegateCall - whenSenderNotZeroAddress - whenRecipientNotZeroAddress - whenDepositAmountNotZero - whenStartTimeNotZero - whenTrancheCountNotZero - whenTrancheCountNotExceedMaxValue - whenTrancheAmountsSumNotOverflow - whenStartTimeLessThanFirstTimestamp - whenTrancheTimestampsAreOrdered - whenDepositAmountNotEqualTrancheAmountsSum - whenBrokerFeeNotExceedMaxValue - whenAssetContract - { - testCreateWithTimestamps(address(dai)); - } - - /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. - function testCreateWithTimestamps(address asset) internal { - // Make the Sender the stream's funder. - address funder = users.sender; - - // It should perform the ERC-20 transfers. - expectCallToTransferFrom({ - asset: IERC20(asset), - from: funder, - to: address(lockup), - value: defaults.DEPOSIT_AMOUNT() - }); - - // Expect the broker fee to be paid to the broker. - expectCallToTransferFrom({ - asset: IERC20(asset), - from: funder, - to: users.broker, - value: defaults.BROKER_FEE_AMOUNT() - }); - - // It should emit {CreateLockupTranchedStream} and {MetadataUpdate} events. - vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CreateLockupTranchedStream({ - streamId: streamId, - funder: funder, - sender: users.sender, - recipient: users.recipient, - amounts: defaults.lockupCreateAmounts(), - tranches: defaults.tranches(), - asset: IERC20(asset), - cancelable: true, - transferable: true, - timestamps: defaults.lockupTranchedTimestamps(), - broker: users.broker - }); - - // It should create the stream. - streamId = createDefaultStreamWithAssetLT(IERC20(asset)); - - // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); - assertEq(lockup.getAsset(streamId), IERC20(asset), "asset"); - assertEq(lockup.getEndTime(streamId), defaults.END_TIME(), "endTime"); - assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); - assertEq(lockup.getSender(streamId), users.sender, "sender"); - assertEq(lockup.getStartTime(streamId), defaults.START_TIME(), "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getTranches(streamId), defaults.tranches(), "tranches"); - - // Assert that the stream's status is "PENDING". - Lockup.Status actualStatus = lockup.statusOf(streamId); - Lockup.Status expectedStatus = Lockup.Status.PENDING; - assertEq(actualStatus, expectedStatus); - - // It should bump the next stream ID. - uint256 actualNextStreamId = lockup.nextStreamId(); - uint256 expectedNextStreamId = streamId + 1; - assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - - // It should mint the NFT. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; - assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); - } -} diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree deleted file mode 100644 index f6e6393e4..000000000 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree +++ /dev/null @@ -1,54 +0,0 @@ -CreateWithTimestampsLT_Integration_Concrete_Test -├── when delegate call -│ └── it should revert -└── when no delegate call - ├── when sender zero address - │ └── it should revert - └── when sender not zero address - ├── when recipient zero address - │ └── it should revert - └── when recipient not zero address - ├── when deposit amount zero - │ └── it should revert - └── when deposit amount not zero - ├── when start time zero - │ └── it should revert - └── when start time not zero - ├── when tranche count zero - │ └── it should revert - └── when tranche count not zero - ├── when tranche count exceeds max value - │ └── it should revert - └── when tranche count not exceed max value - ├── when tranche amounts sum overflows - │ └── it should revert - └── when tranche amounts sum not overflow - ├── when start time greater than first timestamp - │ └── it should revert - ├── when start time equals first timestamp - │ └── it should revert - └── when start time less than first timestamp - ├── when timestamps not strictly increasing - │ └── it should revert - └── when timestamps strictly increasing - ├── when deposit amount not equal tranche amounts sum - │ └── it should revert - └── when deposit amount equals tranche amounts sum - ├── when broker fee exceeds max value - │ └── it should revert - └── when broker fee not exceed max value - ├── when asset not contract - │ └── it should revert - └── when asset contract - ├── when asset misses ERC20 return value - │ ├── it should create the stream - │ ├── it should bump the next stream ID - │ ├── it should mint the NFT - │ ├── it should emit {CreateLockupTranchedStream} and {MetadataUpdate} events - │ └── it should perform the ERC-20 transfers - └── when asset not miss ERC20 return value - ├── it should create the stream - ├── it should bump the next stream ID - ├── it should mint the NFT - ├── it should emit {CreateLockupTranchedStream} and {MetadataUpdate} events - └── it should perform the ERC-20 transfers 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 deleted file mode 100644 index f4586cdc7..000000000 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; - -import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; - -contract GetTimestamps_Lockup_Tranched_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { - function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getTimestamps(nullStreamId); - } - - function test_GivenNotNull() external { - Lockup.Timestamps memory actualTimestamps = lockup.getTimestamps(defaultStreamId); - Lockup.Timestamps memory expectedTimestamps = defaults.lockupTranchedTimestamps(); - assertEq(actualTimestamps, expectedTimestamps); - } -} diff --git a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree deleted file mode 100644 index 25af809be..000000000 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree +++ /dev/null @@ -1,5 +0,0 @@ -GetTimestamps_Lockup_Tranched_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - └── it should return the correct timestamps 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 6233a6c20..7929a439f 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 @@ -2,17 +2,27 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; -import { LockupTranched } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Concrete_Test } from "../LockupTranched.t.sol"; -contract GetTranches_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { +contract GetTranches_Integration_Concrete_Test is Lockup_Tranched_Integration_Concrete_Test { function test_RevertGiven_Null() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); - lockup.getTranches(nullStreamId); + expectRevert_Null({ callData: abi.encodeCall(lockup.getTranches, nullStreamId) }); } - function test_GivenNotNull() external { + function test_RevertGiven_NotTranchedModel() external givenNotNull { + lockupModel = Lockup.Model.LOCKUP_LINEAR; + uint256 streamId = createDefaultStream(); + vm.expectRevert( + abi.encodeWithSelector( + Errors.SablierLockup_NotExpectedModel.selector, Lockup.Model.LOCKUP_LINEAR, Lockup.Model.LOCKUP_TRANCHED + ) + ); + lockup.getTranches(streamId); + } + + function test_GivenTranchedModel() external givenNotNull { LockupTranched.Tranche[] memory actualTranches = lockup.getTranches(defaultStreamId); LockupTranched.Tranche[] memory expectedTranches = defaults.tranches(); assertEq(actualTranches, expectedTranches, "tranches"); diff --git a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree index 552166a59..e01036ecf 100644 --- a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree +++ b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree @@ -2,4 +2,7 @@ GetTranches_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null - └── it should return the correct tranches + ├── given not tranched model + │ └── it should revert + └── given tranched model + └── it should return the correct tranches diff --git a/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol index fcff6997c..829369963 100644 --- a/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.t.sol @@ -3,14 +3,14 @@ pragma solidity >=0.8.22 <0.9.0; import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup-base/streamed-amount-of/streamedAmountOf.t.sol"; -import { Lockup_Tranched_Integration_Shared_Test, Integration_Test } from "./../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Concrete_Test, Integration_Test } from "./../LockupTranched.t.sol"; contract StreamedAmountOf_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, StreamedAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { 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 a6704c4d8..06f85eb0a 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 @@ -7,7 +7,7 @@ import { console2 } from "forge-std/src/console2.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { Base64 } from "solady/src/utils/Base64.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Integration_Test } from "../LockupTranched.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,7 +16,7 @@ import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol /// - The contract deployer, i.e. the `sender` config option in `foundry.toml`, must have the default value /// 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38 so that the deployed contracts have the same addresses as /// the values hard coded in the tests below -contract TokenURI_Lockup_Tranched_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { +contract TokenURI_Lockup_Tranched_Integration_Concrete_Test is Integration_Test { address internal constant LOCKUP = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; /// @dev To make these tests noninvasive, they are run only when the contract address matches the hard coded value. 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 ebb883009..8c717a5fb 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 @@ -3,14 +3,14 @@ pragma solidity >=0.8.22 <0.9.0; import { WithdrawableAmountOf_Integration_Concrete_Test } from "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { Lockup_Tranched_Integration_Shared_Test, Integration_Test } from "./../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Concrete_Test, Integration_Test } from "./../LockupTranched.t.sol"; contract WithdrawableAmountOf_Lockup_Tranched_Integration_Concrete_Test is - Lockup_Tranched_Integration_Shared_Test, + Lockup_Tranched_Integration_Concrete_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Concrete_Test, Integration_Test) { + Lockup_Tranched_Integration_Concrete_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { diff --git a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol index e9b801222..68b24754d 100644 --- a/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol +++ b/test/core/integration/concrete/nft-descriptor/generateAccentColor.t.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract GenerateAccentColor_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { +contract GenerateAccentColor_Integration_Concrete_Test is Base_Test { function test_GenerateAccentColor() external view { // 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%)"; + string memory expectedColor = "hsl(225,28%,77%)"; assertEq(actualColor, expectedColor, "accentColor"); } } diff --git a/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol b/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol index e4b191652..6b2d6704c 100644 --- a/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol +++ b/test/core/integration/concrete/nft-descriptor/is-allowed-character/IsAllowedCharacter.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract IsAllowedCharacter_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { +contract IsAllowedCharacter_Integration_Concrete_Test is Base_Test { function test_WhenEmptyString() external view { string memory symbol = ""; bool result = nftDescriptorMock.isAllowedCharacter_(symbol); 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 57d67c82c..5f81def48 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 @@ -6,9 +6,9 @@ import { MockERC721 } from "forge-std/src/mocks/MockERC721.sol"; import { Errors } from "src/core/libraries/Errors.sol"; -import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { +contract MapSymbol_Integration_Concrete_Test is Base_Test { function test_RevertGiven_UnknownNFTContract() external { MockERC721 nft = new MockERC721(); nft.initialize("Foo", "FOO"); diff --git a/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol b/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol index efa588cb7..c187c7580 100644 --- a/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol +++ b/test/core/integration/concrete/nft-descriptor/safe-asset-decimals/safeAssetDecimals.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Shared_Test } from "../../../shared/nft-descriptor/NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract SafeAssetDecimals_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { +contract SafeAssetDecimals_Integration_Concrete_Test is Base_Test { function test_WhenAssetNotContract() external view { address eoa = vm.addr({ privateKey: 1 }); uint8 actualDecimals = nftDescriptorMock.safeAssetDecimals_(address(eoa)); 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 24ab4b41b..b2810a3dd 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,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { Base_Test } from "test/Base.t.sol"; import { ERC20Bytes32 } from "test/mocks/erc20/ERC20Bytes32.sol"; import { ERC20Mock } from "test/mocks/erc20/ERC20Mock.sol"; -import { NFTDescriptor_Integration_Shared_Test } from "./../../../shared/nft-descriptor/NFTDescriptor.t.sol"; -contract SafeAssetSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared_Test { +contract SafeAssetSymbol_Integration_Concrete_Test is Base_Test { function test_WhenAssetNotContract() external view { address eoa = vm.addr({ privateKey: 1 }); string memory actualSymbol = nftDescriptorMock.safeAssetSymbol_(address(eoa)); diff --git a/test/core/integration/fuzz/lockup-base/cancel.t.sol b/test/core/integration/fuzz/lockup-base/cancel.t.sol index 67ccc4625..853866c6f 100644 --- a/test/core/integration/fuzz/lockup-base/cancel.t.sol +++ b/test/core/integration/fuzz/lockup-base/cancel.t.sol @@ -4,9 +4,10 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; +import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { Integration_Test } from "../../Integration.t.sol"; +import { Integration_Test } from "./../../Integration.t.sol"; abstract contract Cancel_Integration_Fuzz_Test is Integration_Test { function testFuzz_Cancel_StatusPending(uint256 timeJump) @@ -78,8 +79,17 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test { uint128 senderAmount = lockup.refundableAmountOf(recipientGoodStreamId); expectCallToTransfer({ to: users.sender, value: senderAmount }); - // Expect the relevant events to be emitted. + // Expect the recipient to be called. uint128 recipientAmount = lockup.withdrawableAmountOf(recipientGoodStreamId); + vm.expectCall( + address(recipientGood), + abi.encodeCall( + ISablierLockupRecipient.onSablierLockupCancel, + (recipientGoodStreamId, users.sender, senderAmount, recipientAmount) + ) + ); + + // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockupBase.CancelLockupStream( recipientGoodStreamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount diff --git a/test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol b/test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol deleted file mode 100644 index 5372c1a8c..000000000 --- a/test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol +++ /dev/null @@ -1,103 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Solarray } from "solarray/src/Solarray.sol"; - -import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; - -import { Lockup_Integration_Shared_Test } from "../../shared/lockup/Lockup.t.sol"; - -abstract contract CancelMultiple_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - Lockup.Model internal lockupModel; - // The original time when the tests started. - uint40 internal originalTime; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - originalTime = getBlockTimestamp(); - } - - function testFuzz_CancelMultiple( - uint256 timeJump, - uint40 endTime - ) - external - whenNoDelegateCall - givenNotNull - givenNoColdStreams - whenCallerAuthorizedForAllStreams - givenAllStreamsCancelable - { - timeJump = _bound(timeJump, 0 seconds, defaults.TOTAL_DURATION() - 1 seconds); - endTime = boundUint40(endTime, defaults.END_TIME(), defaults.END_TIME() + defaults.TOTAL_DURATION()); - - // Create a new stream with a different end time. - uint256 streamId; - if (lockupModel == Lockup.Model.LOCKUP_LINEAR) { - streamId = createDefaultStreamWithEndTimeLL(endTime); - } else if (lockupModel == Lockup.Model.LOCKUP_DYNAMIC) { - streamId = createDefaultStreamWithEndTimeLD(endTime); - } else if (lockupModel == Lockup.Model.LOCKUP_TRANCHED) { - streamId = createDefaultStreamWithEndTimeLT(endTime); - } - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - - // Create the stream IDs array. - uint256[] memory streamIds = Solarray.uint256s(cancelMultipleStreamIds[0], streamId); - - // Expect the assets to be refunded to the Sender. - uint128 senderAmount0 = lockup.refundableAmountOf(streamIds[0]); - expectCallToTransfer({ to: users.sender, value: senderAmount0 }); - uint128 senderAmount1 = lockup.refundableAmountOf(streamIds[1]); - expectCallToTransfer({ to: users.sender, value: senderAmount1 }); - - // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockupBase.CancelLockupStream({ - streamId: streamIds[0], - sender: users.sender, - recipient: users.recipient, - asset: dai, - senderAmount: senderAmount0, - recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 - }); - vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockupBase.CancelLockupStream({ - streamId: streamIds[1], - sender: users.sender, - recipient: users.recipient, - asset: dai, - senderAmount: senderAmount1, - recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount1 - }); - - // Cancel the streams. - lockup.cancelMultiple(streamIds); - - // Assert that the streams have been updated. - Lockup.Status expectedStatus0 = - senderAmount0 == defaults.DEPOSIT_AMOUNT() ? Lockup.Status.DEPLETED : Lockup.Status.CANCELED; - Lockup.Status expectedStatus1 = - senderAmount1 == defaults.DEPOSIT_AMOUNT() ? Lockup.Status.DEPLETED : Lockup.Status.CANCELED; - assertEq(lockup.statusOf(streamIds[0]), expectedStatus0, "status0"); - assertEq(lockup.statusOf(streamIds[1]), expectedStatus1, "status1"); - - // Assert that the streams are not cancelable anymore. - assertFalse(lockup.isCancelable(streamIds[0]), "isCancelable0"); - assertFalse(lockup.isCancelable(streamIds[1]), "isCancelable1"); - - // Assert that the refunded amounts have been updated. - uint128 expectedRefundedAmount0 = senderAmount0; - uint128 expectedRefundedAmount1 = senderAmount1; - assertEq(lockup.getRefundedAmount(streamIds[0]), expectedRefundedAmount0, "refundedAmount0"); - assertEq(lockup.getRefundedAmount(streamIds[1]), expectedRefundedAmount1, "refundedAmount1"); - - // Assert that the NFTs have not been burned. - 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-base/getWithdrawnAmount.t.sol b/test/core/integration/fuzz/lockup-base/getWithdrawnAmount.t.sol deleted file mode 100644 index 3573287b5..000000000 --- a/test/core/integration/fuzz/lockup-base/getWithdrawnAmount.t.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Integration_Test } from "../../Integration.t.sol"; - -abstract contract GetWithdrawnAmount_Integration_Fuzz_Test is Integration_Test { - function testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256 timeJump) external givenNotNull { - timeJump = _bound(timeJump, 0 seconds, defaults.TOTAL_DURATION() * 2); - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = 0; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); - } - - function testFuzz_GetWithdrawnAmount( - uint256 timeJump, - uint128 withdrawAmount - ) - external - givenNotNull - givenPreviousWithdrawal - { - timeJump = _bound(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() - 1 seconds); - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - - // Bound the withdraw amount. - uint128 streamedAmount = lockup.streamedAmountOf(defaultStreamId); - withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); - - // Make the withdrawal. - lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); - - // Assert that the withdrawn amount has been updated. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(defaultStreamId); - uint128 expectedWithdrawnAmount = withdrawAmount; - assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); - } -} diff --git a/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol index 0e0db13b1..c8ebf6c9c 100644 --- a/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol @@ -6,7 +6,7 @@ import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; -abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { +contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { function testFuzz_WithdrawMax_EndTimeNotInFuture(uint256 timeJump) external { timeJump = _bound(timeJump, defaults.TOTAL_DURATION(), defaults.TOTAL_DURATION() * 2); diff --git a/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol index 033286ff7..e15e3b921 100644 --- a/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol @@ -7,12 +7,11 @@ import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Integration_Test } from "../../Integration.t.sol"; -abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Test { +contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - New recipient same and different from the current one /// - Withdrawable amount zero and not zero - function testFuzz_WithdrawMaxAndTransfer( uint256 timeJump, address newRecipient diff --git a/test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol deleted file mode 100644 index 1a478dbb7..000000000 --- a/test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol +++ /dev/null @@ -1,101 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; - -import { Lockup_Integration_Shared_Test } from "../../shared/lockup/Lockup.t.sol"; - -abstract contract WithdrawMultiple_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - address internal caller; - Lockup.Model internal lockupModel; - // The original time when the tests started. - uint40 internal originalTime; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - originalTime = getBlockTimestamp(); - } - - function testFuzz_WithdrawMultiple( - uint256 timeJump, - uint128 ongoingWithdrawAmount - ) - external - whenNoDelegateCall - whenArraysEqual - givenNotNull - givenNoDEPLETEDStreams - whenCallerAuthorizedForAllStreams - whenWithdrawalAddressNotZero - whenNoZeroAmounts - whenNoAmountOverdraws - { - timeJump = _bound(timeJump, defaults.TOTAL_DURATION(), defaults.TOTAL_DURATION() * 2 - 1 seconds); - - // Create a new stream with an end time double that of the default stream. - uint40 ongoingEndTime = defaults.END_TIME() + defaults.TOTAL_DURATION(); - - // Create a new stream with ongoing end time. - uint256 ongoingStreamId; - if (lockupModel == Lockup.Model.LOCKUP_LINEAR) { - ongoingStreamId = createDefaultStreamWithEndTimeLL(ongoingEndTime); - } else if (lockupModel == Lockup.Model.LOCKUP_DYNAMIC) { - ongoingStreamId = createDefaultStreamWithEndTimeLD(ongoingEndTime); - } else if (lockupModel == Lockup.Model.LOCKUP_TRANCHED) { - ongoingStreamId = createDefaultStreamWithEndTimeLT(ongoingEndTime); - } - - // Create and use a default stream as the settled stream. - uint256 settledStreamId = createDefaultStreamLD(); - uint128 settledWithdrawAmount = defaults.DEPOSIT_AMOUNT(); - - // Run the test with the caller provided in {whenCallerAuthorizedForAllStreams}. - resetPrank({ msgSender: caller }); - - // Simulate the passage of time. - vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - - // Bound the ongoing withdraw amount. - uint128 ongoingWithdrawableAmount = lockup.withdrawableAmountOf(ongoingStreamId); - ongoingWithdrawAmount = boundUint128(ongoingWithdrawAmount, 1, ongoingWithdrawableAmount); - - // Expect the withdrawals to be made. - 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 ISablierLockupBase.WithdrawFromLockupStream({ - streamId: ongoingStreamId, - to: users.recipient, - asset: dai, - amount: ongoingWithdrawAmount - }); - vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockupBase.WithdrawFromLockupStream({ - streamId: settledStreamId, - to: users.recipient, - asset: dai, - amount: settledWithdrawAmount - }); - - // Make the withdrawals. - uint256[] memory streamIds = Solarray.uint256s(ongoingStreamId, settledStreamId); - uint128[] memory amounts = Solarray.uint128s(ongoingWithdrawAmount, settledWithdrawAmount); - lockup.withdrawMultiple(streamIds, amounts); - - // Assert that the statuses have been updated. - assertEq(lockup.statusOf(streamIds[0]), Lockup.Status.STREAMING, "status0"); - assertEq(lockup.statusOf(streamIds[1]), Lockup.Status.DEPLETED, "status1"); - - // Assert that the withdrawn amounts have been updated. - assertEq(lockup.getWithdrawnAmount(streamIds[0]), amounts[0], "withdrawnAmount0"); - 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"); - } -} diff --git a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index b95b0e975..38ebbe669 100644 --- a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,98 +1,21 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup } from "src/core/types/DataTypes.sol"; -import { Integration_Test } from "./../../shared/lockup/Lockup.t.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; +import { Integration_Test } from "./../../Integration.t.sol"; import { Cancel_Integration_Fuzz_Test } from "./../lockup-base/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "./../lockup-base/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "./../lockup-base/getWithdrawnAmount.t.sol"; import { RefundableAmountOf_Integration_Fuzz_Test } from "./../lockup-base/refundableAmountOf.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "./../lockup-base/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "./../lockup-base/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "./../lockup-base/withdrawMultiple.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract Cancel_Lockup_Dynamic_Integration_Fuzz_Test is - Lockup_Dynamic_Integration_Shared_Test, - Cancel_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Dynamic_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { - modifier whenCallerAuthorizedForAllStreams() override { - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLD({ warpTime: originalTime }); - _; - } - +contract Cancel_Lockup_Dynamic_Integration_Fuzz_Test is Cancel_Integration_Fuzz_Test { function setUp() public virtual override { - CancelMultiple_Integration_Fuzz_Test.setUp(); - lockupModel = Lockup.Model.LOCKUP_DYNAMIC; - } -} - -contract GetWithdrawnAmount_Lockup_Dynamic_Integration_Fuzz_Test is - Lockup_Dynamic_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract RefundableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is - Lockup_Dynamic_Integration_Shared_Test, - RefundableAmountOf_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); + Integration_Test.setUp(); } } -contract WithdrawMax_Lockup_Dynamic_Integration_Fuzz_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawMax_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMaxAndTransfer_Lockup_Dynamic_Integration_Fuzz_Test is - Lockup_Dynamic_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Dynamic_Integration_Fuzz_Test is WithdrawMultiple_Integration_Fuzz_Test { - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: originalTime }); - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: originalTime }); - caller = users.operator; - _; - } - +contract RefundableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is RefundableAmountOf_Integration_Fuzz_Test { function setUp() public virtual override { - WithdrawMultiple_Integration_Fuzz_Test.setUp(); - lockupModel = Lockup.Model.LOCKUP_DYNAMIC; + Integration_Test.setUp(); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol index 94503e435..0c159ebb0 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol @@ -3,16 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Integration_Test } from "./../../Integration.t.sol"; +contract CreateWithDurationsLD_Integration_Fuzz_Test is Integration_Test { struct Vars { uint256 actualNextStreamId; address actualNFTOwner; @@ -46,10 +39,12 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Share // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); + // 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 {SablierLockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -61,14 +56,13 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Share vars.segmentsWithTimestamps = getSegmentsWithTimestamps(segments); Lockup.Timestamps memory timestamps = Lockup.Timestamps({ start: getBlockTimestamp(), - cliff: 0, end: vars.segmentsWithTimestamps[vars.segmentsWithTimestamps.length - 1].timestamp }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupDynamicStream({ - streamId: streamId, + streamId: expectedStreamId, funder: vars.funder, sender: users.sender, recipient: users.recipient, @@ -82,10 +76,9 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Share }); // Create the stream. - Lockup.CreateWithDurations memory params = defaults.createWithDurations(); - params.totalAmount = vars.totalAmount; - params.transferable = true; - lockup.createWithDurationsLD(params, segments); + _defaultParams.createWithDurations.totalAmount = vars.totalAmount; + _defaultParams.createWithDurations.transferable = true; + uint256 streamId = lockup.createWithDurationsLD(_defaultParams.createWithDurations, segments); // 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. @@ -97,14 +90,15 @@ contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Share assertEq(lockup.getAsset(streamId), dai, "asset"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); assertEq(lockup.getSegments(streamId), vars.segmentsWithTimestamps, "segments"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC); // Assert that the stream's status is correct. vars.actualStatus = lockup.statusOf(streamId); diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol index 63fb20781..70d720f96 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol @@ -6,16 +6,9 @@ import { stdError } from "forge-std/src/StdError.sol"; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Integration_Test } from "./../../Integration.t.sol"; +contract CreateWithTimestampsLD_Integration_Fuzz_Test is Integration_Test { function testFuzz_RevertWhen_SegmentCountTooHigh(uint256 segmentCount) external whenNoDelegateCall @@ -27,8 +20,8 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar uint256 defaultMax = defaults.MAX_COUNT(); segmentCount = _bound(segmentCount, defaultMax + 1, defaultMax * 2); LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, segmentCount)); - createDefaultStreamWithSegmentsLD(segments); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_SegmentCountTooHigh.selector, segmentCount)); + lockup.createWithTimestampsLD(_defaultParams.createWithTimestamps, segments); } function testFuzz_RevertWhen_SegmentAmountsSumOverflows( @@ -45,11 +38,10 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar { amount0 = boundUint128(amount0, MAX_UINT128 / 2 + 1, MAX_UINT128); amount1 = boundUint128(amount0, MAX_UINT128 / 2 + 1, MAX_UINT128); - LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].amount = amount0; - segments[1].amount = amount1; + _defaultParams.segments[0].amount = amount0; + _defaultParams.segments[1].amount = amount1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithSegmentsLD(segments); + createDefaultStream(); } function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentTimestamp(uint40 firstTimestamp) @@ -65,20 +57,17 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar firstTimestamp = boundUint40(firstTimestamp, 0, defaults.START_TIME()); // Change the timestamp of the first segment. - LockupDynamic.Segment[] memory segments = defaults.segments(); - segments[0].timestamp = firstTimestamp; + _defaultParams.segments[0].timestamp = firstTimestamp; // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), - segments[0].timestamp + _defaultParams.segments[0].timestamp ) ); - - // Create the stream. - createDefaultStreamWithSegmentsLD(segments); + createDefaultStream(); } function testFuzz_RevertWhen_DepositAmountNotEqualToSegmentAmountsSum(uint128 depositDiff) @@ -102,21 +91,18 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); - params.totalAmount = depositAmount; - LockupDynamic.Segment[] memory segments = defaults.segments(); + _defaultParams.createWithTimestamps.totalAmount = depositAmount; + _defaultParams.createWithTimestamps.broker = defaults.brokerNull(); // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierHelpers_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) ); - - // Create the stream. - lockup.createWithTimestampsLD(params, segments); + createDefaultStream(); } function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) @@ -134,10 +120,11 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar { vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); + _defaultParams.createWithTimestamps.broker = broker; vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierHelpers_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBrokerLD(broker); + createDefaultStream(); } struct Vars { @@ -190,27 +177,34 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar ); vm.assume(segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); + + params.asset = dai; + params.timestamps.start = boundUint40(params.timestamps.start, 1, defaults.START_TIME()); params.transferable = true; // Fuzz the segment timestamps. - fuzzSegmentTimestamps(segments, params.startTime); + fuzzSegmentTimestamps(segments, params.timestamps.start); + params.timestamps.end = segments[segments.length - 1].timestamp; // Fuzz the segment amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: params.broker.fee }); + params.totalAmount = vars.totalAmount; + // Make the fuzzed funder the caller in the rest of this test. resetPrank(funder); + uint256 expectedStreamId = lockup.nextStreamId(); + // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierLockupDynamic} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -220,10 +214,8 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - Lockup.Timestamps memory timestamps = - Lockup.Timestamps({ start: params.startTime, cliff: 0, end: segments[segments.length - 1].timestamp }); emit ISablierLockup.CreateLockupDynamicStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: params.sender, recipient: params.recipient, @@ -231,26 +223,13 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar asset: dai, cancelable: params.cancelable, transferable: params.transferable, + timestamps: params.timestamps, segments: segments, - timestamps: timestamps, broker: params.broker.account }); // Create the stream. - lockup.createWithTimestampsLD( - Lockup.CreateWithTimestamps({ - sender: params.sender, - recipient: params.recipient, - totalAmount: vars.totalAmount, - asset: dai, - cancelable: params.cancelable, - transferable: params.transferable, - startTime: params.startTime, - endTime: segments[segments.length - 1].timestamp, - broker: params.broker - }), - segments - ); + uint256 streamId = lockup.createWithTimestampsLD(params, segments); // 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. @@ -260,20 +239,21 @@ contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shar // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); assertEq(lockup.getAsset(streamId), dai, "asset"); - assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); + assertEq(lockup.getEndTime(streamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), params.recipient, "recipient"); assertEq(lockup.getSender(streamId), params.sender, "sender"); - assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getStartTime(streamId), params.timestamps.start, "startTime"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); assertEq(lockup.getSegments(streamId), segments, "segments"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_DYNAMIC); // Assert that the stream's status is correct. vars.actualStatus = lockup.statusOf(streamId); - if (params.startTime > getBlockTimestamp()) { + if (params.timestamps.start > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { vars.expectedStatus = Lockup.Status.SETTLED; diff --git a/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 5ab9c490a..9304cd93b 100644 --- a/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; +import { Integration_Test } from "./../../Integration.t.sol"; -contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Integration_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -37,7 +37,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic // Create the stream with the fuzzed segment. Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = segment.amount; - params.endTime = segment.timestamp; + params.timestamps.end = segment.timestamp; uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Simulate the passage of time. @@ -89,7 +89,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic // Create the stream with the fuzzed segments. Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = totalAmount; - params.endTime = segments[segments.length - 1].timestamp; + params.timestamps.end = segments[segments.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Simulate the passage of time. @@ -136,7 +136,7 @@ contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic // Create the stream with the fuzzed segments. Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = totalAmount; - params.endTime = segments[segments.length - 1].timestamp; + params.timestamps.end = segments[segments.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Warp to the future for the first time. diff --git a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index a305c6f00..8d9690a55 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -2,23 +2,15 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; + import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; + import { Withdraw_Integration_Fuzz_Test } from "./../lockup-base/withdraw.t.sol"; /// @dev This contract complements the tests in {Withdraw_Integration_Fuzz_Test} by testing the withdraw function -/// against -/// streams created with fuzzed segments. -contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is - Withdraw_Integration_Fuzz_Test, - Lockup_Dynamic_Integration_Shared_Test -{ - function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { - Lockup_Dynamic_Integration_Shared_Test.setUp(); - } - +/// against streams created with fuzzed segments. +contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is Withdraw_Integration_Fuzz_Test { struct Params { LockupDynamic.Segment[] segments; uint256 timeJump; @@ -75,7 +67,7 @@ contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is // Create the stream with the fuzzed segments. Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestamps(); createParams.totalAmount = vars.totalAmount; - createParams.endTime = params.segments[params.segments.length - 1].timestamp; + createParams.timestamps.end = params.segments[params.segments.length - 1].timestamp; vars.streamId = lockup.createWithTimestampsLD(createParams, params.segments); diff --git a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index f066d14e4..565a9c251 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; +import { Integration_Test } from "./../../Integration.t.sol"; -contract WithdrawableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Integration_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past diff --git a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol index cded1d063..133710578 100644 --- a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -2,108 +2,48 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; + import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; import { Cancel_Integration_Fuzz_Test } from "./../lockup-base/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "./../lockup-base/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "./../lockup-base/getWithdrawnAmount.t.sol"; import { RefundableAmountOf_Integration_Fuzz_Test } from "./../lockup-base/refundableAmountOf.t.sol"; import { Withdraw_Integration_Fuzz_Test } from "./../lockup-base/withdraw.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "./../lockup-base/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "./../lockup-base/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "./../lockup-base/withdrawMultiple.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract Cancel_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, - Cancel_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Linear_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { - modifier whenCallerAuthorizedForAllStreams() override { - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLL({ warpTime: originalTime }); - _; - } - +contract Lockup_Linear_Integration_Fuzz_Test is Integration_Test { function setUp() public virtual override { - CancelMultiple_Integration_Fuzz_Test.setUp(); + Integration_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_LINEAR; + createDefaultStreamIds(); } } -contract GetWithdrawnAmount_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Fuzz_Test +contract Cancel_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Fuzz_Test, + Cancel_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Fuzz_Test, Integration_Test) { + Lockup_Linear_Integration_Fuzz_Test.setUp(); } } contract RefundableAmountOf_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Fuzz_Test, RefundableAmountOf_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Fuzz_Test, Integration_Test) { + Lockup_Linear_Integration_Fuzz_Test.setUp(); } } contract Withdraw_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, + Lockup_Linear_Integration_Fuzz_Test, Withdraw_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMax_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawMax_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMaxAndTransfer_Lockup_Linear_Integration_Fuzz_Test is - Lockup_Linear_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { - Lockup_Linear_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Linear_Integration_Fuzz_Test is WithdrawMultiple_Integration_Fuzz_Test { - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: originalTime }); - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: originalTime }); - caller = users.operator; - _; - } - - function setUp() public virtual override { - WithdrawMultiple_Integration_Fuzz_Test.setUp(); - lockupModel = Lockup.Model.LOCKUP_LINEAR; + function setUp() public virtual override(Lockup_Linear_Integration_Fuzz_Test, Integration_Test) { + Lockup_Linear_Integration_Fuzz_Test.setUp(); } } diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol index b9167e80a..59e2e1493 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol @@ -5,16 +5,9 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Lockup_Linear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; +contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Linear_Integration_Fuzz_Test { function testFuzz_RevertWhen_TotalDurationCalculationOverflows(LockupLinear.Durations memory durations) external whenNoDelegateCall @@ -34,11 +27,12 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Share // Expect the relevant error to be thrown. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) + abi.encodeWithSelector(Errors.SablierHelpers_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); // Create the stream. - createDefaultStreamWithDurationsLL(durations); + _defaultParams.durations = durations; + createDefaultStreamWithDurations(); } function testFuzz_CreateWithDurationsLL(LockupLinear.Durations memory durations) @@ -52,24 +46,27 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Share // Make the Sender the stream's funder (recall that the Sender is the default caller). address funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); - // Expect the assets to be transferred from the funder to {SablierLockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Expect the broker fee to be paid to the broker. expectCallToTransferFrom({ from: funder, to: users.broker, value: defaults.BROKER_FEE_AMOUNT() }); // Create the timestamps struct by calculating the start time, cliff time and the end time. - Lockup.Timestamps memory timestamps = Lockup.Timestamps({ - start: getBlockTimestamp(), - cliff: durations.cliff == 0 ? 0 : getBlockTimestamp() + durations.cliff, - end: getBlockTimestamp() + durations.total - }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: getBlockTimestamp(), end: getBlockTimestamp() + durations.total }); + + uint40 cliffTime; + if (durations.cliff > 0) { + cliffTime = getBlockTimestamp() + durations.cliff; + } // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupLinearStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: users.sender, recipient: users.recipient, @@ -78,25 +75,28 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Share cancelable: true, transferable: true, timestamps: timestamps, + cliffTime: cliffTime, broker: users.broker }); // Create the stream. - createDefaultStreamWithDurationsLL(durations); + _defaultParams.durations = durations; + uint256 streamId = createDefaultStreamWithDurations(); // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), defaults.DEPOSIT_AMOUNT(), "depositedAmount"); assertEq(lockup.getAsset(streamId), dai, "asset"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), true, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getCliffTime(streamId), timestamps.cliff, "cliff"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); + assertEq(lockup.getCliffTime(streamId), cliffTime, "cliffTime"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_LINEAR); // Assert that the stream's status is "STREAMING". Lockup.Status actualStatus = lockup.statusOf(streamId); @@ -107,10 +107,5 @@ contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Share uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); - - // Assert that the NFT has been minted. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - address expectedNFTOwner = users.recipient; - assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol index 29ff5ec53..efe64ed05 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol @@ -7,16 +7,9 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Lockup_Linear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; +contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Linear_Integration_Fuzz_Test { function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) external whenNoDelegateCall @@ -27,9 +20,11 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierHelpers_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBrokerLL(broker); + + _defaultParams.createWithTimestamps.broker = broker; + lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, _defaultParams.cliffTime); } function testFuzz_RevertWhen_StartTimeNotLessThanCliffTime(uint40 startTime) @@ -40,12 +35,14 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar whenDepositAmountNotZero { startTime = boundUint40(startTime, defaults.CLIFF_TIME() + 1 seconds, defaults.END_TIME() - 1 seconds); + _defaultParams.createWithTimestamps.timestamps.start = startTime; + vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() + Errors.SablierHelpers_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() ) ); - createDefaultStreamWithStartTimeLL(startTime); + lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, _defaultParams.cliffTime); } function testFuzz_RevertWhen_CliffTimeNotLessThanEndTime( @@ -62,13 +59,19 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar endTime = boundUint40(endTime, startTime + 1 seconds, startTime + 2 weeks); cliffTime = boundUint40(cliffTime, endTime, MAX_UNIX_TIMESTAMP); + _defaultParams.createWithTimestamps.timestamps.start = startTime; + _defaultParams.createWithTimestamps.timestamps.end = endTime; + vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) + abi.encodeWithSelector(Errors.SablierHelpers_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); - createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); + + lockup.createWithTimestampsLL(_defaultParams.createWithTimestamps, cliffTime); } struct Vars { + uint256 expectedStreamId; + uint256 actualStreamId; uint256 actualNextStreamId; address actualNFTOwner; Lockup.Status actualStatus; @@ -111,16 +114,18 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar && params.broker.account != address(0) ); vm.assume(params.totalAmount != 0); - params.startTime = boundUint40(params.startTime, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); + params.timestamps.start = + boundUint40(params.timestamps.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.transferable = true; // The cliff time must be either zero or greater than the start time. if (cliffTime > 0) { - cliffTime = boundUint40(cliffTime, params.startTime + 1 seconds, params.startTime + 52 weeks); - params.endTime = boundUint40(params.endTime, cliffTime + 1 seconds, MAX_UNIX_TIMESTAMP); + cliffTime = boundUint40(cliffTime, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks); + params.timestamps.end = boundUint40(params.timestamps.end, cliffTime + 1 seconds, MAX_UNIX_TIMESTAMP); } else { - params.endTime = boundUint40(params.endTime, params.startTime + 1 seconds, MAX_UNIX_TIMESTAMP); + params.timestamps.end = + boundUint40(params.timestamps.end, params.timestamps.start + 1 seconds, MAX_UNIX_TIMESTAMP); } // Calculate the fee amounts and the deposit amount. @@ -131,14 +136,15 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar // Make the fuzzed funder the caller in this test. resetPrank(funder); + vars.expectedStreamId = lockup.nextStreamId(); // Mint enough assets to the funder. deal({ token: address(dai), to: funder, give: params.totalAmount }); - // Approve {SablierLockupLinear} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockupLinear}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -149,7 +155,7 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupLinearStream({ - streamId: streamId, + streamId: vars.expectedStreamId, funder: funder, sender: params.sender, recipient: params.recipient, @@ -157,53 +163,40 @@ contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shar asset: dai, cancelable: params.cancelable, transferable: params.transferable, - timestamps: Lockup.Timestamps({ start: params.startTime, cliff: cliffTime, end: params.endTime }), + timestamps: Lockup.Timestamps({ start: params.timestamps.start, end: params.timestamps.end }), + cliffTime: cliffTime, broker: params.broker.account }); + params.asset = dai; + // Create the stream. - lockup.createWithTimestampsLL( - Lockup.CreateWithTimestamps({ - sender: params.sender, - recipient: params.recipient, - totalAmount: params.totalAmount, - asset: dai, - cancelable: params.cancelable, - transferable: params.transferable, - startTime: params.startTime, - endTime: params.endTime, - broker: params.broker - }), - cliffTime - ); + vars.actualStreamId = lockup.createWithTimestampsLL(params, cliffTime); // It should create the stream. - assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); - assertEq(lockup.getAsset(streamId), dai, "asset"); - assertEq(lockup.getEndTime(streamId), params.endTime, "endTime"); - assertEq(lockup.isCancelable(streamId), params.cancelable, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), params.recipient, "recipient"); - assertEq(lockup.getSender(streamId), params.sender, "sender"); - assertEq(lockup.getStartTime(streamId), params.startTime, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); - assertEq(lockup.getCliffTime(streamId), cliffTime, "cliff"); + assertEq(lockup.getDepositedAmount(vars.actualStreamId), vars.createAmounts.deposit, "depositedAmount"); + assertEq(lockup.getAsset(vars.actualStreamId), dai, "asset"); + assertEq(lockup.getEndTime(vars.actualStreamId), params.timestamps.end, "endTime"); + assertEq(lockup.isCancelable(vars.actualStreamId), params.cancelable, "isCancelable"); + assertFalse(lockup.isDepleted(vars.actualStreamId), "isDepleted"); + assertTrue(lockup.isStream(vars.actualStreamId), "isStream"); + assertTrue(lockup.isTransferable(vars.actualStreamId), "isTransferable"); + assertEq(lockup.getRecipient(vars.actualStreamId), params.recipient, "recipient"); + assertEq(lockup.getSender(vars.actualStreamId), params.sender, "sender"); + assertEq(lockup.getStartTime(vars.actualStreamId), params.timestamps.start, "startTime"); + assertFalse(lockup.wasCanceled(vars.actualStreamId), "wasCanceled"); + assertEq(lockup.getCliffTime(vars.actualStreamId), cliffTime, "cliff"); + assertEq(lockup.getLockupModel(vars.actualStreamId), Lockup.Model.LOCKUP_LINEAR); // Assert that the stream's status is correct. - vars.actualStatus = lockup.statusOf(streamId); - vars.expectedStatus = params.startTime > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + vars.actualStatus = lockup.statusOf(vars.actualStreamId); + vars.expectedStatus = + params.timestamps.start > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. vars.actualNextStreamId = lockup.nextStreamId(); - vars.expectedNextStreamId = streamId + 1; + vars.expectedNextStreamId = vars.actualStreamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); - - // Assert that the NFT has been minted. - vars.actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); - vars.expectedNFTOwner = params.recipient; - assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } } diff --git a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol index 88ce9a5b9..5dea8e436 100644 --- a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; -contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Fuzz_Test { function testFuzz_StreamedAmountOf_CliffTimeInFuture(uint40 timeJump) external givenNotNull diff --git a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index 97f3b5bff..600905f1d 100644 --- a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Fuzz_Test } from "./LockupLinear.t.sol"; -contract WithdrawableAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Fuzz_Test { function testFuzz_WithdrawableAmountOf_CliffTimeInFuture(uint40 timeJump) external givenNotNull diff --git a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol index 2720b4286..cfc21ae5c 100644 --- a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -2,98 +2,38 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; + import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../../shared/lockup/LockupTranched.t.sol"; import { Cancel_Integration_Fuzz_Test } from "./../lockup-base/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "./../lockup-base/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "./../lockup-base/getWithdrawnAmount.t.sol"; import { RefundableAmountOf_Integration_Fuzz_Test } from "./../lockup-base/refundableAmountOf.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "./../lockup-base/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "./../lockup-base/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "./../lockup-base/withdrawMultiple.t.sol"; /*////////////////////////////////////////////////////////////////////////// SHARED TESTS //////////////////////////////////////////////////////////////////////////*/ -contract Cancel_Lockup_Tranched_Integration_Fuzz_Test is - Lockup_Tranched_Integration_Shared_Test, - Cancel_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract CancelMultiple_Lockup_Tranched_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { - modifier whenCallerAuthorizedForAllStreams() override { - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLT({ warpTime: originalTime }); - _; - } - +contract Lockup_Tranched_Integration_Fuzz_Test is Integration_Test { function setUp() public virtual override { - CancelMultiple_Integration_Fuzz_Test.setUp(); - lockupModel = Lockup.Model.LOCKUP_TRANCHED; - } -} + Integration_Test.setUp(); -contract RefundableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is - Lockup_Tranched_Integration_Shared_Test, - RefundableAmountOf_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract GetWithdrawnAmount_Lockup_Tranched_Integration_Fuzz_Test is - Lockup_Tranched_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Fuzz_Test -{ - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_TRANCHED; + createDefaultStreamIds(); } } -contract WithdrawMax_Lockup_Tranched_Integration_Fuzz_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawMax_Integration_Fuzz_Test +contract Cancel_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Fuzz_Test, + Cancel_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Fuzz_Test, Integration_Test) { + Lockup_Tranched_Integration_Fuzz_Test.setUp(); } } -contract WithdrawMaxAndTransfer_Lockup_Tranched_Integration_Fuzz_Test is - Lockup_Tranched_Integration_Shared_Test, - WithdrawMaxAndTransfer_Integration_Fuzz_Test +contract RefundableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Fuzz_Test, + RefundableAmountOf_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); - } -} - -contract WithdrawMultiple_Lockup_Tranched_Integration_Fuzz_Test is WithdrawMultiple_Integration_Fuzz_Test { - /// @dev This modifier runs the test in three different modes: - /// - Stream's sender as caller - /// - Stream's recipient as caller - /// - Approved NFT operator as caller - modifier whenCallerAuthorizedForAllStreams() override { - caller = users.sender; - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: originalTime }); - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: originalTime }); - caller = users.recipient; - _; - - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: originalTime }); - caller = users.operator; - _; - } - - function setUp() public virtual override { - WithdrawMultiple_Integration_Fuzz_Test.setUp(); - lockupModel = Lockup.Model.LOCKUP_TRANCHED; + function setUp() public virtual override(Lockup_Tranched_Integration_Fuzz_Test, Integration_Test) { + Lockup_Tranched_Integration_Fuzz_Test.setUp(); } } diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol index f4392d604..8e1e1e35b 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol @@ -4,16 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Lockup_Tranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; +contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Tranched_Integration_Fuzz_Test { struct Vars { uint256 actualNextStreamId; address actualNFTOwner; @@ -46,11 +39,12 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Share // Make the Sender the stream's funder (recall that the Sender is the default caller). vars.funder = users.sender; + uint256 expectedStreamId = lockup.nextStreamId(); // 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 {SablierLockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -62,14 +56,13 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Share vars.tranchesWithTimestamps = getTranchesWithTimestamps(tranches); Lockup.Timestamps memory timestamps = Lockup.Timestamps({ start: getBlockTimestamp(), - cliff: 0, end: vars.tranchesWithTimestamps[vars.tranchesWithTimestamps.length - 1].timestamp }); // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); emit ISablierLockup.CreateLockupTranchedStream({ - streamId: streamId, + streamId: expectedStreamId, funder: vars.funder, sender: users.sender, recipient: users.recipient, @@ -83,10 +76,9 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Share }); // Create the stream. - Lockup.CreateWithDurations memory params = defaults.createWithDurations(); - params.totalAmount = vars.totalAmount; - params.transferable = true; - lockup.createWithDurationsLT(params, tranches); + _defaultParams.createWithDurations.totalAmount = vars.totalAmount; + _defaultParams.createWithDurations.transferable = true; + uint256 streamId = lockup.createWithDurationsLT(_defaultParams.createWithDurations, tranches); // 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. @@ -98,14 +90,15 @@ contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Share assertEq(lockup.getAsset(streamId), dai, "asset"); assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); - assertEq(lockup.getRecipient(streamId), params.recipient, "recipient"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); + assertEq(lockup.getRecipient(streamId), users.recipient, "recipient"); assertEq(lockup.getSender(streamId), users.sender, "sender"); assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); assertEq(lockup.getTranches(streamId), vars.tranchesWithTimestamps, "tranches"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_TRANCHED); // Assert that the stream's status is correct. vars.actualStatus = lockup.statusOf(streamId); diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol index f06a05414..326549bbc 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol @@ -8,16 +8,9 @@ import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { - uint256 internal streamId; - - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - streamId = lockup.nextStreamId(); - } +import { Lockup_Tranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; +contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Tranched_Integration_Fuzz_Test { function testFuzz_RevertWhen_TrancheCountTooHigh(uint256 trancheCount) external whenNoDelegateCall @@ -29,8 +22,8 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar uint256 defaultMax = defaults.MAX_COUNT(); trancheCount = _bound(trancheCount, defaultMax + 1, defaultMax * 10); LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, trancheCount)); - createDefaultStreamWithTranchesLT(tranches); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierHelpers_TrancheCountTooHigh.selector, trancheCount)); + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); } function testFuzz_RevertWhen_TrancheAmountsSumOverflows( @@ -51,7 +44,7 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar tranches[0].amount = amount0; tranches[1].amount = amount1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithTranchesLT(tranches); + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); } function testFuzz_RevertWhen_StartTimeNotLessThanFirstTrancheTimestamp(uint40 firstTimestamp) @@ -73,14 +66,12 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierHelpers_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) ); - - // Create the stream. - createDefaultStreamWithTranchesLT(tranches); + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, tranches); } function testFuzz_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum(uint128 depositDiff) @@ -111,13 +102,12 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_DepositAmountNotEqualToTrancheAmountsSum.selector, + Errors.SablierHelpers_DepositAmountNotEqualToTrancheAmountsSum.selector, depositAmount, defaultDepositAmount ) ); - // Create the stream. lockup.createWithTimestampsLT(params, tranches); } @@ -137,9 +127,10 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar vm.assume(broker.account != address(0)); broker.fee = _bound(broker.fee, MAX_BROKER_FEE + ud(1), MAX_UD60x18); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) + abi.encodeWithSelector(Errors.SablierHelpers_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBrokerLT(broker); + _defaultParams.createWithTimestamps.broker = broker; + lockup.createWithTimestampsLT(_defaultParams.createWithTimestamps, _defaultParams.tranches); } struct Vars { @@ -193,27 +184,31 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar vm.assume(tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); + params.asset = dai; + params.timestamps.start = boundUint40(params.timestamps.start, 1, defaults.START_TIME()); params.transferable = true; // Fuzz the tranche timestamps. - fuzzTrancheTimestamps(tranches, params.startTime); + fuzzTrancheTimestamps(tranches, params.timestamps.start); + params.timestamps.end = tranches[tranches.length - 1].timestamp; // Fuzz the tranche amounts and calculate the total and create amounts (deposit and broker fee). Vars memory vars; (vars.totalAmount, vars.createAmounts) = fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: params.broker.fee }); + params.totalAmount = vars.totalAmount; + // Make the fuzzed funder the caller in the rest of this test. resetPrank(funder); // Mint enough assets to the fuzzed funder. deal({ token: address(dai), to: funder, give: vars.totalAmount }); - // Approve {SablierLockupTranched} to transfer the assets from the fuzzed funder. + // Approve {SablierLockup} to transfer the assets from the fuzzed funder. dai.approve({ spender: address(lockup), value: MAX_UINT256 }); - // Expect the assets to be transferred from the funder to {SablierLockupTranched}. + // Expect the assets to be transferred from the funder to {SablierLockup}. expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. @@ -221,12 +216,12 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar expectCallToTransferFrom({ from: funder, to: params.broker.account, value: vars.createAmounts.brokerFee }); } + uint256 expectedStreamId = lockup.nextStreamId(); + // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - Lockup.Timestamps memory timestamps = - Lockup.Timestamps({ start: params.startTime, cliff: 0, end: tranches[tranches.length - 1].timestamp }); emit ISablierLockup.CreateLockupTranchedStream({ - streamId: streamId, + streamId: expectedStreamId, funder: funder, sender: params.sender, recipient: params.recipient, @@ -235,25 +230,12 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar cancelable: params.cancelable, transferable: params.transferable, tranches: tranches, - timestamps: timestamps, + timestamps: params.timestamps, broker: params.broker.account }); // Create the stream. - lockup.createWithTimestampsLT( - Lockup.CreateWithTimestamps({ - sender: params.sender, - recipient: params.recipient, - totalAmount: vars.totalAmount, - asset: dai, - cancelable: params.cancelable, - transferable: params.transferable, - startTime: params.startTime, - endTime: tranches[tranches.length - 1].timestamp, - broker: params.broker - }), - tranches - ); + uint256 streamId = lockup.createWithTimestampsLT(params, tranches); // 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. @@ -263,20 +245,21 @@ contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shar // It should create the stream. assertEq(lockup.getDepositedAmount(streamId), vars.createAmounts.deposit, "depositedAmount"); assertEq(lockup.getAsset(streamId), dai, "asset"); - assertEq(lockup.getEndTime(streamId), timestamps.end, "endTime"); + assertEq(lockup.getEndTime(streamId), params.timestamps.end, "endTime"); assertEq(lockup.isCancelable(streamId), vars.isCancelable, "isCancelable"); - assertEq(lockup.isDepleted(streamId), false, "isDepleted"); - assertEq(lockup.isStream(streamId), true, "isStream"); - assertEq(lockup.isTransferable(streamId), true, "isTransferable"); + assertFalse(lockup.isDepleted(streamId), "isDepleted"); + assertTrue(lockup.isStream(streamId), "isStream"); + assertTrue(lockup.isTransferable(streamId), "isTransferable"); assertEq(lockup.getRecipient(streamId), params.recipient, "recipient"); assertEq(lockup.getSender(streamId), params.sender, "sender"); - assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); - assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getStartTime(streamId), params.timestamps.start, "startTime"); + assertFalse(lockup.wasCanceled(streamId), "wasCanceled"); assertEq(lockup.getTranches(streamId), tranches, "tranches"); + assertEq(lockup.getLockupModel(streamId), Lockup.Model.LOCKUP_TRANCHED); // Assert that the stream's status is correct. vars.actualStatus = lockup.statusOf(streamId); - if (params.startTime > getBlockTimestamp()) { + if (params.timestamps.start > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { vars.expectedStatus = Lockup.Status.SETTLED; diff --git a/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 1dc868de1..c407b396d 100644 --- a/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../../shared/lockup/LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; -contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranched_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranched_Integration_Fuzz_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -47,12 +47,11 @@ contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranch Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = totalAmount; - params.endTime = tranches[tranches.length - 1].timestamp; + params.timestamps.end = tranches[tranches.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLT(params, tranches); // 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 = lockup.streamedAmountOf(streamId); @@ -95,7 +94,7 @@ contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranch Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = totalAmount; - params.endTime = tranches[tranches.length - 1].timestamp; + params.timestamps.end = tranches[tranches.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLT(params, tranches); // Warp to the future for the first time. diff --git a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 76e7025bf..102ad596d 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -4,19 +4,19 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { Integration_Test } from "./../../Integration.t.sol"; -import { Lockup_Tranched_Integration_Shared_Test } from "./../../shared/lockup/LockupTranched.t.sol"; -import { Withdraw_Integration_Fuzz_Test } from "./../lockup-base/withdraw.t.sol"; +import { Integration_Test } from "../../Integration.t.sol"; +import { Withdraw_Integration_Fuzz_Test } from "./../lockup-base/withdraw.t.sol"; +import { Lockup_Tranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; /// @dev This contract complements the tests in {Withdraw_Integration_Fuzz_Test} by testing the withdraw function -/// against -/// streams created with fuzzed tranches. +/// against streams created with fuzzed tranches. + contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is - Withdraw_Integration_Fuzz_Test, - Lockup_Tranched_Integration_Shared_Test + Lockup_Tranched_Integration_Fuzz_Test, + Withdraw_Integration_Fuzz_Test { - function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { - Lockup_Tranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Fuzz_Test, Integration_Test) { + Lockup_Tranched_Integration_Fuzz_Test.setUp(); } struct Params { @@ -75,7 +75,7 @@ contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is // Create the stream with the fuzzed tranches. Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestamps(); createParams.totalAmount = vars.totalAmount; - createParams.endTime = params.tranches[params.tranches.length - 1].timestamp; + createParams.timestamps.end = params.tranches[params.tranches.length - 1].timestamp; vars.streamId = lockup.createWithTimestampsLT(createParams, params.tranches); diff --git a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index a592e8412..3b07d52b2 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -4,9 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; import { Broker, Lockup } from "src/core/types/DataTypes.sol"; -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; +import { Lockup_Tranched_Integration_Fuzz_Test } from "./LockupTranched.t.sol"; -contract WithdrawableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranched_Integration_Fuzz_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past diff --git a/test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol b/test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol index e025f37c4..b0c493e78 100644 --- a/test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol +++ b/test/core/integration/fuzz/nft-descriptor/isAllowedCharacter.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Integration_Shared_Test } from "../../shared/nft-descriptor/NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract IsAllowedCharacter_Integration_Fuzz_Test is NFTDescriptor_Integration_Shared_Test { +contract IsAllowedCharacter_Integration_Fuzz_Test is Base_Test { bytes1 internal constant SPACE = 0x20; // ASCII 32 bytes1 internal constant DASH = 0x2D; // ASCII 45 bytes1 internal constant ZERO = 0x30; // ASCII 48 diff --git a/test/core/integration/shared/lockup/Lockup.t.sol b/test/core/integration/shared/lockup/Lockup.t.sol deleted file mode 100644 index e23e5ce06..000000000 --- a/test/core/integration/shared/lockup/Lockup.t.sol +++ /dev/null @@ -1,454 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { Broker, Lockup, LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -/// @dev A shared test containing various create functions for Lockup Dynamic, Lockup Linear, and Lockup Tranched. -abstract contract Lockup_Integration_Shared_Test is Integration_Test { - struct CreateParams { - Lockup.CreateWithTimestamps createWithTimestamps; - Lockup.CreateWithDurations createWithDurations; - uint40 cliffTime; - LockupLinear.Durations durations; - LockupDynamic.Segment[] segments; - LockupDynamic.SegmentWithDuration[] segmentsWithDurations; - LockupTranched.Tranche[] tranches; - LockupTranched.TrancheWithDuration[] tranchesWithDurations; - } - - CreateParams private _params; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Integration_Test.setUp(); - - _params.createWithTimestamps = defaults.createWithTimestamps(); - _params.createWithDurations = defaults.createWithDurations(); - _params.cliffTime = defaults.CLIFF_TIME(); - _params.durations = defaults.durations(); - - // See https://github.com/ethereum/solidity/issues/12783 - LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); - LockupDynamic.Segment[] memory segments = defaults.segments(); - for (uint256 i; i < defaults.SEGMENT_COUNT(); ++i) { - _params.segments.push(segments[i]); - _params.segmentsWithDurations.push(segmentsWithDurations[i]); - } - LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - for (uint256 i; i < defaults.TRANCHE_COUNT(); ++i) { - _params.tranches.push(tranches[i]); - _params.tranchesWithDurations.push(tranchesWithDurations[i]); - } - } - - /*////////////////////////////////////////////////////////////////////////// - LOCKUP-DYNAMIC - //////////////////////////////////////////////////////////////////////////*/ - - function createDefaultStreamLD() internal returns (uint256 streamId) { - streamId = lockup.createWithTimestampsLD(_params.createWithTimestamps, _params.segments); - } - - function createDefaultStreamWithAssetLD(IERC20 asset) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamWithBrokerLD(Broker memory broker) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurationsLD() internal returns (uint256 streamId) { - streamId = lockup.createWithDurationsLD(_params.createWithDurations, _params.segmentsWithDurations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurationsLD(LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations) - internal - returns (uint256 streamId) - { - streamId = lockup.createWithDurationsLD(_params.createWithDurations, segmentsWithDurations); - } - - function createDefaultStreamWithEndTimeLD(uint40 endTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - LockupDynamic.Segment[] memory segments_ = _params.segments; - params.endTime = endTime; - segments_[1].timestamp = endTime; - streamId = lockup.createWithTimestampsLD(params, segments_); - } - - function createDefaultStreamWithIdenticalUsersLD(address user) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = user; - params.recipient = user; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamNotCancelableLD() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamNotTransferableLD() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamWithRecipientLD(address recipient) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - /// @dev Creates the default stream with the provided segments. - function createDefaultStreamWithSegmentsLD(LockupDynamic.Segment[] memory segments) - internal - returns (uint256 streamId) - { - streamId = lockup.createWithTimestampsLD(_params.createWithTimestamps, segments); - } - - function createDefaultStreamWithSenderLD(address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamWithStartTimeLD(uint40 startTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = startTime; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestampsLD(Lockup.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - LockupDynamic.Segment[] memory segments_ = _params.segments; - params.startTime = timestamps.start; - params.endTime = timestamps.end; - segments_[1].timestamp = timestamps.end; - streamId = lockup.createWithTimestampsLD(params, segments_); - } - - function createDefaultStreamWithTotalAmountLD(uint128 totalAmount) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - function createDefaultStreamWithUsersLD(address recipient, address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockup.createWithTimestampsLD(params, _params.segments); - } - - /// @dev The following two functions are used in `CancelMultiple` and `WithdrawMultiple` tests. - function WarpAndCreateStreamsForCancelMultipleLD(uint40 warpTime) internal returns (uint256[2] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create the first stream. - streamIds[0] = createDefaultStreamLD(); - - // Create the second stream with an end time double that of the default stream so that the refund amounts are - // different. - streamIds[1] = createDefaultStreamWithEndTimeLD(defaults.END_TIME() + defaults.TOTAL_DURATION()); - } - - function WarpAndCreateStreamsWithdrawMultipleLD(uint40 warpTime) internal returns (uint256[3] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create three test streams: - // 1. A default stream - // 2. A stream with an early end time - // 3. A stream meant to be canceled before the withdrawal is made - streamIds[0] = createDefaultStreamLD(); - streamIds[1] = createDefaultStreamWithEndTimeLD(defaults.WARP_26_PERCENT()); - streamIds[2] = createDefaultStreamLD(); - } - - /*////////////////////////////////////////////////////////////////////////// - LOCKUP-LINEAR - //////////////////////////////////////////////////////////////////////////*/ - - function createDefaultStreamLL() internal returns (uint256 streamId) { - streamId = lockup.createWithTimestampsLL(_params.createWithTimestamps, _params.cliffTime); - } - - function createDefaultStreamWithAssetLL(IERC20 asset) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithBrokerLL(Broker memory broker) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurationsLL() internal returns (uint256 streamId) { - streamId = lockup.createWithDurationsLL(_params.createWithDurations, _params.durations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurationsLL(LockupLinear.Durations memory durations) - internal - returns (uint256 streamId) - { - streamId = lockup.createWithDurationsLL(_params.createWithDurations, durations); - } - - function createDefaultStreamNotCancelableLL() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamNotTransferableLL() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithEndTimeLL(uint40 endTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.endTime = endTime; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithIdenticalUsersLL(address user) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = user; - params.recipient = user; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithRecipientLL(address recipient) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithSenderLL(address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithStartTimeLL(uint40 startTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = startTime; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestampsLL(Lockup.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = timestamps.start; - params.endTime = timestamps.end; - streamId = lockup.createWithTimestampsLL(params, timestamps.cliff); - } - - function createDefaultStreamWithTotalAmountLL(uint128 totalAmount) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - function createDefaultStreamWithUsersLL(address recipient, address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockup.createWithTimestampsLL(params, _params.cliffTime); - } - - /// @dev The following two functions are used in `CancelMultiple` and `WithdrawMultiple` tests. - function WarpAndCreateStreamsForCancelMultipleLL(uint40 warpTime) internal returns (uint256[2] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create the first stream. - streamIds[0] = createDefaultStreamLL(); - // Create the second stream with an end time double that of the default stream so that the refund amounts are - // different. - streamIds[1] = createDefaultStreamWithEndTimeLL(defaults.END_TIME() + defaults.TOTAL_DURATION()); - } - - function WarpAndCreateStreamsWithdrawMultipleLL(uint40 warpTime) internal returns (uint256[3] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create three test streams: - // 1. A default stream - // 2. A stream with an early end time - // 3. A stream meant to be canceled before the withdrawal is made - streamIds[0] = createDefaultStreamLL(); - streamIds[1] = createDefaultStreamWithEndTimeLL(defaults.WARP_26_PERCENT()); - streamIds[2] = createDefaultStreamLL(); - } - - /*////////////////////////////////////////////////////////////////////////// - LOCKUP-TRANCHED - //////////////////////////////////////////////////////////////////////////*/ - - function createDefaultStreamLT() internal returns (uint256 streamId) { - streamId = lockup.createWithTimestampsLT(_params.createWithTimestamps, _params.tranches); - } - - function createDefaultStreamWithAssetLT(IERC20 asset) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamWithBrokerLT(Broker memory broker) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurationsLT() internal returns (uint256 streamId) { - streamId = lockup.createWithDurationsLT(_params.createWithDurations, _params.tranchesWithDurations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurationsLT(LockupTranched.TrancheWithDuration[] memory tranchesWithDuration) - internal - returns (uint256 streamId) - { - streamId = lockup.createWithDurationsLT(_params.createWithDurations, tranchesWithDuration); - } - - function createDefaultStreamWithEndTimeLT(uint40 endTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - LockupTranched.Tranche[] memory tranches_ = _params.tranches; - params.endTime = endTime; - tranches_[2].timestamp = endTime; - - // Ensure the timestamps are arranged in ascending order. - if (tranches_[2].timestamp <= tranches_[1].timestamp) { - tranches_[1].timestamp = tranches_[2].timestamp - 1; - } - if (tranches_[1].timestamp <= tranches_[0].timestamp) { - tranches_[0].timestamp = tranches_[1].timestamp - 1; - } - - streamId = lockup.createWithTimestampsLT(params, tranches_); - } - - function createDefaultStreamWithIdenticalUsersLT(address user) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = user; - params.recipient = user; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamNotCancelableLT() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamNotTransferableLT() internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestampsLT(Lockup.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - LockupTranched.Tranche[] memory tranches_ = _params.tranches; - params.startTime = timestamps.start; - params.endTime = timestamps.end; - tranches_[1].timestamp = timestamps.end; - streamId = lockup.createWithTimestampsLT(params, tranches_); - } - - function createDefaultStreamWithRecipientLT(address recipient) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - /// @dev Creates the default stream with the provided tranches. - function createDefaultStreamWithTranchesLT(LockupTranched.Tranche[] memory tranches) - internal - returns (uint256 streamId) - { - streamId = lockup.createWithTimestampsLT(_params.createWithTimestamps, tranches); - } - - function createDefaultStreamWithSenderLT(address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamWithStartTimeLT(uint40 startTime) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = startTime; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamWithTotalAmountLT(uint128 totalAmount) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - function createDefaultStreamWithUsersLT(address recipient, address sender) internal returns (uint256 streamId) { - Lockup.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockup.createWithTimestampsLT(params, _params.tranches); - } - - /// @dev The following two functions are used in `CancelMultiple` and `WithdrawMultiple` tests. - function WarpAndCreateStreamsForCancelMultipleLT(uint40 warpTime) internal returns (uint256[2] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create the first stream. - streamIds[0] = createDefaultStreamLT(); - // Create the second stream with an end time double that of the default stream so that the refund amounts are - // different. - streamIds[1] = createDefaultStreamWithEndTimeLT(defaults.END_TIME() + defaults.TOTAL_DURATION()); - } - - function WarpAndCreateStreamsWithdrawMultipleLT(uint40 warpTime) internal returns (uint256[3] memory streamIds) { - vm.warp({ newTimestamp: warpTime }); - - // Create three test streams: - // 1. A default stream - // 2. A stream with an early end time - // 3. A stream meant to be canceled before the withdrawal is made - streamIds[0] = createDefaultStreamLT(); - streamIds[1] = createDefaultStreamWithEndTimeLT(defaults.WARP_26_PERCENT()); - streamIds[2] = createDefaultStreamLT(); - } -} diff --git a/test/core/integration/shared/lockup/LockupDynamic.t.sol b/test/core/integration/shared/lockup/LockupDynamic.t.sol deleted file mode 100644 index c9ba5a1f0..000000000 --- a/test/core/integration/shared/lockup/LockupDynamic.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -/// @dev A shared test used across Lockup Dynamic concrete and fuzz tests. -abstract contract Lockup_Dynamic_Integration_Shared_Test is Lockup_Integration_Shared_Test { - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - - // Initialize streams IDs. - defaultStreamId = createDefaultStreamLD(); - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLD({ warpTime: getBlockTimestamp() }); - differentSenderRecipientStreamId = - createDefaultStreamWithUsersLD({ recipient: address(recipientGood), sender: users.sender }); - earlyEndtimeStreamId = createDefaultStreamWithEndTimeLD({ endTime: defaults.CLIFF_TIME() + 1 seconds }); - identicalSenderRecipientStreamId = createDefaultStreamWithIdenticalUsersLD(users.sender); - notCancelableStreamId = createDefaultStreamNotCancelableLD(); - notTransferableStreamId = createDefaultStreamNotTransferableLD(); - recipientGoodStreamId = createDefaultStreamWithRecipientLD(address(recipientGood)); - recipientInvalidSelectorStreamId = createDefaultStreamWithRecipientLD(address(recipientInvalidSelector)); - recipientReentrantStreamId = createDefaultStreamWithRecipientLD(address(recipientReentrant)); - recipientRevertStreamId = createDefaultStreamWithRecipientLD(address(recipientReverting)); - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLD({ warpTime: getBlockTimestamp() }); - } -} diff --git a/test/core/integration/shared/lockup/LockupLinear.t.sol b/test/core/integration/shared/lockup/LockupLinear.t.sol deleted file mode 100644 index 04920379c..000000000 --- a/test/core/integration/shared/lockup/LockupLinear.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -/// @dev A shared test used across Lockup Linear concrete and fuzz tests. -abstract contract Lockup_Linear_Integration_Shared_Test is Lockup_Integration_Shared_Test { - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - - // Initialize streams IDs. - defaultStreamId = createDefaultStreamLL(); - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLL({ warpTime: getBlockTimestamp() }); - differentSenderRecipientStreamId = - createDefaultStreamWithUsersLL({ recipient: address(recipientGood), sender: users.sender }); - earlyEndtimeStreamId = createDefaultStreamWithEndTimeLL({ endTime: defaults.CLIFF_TIME() + 1 seconds }); - identicalSenderRecipientStreamId = createDefaultStreamWithIdenticalUsersLL(users.sender); - notCancelableStreamId = createDefaultStreamNotCancelableLL(); - notTransferableStreamId = createDefaultStreamNotTransferableLL(); - recipientGoodStreamId = createDefaultStreamWithRecipientLL(address(recipientGood)); - recipientInvalidSelectorStreamId = createDefaultStreamWithRecipientLL(address(recipientInvalidSelector)); - recipientReentrantStreamId = createDefaultStreamWithRecipientLL(address(recipientReentrant)); - recipientRevertStreamId = createDefaultStreamWithRecipientLL(address(recipientReverting)); - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLL({ warpTime: getBlockTimestamp() }); - } -} diff --git a/test/core/integration/shared/lockup/LockupTranched.t.sol b/test/core/integration/shared/lockup/LockupTranched.t.sol deleted file mode 100644 index 8e31db98e..000000000 --- a/test/core/integration/shared/lockup/LockupTranched.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; - -/// @dev A shared test used across Lockup Tranched concrete and fuzz tests. -abstract contract Lockup_Tranched_Integration_Shared_Test is Lockup_Integration_Shared_Test { - function setUp() public virtual override { - Lockup_Integration_Shared_Test.setUp(); - - // Initialize streams IDs. - defaultStreamId = createDefaultStreamLT(); - cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLT({ warpTime: getBlockTimestamp() }); - differentSenderRecipientStreamId = - createDefaultStreamWithUsersLT({ recipient: address(recipientGood), sender: users.sender }); - earlyEndtimeStreamId = createDefaultStreamWithEndTimeLT({ endTime: defaults.CLIFF_TIME() + 1 seconds }); - identicalSenderRecipientStreamId = createDefaultStreamWithIdenticalUsersLT(users.sender); - notCancelableStreamId = createDefaultStreamNotCancelableLT(); - notTransferableStreamId = createDefaultStreamNotTransferableLT(); - recipientGoodStreamId = createDefaultStreamWithRecipientLT(address(recipientGood)); - recipientInvalidSelectorStreamId = createDefaultStreamWithRecipientLT(address(recipientInvalidSelector)); - recipientReentrantStreamId = createDefaultStreamWithRecipientLT(address(recipientReentrant)); - recipientRevertStreamId = createDefaultStreamWithRecipientLT(address(recipientReverting)); - withdrawMultipleStreamIds = WarpAndCreateStreamsWithdrawMultipleLT({ warpTime: getBlockTimestamp() }); - } -} diff --git a/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol b/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol deleted file mode 100644 index c308ab741..000000000 --- a/test/core/integration/shared/nft-descriptor/NFTDescriptor.t.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Base_Test } from "test/Base.t.sol"; -import { NFTDescriptorMock } from "test/mocks/NFTDescriptorMock.sol"; - -abstract contract NFTDescriptor_Integration_Shared_Test is Base_Test { - NFTDescriptorMock internal nftDescriptorMock; - - function setUp() public virtual override { - Base_Test.setUp(); - deployConditionally(); - } - - /// @dev Conditionally deploys {NFTDescriptorMock} normally or from a source precompiled with `--via-ir`. - function deployConditionally() internal { - if (!isTestOptimizedProfile()) { - nftDescriptorMock = new NFTDescriptorMock(); - } else { - nftDescriptorMock = - NFTDescriptorMock(deployCode("out-optimized/NFTDescriptorMock.sol/NFTDescriptorMock.json")); - } - vm.label({ account: address(nftDescriptorMock), newLabel: "NFTDescriptorMock" }); - } -} diff --git a/test/core/invariant/Invariant.t.sol b/test/core/invariant/Invariant.t.sol index b5a849008..bec22824e 100644 --- a/test/core/invariant/Invariant.t.sol +++ b/test/core/invariant/Invariant.t.sol @@ -381,12 +381,14 @@ contract Invariant_Test is Base_Test, StdInvariant { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - if (lockup.getCliffTime(streamId) > 0) { - assertGt( - lockup.getCliffTime(streamId), - lockup.getStartTime(streamId), - "Invariant violated: cliff time <= start time" - ); + if (lockup.getLockupModel(streamId) == Lockup.Model.LOCKUP_LINEAR) { + if (lockup.getCliffTime(streamId) > 0) { + assertGt( + lockup.getCliffTime(streamId), + lockup.getStartTime(streamId), + "Invariant violated: cliff time <= start time" + ); + } } } } @@ -396,9 +398,13 @@ contract Invariant_Test is Base_Test, StdInvariant { uint256 lastStreamId = lockupStore.lastStreamId(); for (uint256 i = 0; i < lastStreamId; ++i) { uint256 streamId = lockupStore.streamIds(i); - assertGt( - lockup.getEndTime(streamId), lockup.getCliffTime(streamId), "Invariant violated: end time <= cliff time" - ); + if (lockup.getLockupModel(streamId) == Lockup.Model.LOCKUP_LINEAR) { + assertGt( + lockup.getEndTime(streamId), + lockup.getCliffTime(streamId), + "Invariant violated: end time <= cliff time" + ); + } } } diff --git a/test/core/invariant/handlers/BaseHandler.sol b/test/core/invariant/handlers/BaseHandler.sol index bc5c46bd6..e7c3485fb 100644 --- a/test/core/invariant/handlers/BaseHandler.sol +++ b/test/core/invariant/handlers/BaseHandler.sol @@ -15,7 +15,7 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { //////////////////////////////////////////////////////////////////////////*/ /// @dev Maximum number of streams that can be created during an invariant campaign. - uint256 internal constant MAX_STREAM_COUNT = 100; + uint256 internal constant MAX_STREAM_COUNT = 300; /// @dev Maps function names to the number of times they have been called. mapping(string func => uint256 calls) public calls; diff --git a/test/core/invariant/handlers/LockupCreateHandler.sol b/test/core/invariant/handlers/LockupCreateHandler.sol index 2edf4ea31..8c4ba38b2 100644 --- a/test/core/invariant/handlers/LockupCreateHandler.sol +++ b/test/core/invariant/handlers/LockupCreateHandler.sol @@ -76,7 +76,7 @@ contract LockupCreateHandler is BaseHandler { LockupLinear.Durations memory durations ) public - instrument("createWithDurations") + instrument("createWithDurationsLL") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -110,7 +110,7 @@ contract LockupCreateHandler is BaseHandler { LockupTranched.TrancheWithDuration[] memory tranches ) public - instrument("createWithDurations") + instrument("createWithDurationsLT") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -154,7 +154,7 @@ contract LockupCreateHandler is BaseHandler { LockupDynamic.Segment[] memory segments ) public - instrument("createWithTimestamps") + instrument("createWithTimestampsLD") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -166,10 +166,10 @@ contract LockupCreateHandler is BaseHandler { vm.assume(segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); + params.timestamps.start = boundUint40(params.timestamps.start, 1, getBlockTimestamp()); // Fuzz the segment timestamps. - fuzzSegmentTimestamps(segments, params.startTime); + fuzzSegmentTimestamps(segments, params.timestamps.start); // Fuzz the segment amounts and calculate the total amount. (params.totalAmount,) = @@ -183,7 +183,7 @@ contract LockupCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - params.endTime = segments[segments.length - 1].timestamp; + params.timestamps.end = segments[segments.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Store the stream ID. @@ -193,10 +193,10 @@ contract LockupCreateHandler is BaseHandler { function createWithTimestampsLL( uint256 timeJumpSeed, Lockup.CreateWithTimestamps memory params, - uint40 cliff + uint40 cliffTime ) public - instrument("createWithTimestamps") + instrument("createWithTimestampsLL") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -205,17 +205,17 @@ contract LockupCreateHandler is BaseHandler { vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1 seconds, getBlockTimestamp()); + params.timestamps.start = boundUint40(params.timestamps.start, 1 seconds, getBlockTimestamp()); params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); // The cliff time must be either zero or greater than the start time. - if (cliff > 0) { - cliff = boundUint40(cliff, params.startTime + 1 seconds, params.startTime + 52 weeks); + if (cliffTime > 0) { + cliffTime = boundUint40(cliffTime, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks); } // Bound the end time so that it is always greater than the start time, and the cliff time. - uint40 endTimeLowerBound = maxOfTwo(params.startTime, cliff); - params.endTime = boundUint40(params.endTime, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); + uint40 endTimeLowerBound = maxOfTwo(params.timestamps.start, cliffTime); + params.timestamps.end = boundUint40(params.timestamps.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); // Mint enough assets to the Sender. deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); @@ -225,7 +225,7 @@ contract LockupCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - uint256 streamId = lockup.createWithTimestampsLL(params, cliff); + uint256 streamId = lockup.createWithTimestampsLL(params, cliffTime); // Store the stream ID. lockupStore.pushStreamId(streamId, params.sender, params.recipient); @@ -237,7 +237,7 @@ contract LockupCreateHandler is BaseHandler { LockupTranched.Tranche[] memory tranches ) public - instrument("createWithTimestamps") + instrument("createWithTimestampsLT") adjustTimestamp(timeJumpSeed) checkUsers(params.sender, params.recipient, params.broker.account) useNewSender(params.sender) @@ -249,10 +249,10 @@ contract LockupCreateHandler is BaseHandler { vm.assume(tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); + params.timestamps.start = boundUint40(params.timestamps.start, 1, getBlockTimestamp()); // Fuzz the tranche timestamps. - fuzzTrancheTimestamps(tranches, params.startTime); + fuzzTrancheTimestamps(tranches, params.timestamps.start); // Fuzz the tranche amounts and calculate the total amount. (params.totalAmount,) = fuzzTranchedStreamAmounts({ @@ -269,7 +269,7 @@ contract LockupCreateHandler is BaseHandler { // Create the stream. params.asset = asset; - params.endTime = tranches[tranches.length - 1].timestamp; + params.timestamps.end = tranches[tranches.length - 1].timestamp; uint256 streamId = lockup.createWithTimestampsLT(params, tranches); // Store the stream ID. diff --git a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol b/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol deleted file mode 100644 index 25b0e5680..000000000 --- a/test/core/unit/concrete/nft-descriptor/NFTDescriptor.t.sol +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; -import { Base_Test } from "test/Base.t.sol"; -import { NFTDescriptorMock } from "test/mocks/NFTDescriptorMock.sol"; - -contract NFTDescriptor_Unit_Concrete_Test is Base_Test, LockupNFTDescriptor { - NFTDescriptorMock internal nftDescriptorMock; - - function setUp() public virtual override { - Base_Test.setUp(); - deployConditionally(); - } - - /// @dev Conditionally deploys {NFTDescriptorMock} normally or from a source precompiled with `--via-ir`. - function deployConditionally() internal { - if (!isTestOptimizedProfile()) { - nftDescriptorMock = new NFTDescriptorMock(); - } else { - nftDescriptorMock = - NFTDescriptorMock(deployCode("out-optimized/NFTDescriptorMock.sol/NFTDescriptorMock.json")); - } - vm.label({ account: address(nftDescriptorMock), newLabel: "NFTDescriptorMock" }); - } -} diff --git a/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol index f271568ba..f7f2947ee 100644 --- a/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol +++ b/test/core/unit/concrete/nft-descriptor/abbreviateAmount.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/core/libraries/SVGElements.sol"; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract AbbreviateAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract AbbreviateAmount_Unit_Concrete_Test is Base_Test { function aa(uint256 amount, uint256 decimals) internal view returns (string memory) { return nftDescriptorMock.abbreviateAmount_({ amount: amount, decimals: decimals }); } diff --git a/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol index e1a97aeae..9aba6aa21 100644 --- a/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol +++ b/test/core/unit/concrete/nft-descriptor/calculateDurationInDays.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/core/libraries/SVGElements.sol"; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract CalculateDurationInDays_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract CalculateDurationInDays_Unit_Concrete_Test is Base_Test { function test_CalculateDurationInDays_Zero() external view { uint256 startTime = getBlockTimestamp(); uint256 endTime = startTime + 1 days - 1 seconds; diff --git a/test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol b/test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol index a01fd49ea..cf155e905 100644 --- a/test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol +++ b/test/core/unit/concrete/nft-descriptor/calculatePixelWidth.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract CalculatePixelWidth_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract CalculatePixelWidth_Unit_Concrete_Test is Base_Test { uint256 internal constant CHAR_WIDTH_LARGE = 16; uint256 internal constant CHAR_WIDTH_SMALL = 13; diff --git a/test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol b/test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol index 1345780df..96895caa9 100644 --- a/test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol +++ b/test/core/unit/concrete/nft-descriptor/calculateStreamedPercentage.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract CalculateStreamedPercentage_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract CalculateStreamedPercentage_Unit_Concrete_Test is Base_Test { function test_CalculateStreamedPercentage_Zero() external view { uint256 actualStreamedPercentage = nftDescriptorMock.calculateStreamedPercentage_({ streamedAmount: 0, depositedAmount: 1337e18 }); diff --git a/test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol b/test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol index 1c5f9403d..47c8db24b 100644 --- a/test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateAttributes.t.sol @@ -2,9 +2,9 @@ // solhint-disable max-line-length,quotes pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract GenerateAttributes_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract GenerateAttributes_Unit_Concrete_Test is Base_Test { function test_GenerateAttributes_Empty() external view { string memory actualAttributes = nftDescriptorMock.generateAttributes_("", "", ""); string memory expectedAttributes = diff --git a/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol b/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol index aed691410..acad1755b 100644 --- a/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateDescription.t.sol @@ -2,9 +2,9 @@ // solhint-disable max-line-length,quotes pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract GenerateDescription_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract GenerateDescription_Unit_Concrete_Test is Base_Test { string internal constant INFO_NON_TRANSFERABLE = unicode"❕INFO: This NFT is non-transferable. It cannot be sold or transferred to another account."; string internal constant INFO_TRANSFERABLE = diff --git a/test/core/unit/concrete/nft-descriptor/generateName.t.sol b/test/core/unit/concrete/nft-descriptor/generateName.t.sol index c5b5b0742..b80b938b2 100644 --- a/test/core/unit/concrete/nft-descriptor/generateName.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateName.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract GenerateName_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract GenerateName_Unit_Concrete_Test is Base_Test { function gn(string memory lockupModel, string memory streamId) internal view returns (string memory) { return nftDescriptorMock.generateName_(lockupModel, streamId); } diff --git a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol index af141f3ed..d2da3edf6 100644 --- a/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol +++ b/test/core/unit/concrete/nft-descriptor/generateSVG.t.sol @@ -5,9 +5,9 @@ pragma solidity >=0.8.22 <0.9.0; 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"; +import { Base_Test } from "test/Base.t.sol"; -contract GenerateSVG_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract GenerateSVG_Unit_Concrete_Test is Base_Test { /// @dev If you need to update the hard-coded token URI: /// 1. Use "vm.writeFile" to log the strings to a file. /// 2. Remember to escape 'Courier New' with \'Courier New\'. diff --git a/test/core/unit/concrete/nft-descriptor/hourglass.t.sol b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol index 5a52295f2..383dbf39f 100644 --- a/test/core/unit/concrete/nft-descriptor/hourglass.t.sol +++ b/test/core/unit/concrete/nft-descriptor/hourglass.t.sol @@ -5,9 +5,9 @@ import { LibString } from "solady/src/utils/LibString.sol"; import { SVGElements } from "src/core/libraries/SVGElements.sol"; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract Hourglass_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract Hourglass_Unit_Concrete_Test is Base_Test { using LibString for string; function test_Hourglass_Pending() external view { diff --git a/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol index f9760302f..be2e10f7c 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyCardType.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { SVGElements } from "src/core/libraries/SVGElements.sol"; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract StringifyCardType_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract StringifyCardType_Unit_Concrete_Test is Base_Test { function test_StringifyCardType() external view { assertEq(nftDescriptorMock.stringifyCardType_(SVGElements.CardType.PROGRESS), "Progress"); assertEq(nftDescriptorMock.stringifyCardType_(SVGElements.CardType.STATUS), "Status"); diff --git a/test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol index 4e5862a32..dc36e7ea6 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyFractionalAmount.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract StringifyFractionalAmount_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract StringifyFractionalAmount_Unit_Concrete_Test is Base_Test { function sfa(uint256 amount) internal view returns (string memory) { return nftDescriptorMock.stringifyFractionalAmount_(amount); } diff --git a/test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol index d0d72913d..2d8dd6d59 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyPercentage.t.sol @@ -1,9 +1,9 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract StringifyPercentage_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract StringifyPercentage_Unit_Concrete_Test is Base_Test { function sp(uint256 percentage) internal view returns (string memory) { return nftDescriptorMock.stringifyPercentage_(percentage); } diff --git a/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol index 5c95970cc..36e7786f8 100644 --- a/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol +++ b/test/core/unit/concrete/nft-descriptor/stringifyStatus.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { Lockup } from "src/core/types/DataTypes.sol"; -import { NFTDescriptor_Unit_Concrete_Test } from "./NFTDescriptor.t.sol"; +import { Base_Test } from "test/Base.t.sol"; -contract StringifyStatus_Unit_Concrete_Test is NFTDescriptor_Unit_Concrete_Test { +contract StringifyStatus_Unit_Concrete_Test is Base_Test { function test_StringifyStatus() external view { assertEq(nftDescriptorMock.stringifyStatus_(Lockup.Status.DEPLETED), "Depleted", "depleted status mismatch"); assertEq(nftDescriptorMock.stringifyStatus_(Lockup.Status.CANCELED), "Canceled", "canceled status mismatch"); diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol index 0d5c97ecc..5d092cd6a 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol @@ -42,6 +42,9 @@ abstract contract CreateWithTimestampsLD_BatchLockup_Fork_Test is Fork_Test { deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: params.startTime, end: params.segments[params.segments.length - 1].timestamp }); + Lockup.CreateWithTimestamps memory createWithTimestamps = Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, @@ -49,10 +52,10 @@ abstract contract CreateWithTimestampsLD_BatchLockup_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.startTime, - endTime: params.segments[params.segments.length - 1].timestamp, + timestamps: timestamps, broker: defaults.brokerNull() }); + BatchLockup.CreateWithTimestampsLD[] memory batchParams = BatchLockupBuilder.fillBatch(createWithTimestamps, params.segments, params.batchSize); diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol index 5eab6a2a3..4772dcb3a 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol @@ -17,6 +17,7 @@ abstract contract CreateWithTimestampsLL_BatchLockup_Fork_Test is Fork_Test { struct CreateWithTimestampsParams { uint128 batchSize; Lockup.Timestamps timestamps; + uint40 cliffTime; address sender; address recipient; uint128 perStreamAmount; @@ -27,11 +28,9 @@ abstract contract CreateWithTimestampsLL_BatchLockup_Fork_Test is Fork_Test { 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); + params.cliffTime = + boundUint40(params.cliffTime, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks); + params.timestamps.end = boundUint40(params.timestamps.end, params.cliffTime + 1 seconds, MAX_UNIX_TIMESTAMP); checkUsers(params.sender, params.recipient); @@ -48,12 +47,11 @@ abstract contract CreateWithTimestampsLL_BatchLockup_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.timestamps.start, - endTime: params.timestamps.end, + timestamps: params.timestamps, broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLL[] memory batchParams = - BatchLockupBuilder.fillBatch(createParams, params.timestamps.cliff, params.batchSize); + BatchLockupBuilder.fillBatch(createParams, params.cliffTime, params.batchSize); // Asset flow: sender → batch → Sablier expectCallToTransferFrom({ @@ -65,7 +63,7 @@ abstract contract CreateWithTimestampsLL_BatchLockup_Fork_Test is Fork_Test { expectMultipleCallsToCreateWithTimestampsLL({ count: uint64(params.batchSize), params: createParams, - cliff: params.timestamps.cliff + cliff: params.cliffTime }); expectMultipleCallsToTransferFrom({ asset: FORK_ASSET, diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol index eddc66bbc..a2abde40e 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol @@ -34,6 +34,9 @@ abstract contract CreateWithTimestampsLT_BatchLockup_Fork_Test is Fork_Test { brokerFee: defaults.brokerNull().fee }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: params.startTime, end: params.tranches[params.tranches.length - 1].timestamp }); + checkUsers(params.sender, params.recipient); uint256 firstStreamId = lockup.nextStreamId(); @@ -49,8 +52,7 @@ abstract contract CreateWithTimestampsLT_BatchLockup_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - startTime: params.startTime, - endTime: params.tranches[params.tranches.length - 1].timestamp, + timestamps: timestamps, broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLT[] memory batchParams = diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index c0983e6af..e9339d7f1 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -44,6 +44,11 @@ abstract contract Assertions is PRBMathAssertions { assertEq(address(a), address(b), err); } + /// @dev Compares two {Lockup.Model} enum values. + function assertEq(Lockup.Model a, Lockup.Model b) internal pure { + assertEq(uint8(a), uint8(b), "lockup model"); + } + /// @dev Compares two {Lockup.Timestamps} struct entities. function assertEq(Lockup.Timestamps memory a, Lockup.Timestamps memory b) internal { assertEqUint40(a.end, b.end, "timestamps.end"); diff --git a/test/utils/BatchLockupBuilder.sol b/test/utils/BatchLockupBuilder.sol index d1828f6a4..1886f11d1 100644 --- a/test/utils/BatchLockupBuilder.sol +++ b/test/utils/BatchLockupBuilder.sol @@ -24,7 +24,7 @@ library BatchLockupBuilder { /// @notice Turns the inputs into an array of {BatchLockup.CreateWithDurationsLD} structs. function fillBatch( Lockup.CreateWithDurations memory params, - LockupDynamic.SegmentWithDuration[] memory segments, + LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations, uint256 batchSize ) internal @@ -38,7 +38,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - segments: segments, + segmentsWithDuration: segmentsWithDurations, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -100,7 +100,7 @@ library BatchLockupBuilder { /// @notice Turns the inputs into an array of {BatchLockup.CreateWithDurationsLT} structs. function fillBatch( Lockup.CreateWithDurations memory params, - LockupTranched.TrancheWithDuration[] memory tranches, + LockupTranched.TrancheWithDuration[] memory tranchesWithDuration, uint256 batchSize ) internal @@ -114,7 +114,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - tranches: tranches, + tranchesWithDuration: tranchesWithDuration, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -152,7 +152,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - startTime: params.startTime, + startTime: params.timestamps.start, segments: segments, broker: params.broker }); @@ -177,7 +177,7 @@ library BatchLockupBuilder { /// @notice Turns the inputs into an array of {BatchLockup.CreateWithTimestampsLL} structs. function fillBatch( Lockup.CreateWithTimestamps memory params, - uint40 cliff, + uint40 cliffTime, uint256 batchSize ) internal @@ -191,7 +191,8 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - timestamps: Lockup.Timestamps({ start: params.startTime, cliff: cliff, end: params.endTime }), + timestamps: params.timestamps, + cliffTime: cliffTime, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -229,7 +230,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - startTime: params.startTime, + startTime: params.timestamps.start, tranches: tranches, broker: params.broker }); diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index e057c7fc7..ae7123fd6 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -136,16 +136,8 @@ contract Defaults is Constants, Merkle { return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } - function lockupDynamicTimestamps() public view returns (Lockup.Timestamps memory) { - return Lockup.Timestamps({ start: START_TIME, cliff: 0, end: END_TIME }); - } - - function lockupLinearTimestamps() public view returns (Lockup.Timestamps memory) { - return Lockup.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); - } - - function lockupTranchedTimestamps() public view returns (Lockup.Timestamps memory) { - return Lockup.Timestamps({ start: START_TIME, cliff: 0, end: END_TIME }); + function lockupTimestamps() public view returns (Lockup.Timestamps memory) { + return Lockup.Timestamps({ start: START_TIME, end: END_TIME }); } function segments() public view returns (LockupDynamic.Segment[] memory segments_) { @@ -229,8 +221,7 @@ contract Defaults is Constants, Merkle { asset: asset, cancelable: true, transferable: true, - startTime: START_TIME, - endTime: END_TIME, + timestamps: lockupTimestamps(), broker: broker() }); } diff --git a/test/utils/Modifiers.sol b/test/utils/Modifiers.sol index c0bb9c384..5d33a85d0 100644 --- a/test/utils/Modifiers.sol +++ b/test/utils/Modifiers.sol @@ -337,6 +337,14 @@ abstract contract Modifiers is Fuzzers { _; } + modifier whenDepositAmountEqualsTrancheAmountsSum() { + _; + } + + modifier whenDepositAmountEqualsSegmentAmountsSum() { + _; + } + /*////////////////////////////////////////////////////////////////////////// CREATE-MERKLE //////////////////////////////////////////////////////////////////////////*/