From 86adfca1dd1e987e5ec0504865ba1ebbb93af670 Mon Sep 17 00:00:00 2001 From: smol-ninja Date: Tue, 5 Nov 2024 10:55:56 +0000 Subject: [PATCH] test: refactor all tests according to singleton contracts test: update periphery tests chore: bump version to v1.3.0 This is a combination of 14 commits. test: update tests accordingly to singletone architecture test: update fork tests for core test(core): refactor integration tests for core test(integration): rename Lockup_Create_Integration_Shared_Test to Lockup_Integration_Shared_Test test: dry'ify concrete tests test(core): update fuzz tests test(core): updates invariant tests test(benchmark): update benchmark test: fix file path build: link libraries to optimized build test: move nullStreamId variable into Integration tests build: etch helpers bytecode onto dummy addresses for optimized tests test: update precompiles test: fix benchmarks test: polish librariy linkage test: mock lockup in periphery fork test test: deploy libraries through DeployOptimized contract --- .solhint.json | 1 + benchmark/BatchLockup.Gas.t.sol | 58 ++- benchmark/Benchmark.t.sol | 9 +- benchmark/EstimateMaxCount.t.sol | 12 +- benchmark/LockupDynamic.Gas.t.sol | 98 ++-- benchmark/LockupLinear.Gas.t.sol | 57 +-- benchmark/LockupTranched.Gas.t.sol | 98 ++-- benchmark/results/SablierBatchLockup.md | 60 +-- benchmark/results/SablierLockupDynamic.md | 31 -- benchmark/results/SablierLockupLinear.md | 19 - benchmark/results/SablierLockupTranched.md | 31 -- benchmark/results/SablierLockup_Dynamic.md | 31 ++ benchmark/results/SablierLockup_Linear.md | 19 + benchmark/results/SablierLockup_Tranched.md | 31 ++ foundry.toml | 7 + package.json | 2 +- precompiles/Precompiles.sol | 4 +- script/Base.s.sol | 22 +- shell/update-counts.sh | 2 +- test/Base.t.sol | 39 +- test/core/fork/LockupDynamic.t.sol | 158 +++--- test/core/fork/LockupLinear.t.sol | 144 +++--- test/core/fork/LockupTranched.t.sol | 154 +++--- test/core/fork/NFTDescriptor.t.sol | 99 ++-- test/core/fork/assets/DAI.t.sol | 12 +- test/core/fork/assets/EURS.t.sol | 12 +- test/core/fork/assets/SHIB.t.sol | 12 +- test/core/fork/assets/USDC.t.sol | 12 +- test/core/fork/assets/USDT.t.sol | 12 +- test/core/integration/Integration.t.sol | 88 ++-- .../{lockup-linear => }/constructor.t.sol | 28 +- .../allow-to-hook/allowToHook.t.sol | 8 +- .../allow-to-hook/allowToHook.tree | 0 .../{lockup => lockup-base}/batch/batch.t.sol | 6 +- .../{lockup => lockup-base}/batch/batch.tree | 0 .../{lockup => lockup-base}/burn/burn.t.sol | 21 +- .../{lockup => lockup-base}/burn/burn.tree | 0 .../cancel-multiple/cancelMultiple.t.sol | 68 +-- .../cancel-multiple/cancelMultiple.tree | 0 .../cancel/cancel.t.sol | 100 ++-- .../cancel/cancel.tree | 0 .../get-asset/getAsset.t.sol | 8 +- .../get-asset/getAsset.tree | 0 .../getDepositedAmount.t.sol | 8 +- .../getDepositedAmount.tree | 0 .../get-end-time/getEndTime.t.sol | 8 +- .../get-end-time/getEndTime.tree | 0 .../get-recipient/getRecipient.t.sol | 1 - .../get-recipient/getRecipient.tree | 0 .../getRefundedAmount.t.sol | 3 +- .../getRefundedAmount.tree | 0 .../get-sender/getSender.t.sol | 8 +- .../get-sender/getSender.tree | 0 .../get-start-time/getStartTime.t.sol | 6 +- .../get-start-time/getStartTime.tree | 0 .../getWithdrawnAmount.t.sol | 3 +- .../getWithdrawnAmount.tree | 0 .../is-allowed-to-hook/isAllowedToHook.t.sol | 0 .../is-allowed-to-hook/isAllowedToHook.tree | 0 .../is-cancelable/isCancelable.t.sol | 8 +- .../is-cancelable/isCancelable.tree | 0 .../is-cold/isCold.t.sol | 3 +- .../is-cold/isCold.tree | 0 .../is-depleted/isDepleted.t.sol | 3 +- .../is-depleted/isDepleted.tree | 0 .../is-stream/isStream.t.sol | 1 - .../is-stream/isStream.tree | 0 .../is-transferable/isTransferable.t.sol | 3 +- .../is-transferable/isTransferable.tree | 0 .../is-warm/isWarm.t.sol | 3 +- .../is-warm/isWarm.tree | 0 .../refundableAmountOf.t.sol | 6 +- .../refundableAmountOf.tree | 0 .../renounce/renounce.t.sol | 31 +- .../renounce/renounce.tree | 0 .../set-nft-descriptor/setNFTDescriptor.t.sol | 8 +- .../set-nft-descriptor/setNFTDescriptor.tree | 0 .../status-of/statusOf.t.sol | 3 +- .../status-of/statusOf.tree | 0 .../streamed-amount-of/streamedAmountOf.t.sol | 3 +- .../streamed-amount-of/streamedAmountOf.tree | 0 .../transfer-from/transferFrom.t.sol | 4 +- .../transfer-from/transferFrom.tree | 0 .../was-canceled/wasCanceled.t.sol | 3 +- .../was-canceled/wasCanceled.tree | 0 .../withdraw-hooks/withdrawHooks.t.sol | 54 ++- .../withdraw-hooks/withdrawHooks.tree | 0 .../withdrawMaxAndTransfer.t.sol | 20 +- .../withdrawMaxAndTransfer.tree | 0 .../withdraw-max/withdrawMax.t.sol | 6 +- .../withdraw-max/withdrawMax.tree | 0 .../withdraw-multiple/withdrawMultiple.t.sol | 101 ++-- .../withdraw-multiple/withdrawMultiple.tree | 0 .../withdraw/withdraw.t.sol | 80 ++- .../withdraw/withdraw.tree | 0 .../withdrawableAmountOf.t.sol | 3 +- .../withdrawableAmountOf.tree | 0 .../lockup-dynamic/LockupDynamic.t.sol | 339 +++++++------ .../concrete/lockup-dynamic/constructor.t.sol | 50 -- ...ions.t.sol => createWithDurationsLD.t.sol} | 77 +-- ...ations.tree => createWithDurationsLD.tree} | 2 +- ...mps.t.sol => createWithTimestampsLD.t.sol} | 103 ++-- ...tamps.tree => createWithTimestampsLD.tree} | 2 +- .../get-segments/getSegments.t.sol | 12 +- .../get-segments/getSegments.tree | 2 +- .../lockup-dynamic/get-stream/getStream.t.sol | 35 -- .../lockup-dynamic/get-stream/getStream.tree | 9 - .../get-timestamps/getTimestamps.t.sol | 16 +- .../get-timestamps/getTimestamps.tree | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 23 +- .../streamed-amount-of/streamedAmountOf.tree | 2 +- .../lockup-dynamic/token-uri/tokenURI.t.sol | 15 +- .../lockup-dynamic/token-uri/tokenURI.tree | 2 +- .../withdrawableAmountOf.t.sol | 20 +- .../withdrawableAmountOf.tree | 2 +- .../concrete/lockup-linear/LockupLinear.t.sol | 339 +++++++------ ...ions.t.sol => createWithDurationsLL.t.sol} | 60 +-- ...ations.tree => createWithDurationsLL.tree} | 2 +- ...mps.t.sol => createWithTimestampsLL.t.sol} | 109 +++-- ...tamps.tree => createWithTimestampsLL.tree} | 2 +- .../get-cliff-time/getCliffTime.t.sol | 14 +- .../get-cliff-time/getCliffTime.tree | 2 +- .../lockup-linear/get-stream/getStream.t.sol | 33 -- .../lockup-linear/get-stream/getStream.tree | 9 - .../get-timestamps/getTimestamps.t.sol | 16 +- .../get-timestamps/getTimestamps.tree | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 36 +- .../streamed-amount-of/streamedAmountOf.tree | 2 +- .../lockup-linear/token-uri/tokenURI.t.sol | 15 +- .../lockup-linear/token-uri/tokenURI.tree | 2 +- .../withdrawableAmountOf.t.sol | 20 +- .../withdrawableAmountOf.tree | 2 +- .../lockup-tranched/LockupTranched.t.sol | 340 +++++++------ .../lockup-tranched/constructor.t.sol | 50 -- ...ions.t.sol => createWithDurationsLT.t.sol} | 77 +-- ...ations.tree => createWithDurationsLT.tree} | 2 +- ...mps.t.sol => createWithTimestampsLT.t.sol} | 96 ++-- ...tamps.tree => createWithTimestampsLT.tree} | 2 +- .../get-stream/getStream.t.sol | 34 -- .../lockup-tranched/get-stream/getStream.tree | 9 - .../get-timestamps/getTimestamps.t.sol | 16 +- .../get-timestamps/getTimestamps.tree | 2 +- .../get-tranches/getTranches.t.sol | 12 +- .../get-tranches/getTranches.tree | 2 +- .../streamed-amount-of/streamedAmountOf.t.sol | 21 +- .../streamed-amount-of/streamedAmountOf.tree | 2 +- .../lockup-tranched/token-uri/tokenURI.t.sol | 17 +- .../lockup-tranched/token-uri/tokenURI.tree | 2 +- .../withdrawableAmountOf.t.sol | 20 +- .../withdrawableAmountOf.tree | 2 +- .../nft-descriptor/map-symbol/mapSymbol.t.sol | 18 +- .../nft-descriptor/map-symbol/mapSymbol.tree | 7 +- .../fuzz/{lockup => lockup-base}/cancel.t.sol | 27 +- .../cancelMultiple.t.sol | 30 +- .../getWithdrawnAmount.t.sol | 0 .../refundableAmountOf.t.sol | 0 .../{lockup => lockup-base}/withdraw.t.sol | 6 +- .../{lockup => lockup-base}/withdrawMax.t.sol | 6 +- .../withdrawMaxAndTransfer.t.sol | 5 +- .../withdrawMultiple.t.sol | 35 +- .../fuzz/lockup-dynamic/LockupDynamic.t.sol | 114 +++-- ...ions.t.sol => createWithDurationsLD.t.sol} | 62 ++- ...mps.t.sol => createWithTimestampsLD.t.sol} | 109 ++--- .../lockup-dynamic/streamedAmountOf.t.sol | 37 +- .../fuzz/lockup-dynamic/withdraw.t.sol | 41 +- .../lockup-dynamic/withdrawableAmountOf.t.sol | 30 +- .../fuzz/lockup-linear/LockupLinear.t.sol | 117 +++-- ...ions.t.sol => createWithDurationsLL.t.sol} | 54 ++- ...mps.t.sol => createWithTimestampsLL.t.sol} | 98 ++-- .../fuzz/lockup-linear/streamedAmountOf.t.sol | 24 +- .../lockup-linear/withdrawableAmountOf.t.sol | 27 +- .../fuzz/lockup-tranched/LockupTranched.t.sol | 109 +++-- ...ions.t.sol => createWithDurationsLT.t.sol} | 61 ++- ...mps.t.sol => createWithTimestampsLT.t.sol} | 107 ++--- .../lockup-tranched/streamedAmountOf.t.sol | 26 +- .../fuzz/lockup-tranched/withdraw.t.sol | 41 +- .../withdrawableAmountOf.t.sol | 24 +- .../shared/lockup-dynamic/LockupDynamic.t.sol | 178 ------- .../shared/lockup-linear/LockupLinear.t.sol | 144 ------ .../lockup-tranched/LockupTranched.t.sol | 187 -------- .../integration/shared/lockup/Lockup.t.sol | 454 ++++++++++++++++++ .../shared/lockup/LockupDynamic.t.sol | 26 + .../shared/lockup/LockupLinear.t.sol | 26 + .../shared/lockup/LockupTranched.t.sol | 26 + .../shared/lockup/cancelMultiple.t.sol | 33 -- .../shared/lockup/withdrawMultiple.t.sol | 56 --- test/core/invariant/Invariant.t.sol | 417 +++++++++++++++- test/core/invariant/Lockup.t.sol | 336 ------------- test/core/invariant/LockupDynamic.t.sol | 79 --- test/core/invariant/LockupLinear.t.sol | 93 ---- test/core/invariant/LockupTranched.t.sol | 79 --- test/core/invariant/handlers/BaseHandler.sol | 8 +- .../handlers/LockupCreateHandler.sol | 278 +++++++++++ .../handlers/LockupDynamicCreateHandler.sol | 120 ----- .../handlers/LockupDynamicHandler.sol | 21 - .../core/invariant/handlers/LockupHandler.sol | 7 +- .../handlers/LockupLinearCreateHandler.sol | 111 ----- .../handlers/LockupLinearHandler.sol | 21 - .../handlers/LockupTranchedCreateHandler.sol | 120 ----- .../handlers/LockupTranchedHandler.sol | 21 - test/mocks/Hooks.sol | 6 +- test/periphery/Periphery.t.sol | 72 +-- test/periphery/fork/Fork.t.sol | 22 +- test/periphery/fork/assets/USDC.t.sol | 18 +- test/periphery/fork/assets/USDT.t.sol | 18 +- .../batch-lockup/createWithTimestampsLD.t.sol | 22 +- .../batch-lockup/createWithTimestampsLL.t.sol | 25 +- .../batch-lockup/createWithTimestampsLT.t.sol | 22 +- .../fork/merkle-campaign/MerkleLL.t.sol | 44 +- .../fork/merkle-campaign/MerkleLT.t.sol | 47 +- .../createWithDurationsLD.t.sol | 9 +- .../createWithDurationsLL.t.sol | 10 +- .../createWithDurationsLT.t.sol | 10 +- .../createWithTimestampsLD.t.sol | 10 +- .../createWithTimestamps.t.sol | 10 +- .../createWithTimestampsLT.t.sol | 10 +- .../merkle-campaign/MerkleCampaign.t.sol | 4 +- .../create-merkle-ll/createMerkleLL.t.sol | 8 +- .../create-merkle-lt/createMerkleLT.t.sol | 8 +- .../merkle-campaign/ll/claim/claim.t.sol | 38 +- .../merkle-campaign/ll/constructor.t.sol | 14 +- .../merkle-campaign/lt/claim/claim.t.sol | 44 +- .../merkle-campaign/lt/constructor.t.sol | 14 +- test/utils/Assertions.sol | 65 +-- test/utils/BaseScript.t.sol | 2 +- test/utils/BatchLockupBuilder.sol | 44 +- test/utils/Calculations.sol | 55 +-- test/utils/Defaults.sol | 190 ++------ test/utils/DeployOptimized.sol | 94 ++-- test/utils/Modifiers.sol | 4 + test/utils/Precompiles.t.sol | 65 +-- 231 files changed, 4153 insertions(+), 4944 deletions(-) delete mode 100644 benchmark/results/SablierLockupDynamic.md delete mode 100644 benchmark/results/SablierLockupLinear.md delete mode 100644 benchmark/results/SablierLockupTranched.md create mode 100644 benchmark/results/SablierLockup_Dynamic.md create mode 100644 benchmark/results/SablierLockup_Linear.md create mode 100644 benchmark/results/SablierLockup_Tranched.md rename test/core/integration/concrete/{lockup-linear => }/constructor.t.sol (51%) rename test/core/integration/concrete/{lockup => lockup-base}/allow-to-hook/allowToHook.t.sol (85%) rename test/core/integration/concrete/{lockup => lockup-base}/allow-to-hook/allowToHook.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/batch/batch.t.sol (87%) rename test/core/integration/concrete/{lockup => lockup-base}/batch/batch.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/burn/burn.t.sol (86%) rename test/core/integration/concrete/{lockup => lockup-base}/burn/burn.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/cancel-multiple/cancelMultiple.t.sol (56%) rename test/core/integration/concrete/{lockup => lockup-base}/cancel-multiple/cancelMultiple.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/cancel/cancel.t.sol (71%) rename test/core/integration/concrete/{lockup => lockup-base}/cancel/cancel.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-asset/getAsset.t.sol (72%) rename test/core/integration/concrete/{lockup => lockup-base}/get-asset/getAsset.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-deposited-amount/getDepositedAmount.t.sol (78%) rename test/core/integration/concrete/{lockup => lockup-base}/get-deposited-amount/getDepositedAmount.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-end-time/getEndTime.t.sol (71%) rename test/core/integration/concrete/{lockup => lockup-base}/get-end-time/getEndTime.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-recipient/getRecipient.t.sol (97%) rename test/core/integration/concrete/{lockup => lockup-base}/get-recipient/getRecipient.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-refunded-amount/getRefundedAmount.t.sol (97%) rename test/core/integration/concrete/{lockup => lockup-base}/get-refunded-amount/getRefundedAmount.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-sender/getSender.t.sol (70%) rename test/core/integration/concrete/{lockup => lockup-base}/get-sender/getSender.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-start-time/getStartTime.t.sol (80%) rename test/core/integration/concrete/{lockup => lockup-base}/get-start-time/getStartTime.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/get-withdrawn-amount/getWithdrawnAmount.t.sol (95%) rename test/core/integration/concrete/{lockup => lockup-base}/get-withdrawn-amount/getWithdrawnAmount.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-allowed-to-hook/isAllowedToHook.t.sol (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-allowed-to-hook/isAllowedToHook.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-cancelable/isCancelable.t.sol (77%) rename test/core/integration/concrete/{lockup => lockup-base}/is-cancelable/isCancelable.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-cold/isCold.t.sol (95%) rename test/core/integration/concrete/{lockup => lockup-base}/is-cold/isCold.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-depleted/isDepleted.t.sol (92%) rename test/core/integration/concrete/{lockup => lockup-base}/is-depleted/isDepleted.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-stream/isStream.t.sol (93%) rename test/core/integration/concrete/{lockup => lockup-base}/is-stream/isStream.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-transferable/isTransferable.t.sol (92%) rename test/core/integration/concrete/{lockup => lockup-base}/is-transferable/isTransferable.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/is-warm/isWarm.t.sol (95%) rename test/core/integration/concrete/{lockup => lockup-base}/is-warm/isWarm.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/refundable-amount-of/refundableAmountOf.t.sol (95%) rename test/core/integration/concrete/{lockup => lockup-base}/refundable-amount-of/refundableAmountOf.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/renounce/renounce.t.sol (76%) rename test/core/integration/concrete/{lockup => lockup-base}/renounce/renounce.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/set-nft-descriptor/setNFTDescriptor.t.sol (87%) rename test/core/integration/concrete/{lockup => lockup-base}/set-nft-descriptor/setNFTDescriptor.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/status-of/statusOf.t.sol (97%) rename test/core/integration/concrete/{lockup => lockup-base}/status-of/statusOf.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/streamed-amount-of/streamedAmountOf.t.sol (97%) rename test/core/integration/concrete/{lockup => lockup-base}/streamed-amount-of/streamedAmountOf.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/transfer-from/transferFrom.t.sol (91%) rename test/core/integration/concrete/{lockup => lockup-base}/transfer-from/transferFrom.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/was-canceled/wasCanceled.t.sol (92%) rename test/core/integration/concrete/{lockup => lockup-base}/was-canceled/wasCanceled.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-hooks/withdrawHooks.t.sol (68%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-hooks/withdrawHooks.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol (91%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-max/withdrawMax.t.sol (94%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-max/withdrawMax.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-multiple/withdrawMultiple.t.sol (53%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw-multiple/withdrawMultiple.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw/withdraw.t.sol (85%) rename test/core/integration/concrete/{lockup => lockup-base}/withdraw/withdraw.tree (100%) rename test/core/integration/concrete/{lockup => lockup-base}/withdrawable-amount-of/withdrawableAmountOf.t.sol (97%) rename test/core/integration/concrete/{lockup => lockup-base}/withdrawable-amount-of/withdrawableAmountOf.tree (100%) delete mode 100644 test/core/integration/concrete/lockup-dynamic/constructor.t.sol rename test/core/integration/concrete/lockup-dynamic/create-with-durations/{createWithDurations.t.sol => createWithDurationsLD.t.sol} (67%) rename test/core/integration/concrete/lockup-dynamic/create-with-durations/{createWithDurations.tree => createWithDurationsLD.tree} (94%) rename test/core/integration/concrete/lockup-dynamic/create-with-timestamps/{createWithTimestamps.t.sol => createWithTimestampsLD.t.sol} (74%) rename test/core/integration/concrete/lockup-dynamic/create-with-timestamps/{createWithTimestamps.tree => createWithTimestampsLD.tree} (98%) delete mode 100644 test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol delete mode 100644 test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree rename test/core/integration/concrete/lockup-linear/create-with-durations/{createWithDurations.t.sol => createWithDurationsLL.t.sol} (64%) rename test/core/integration/concrete/lockup-linear/create-with-durations/{createWithDurations.tree => createWithDurationsLL.tree} (94%) rename test/core/integration/concrete/lockup-linear/create-with-timestamps/{createWithTimestamps.t.sol => createWithTimestampsLL.t.sol} (62%) rename test/core/integration/concrete/lockup-linear/create-with-timestamps/{createWithTimestamps.tree => createWithTimestampsLL.tree} (97%) delete mode 100644 test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol delete mode 100644 test/core/integration/concrete/lockup-linear/get-stream/getStream.tree delete mode 100644 test/core/integration/concrete/lockup-tranched/constructor.t.sol rename test/core/integration/concrete/lockup-tranched/create-with-durations/{createWithDurations.t.sol => createWithDurationsLT.t.sol} (67%) rename test/core/integration/concrete/lockup-tranched/create-with-durations/{createWithDurations.tree => createWithDurationsLT.tree} (94%) rename test/core/integration/concrete/lockup-tranched/create-with-timestamps/{createWithTimestamps.t.sol => createWithTimestampsLT.t.sol} (76%) rename test/core/integration/concrete/lockup-tranched/create-with-timestamps/{createWithTimestamps.tree => createWithTimestampsLT.tree} (98%) delete mode 100644 test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol delete mode 100644 test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree rename test/core/integration/fuzz/{lockup => lockup-base}/cancel.t.sol (77%) rename test/core/integration/fuzz/{lockup => lockup-base}/cancelMultiple.t.sol (74%) rename test/core/integration/fuzz/{lockup => lockup-base}/getWithdrawnAmount.t.sol (100%) rename test/core/integration/fuzz/{lockup => lockup-base}/refundableAmountOf.t.sol (100%) rename test/core/integration/fuzz/{lockup => lockup-base}/withdraw.t.sol (96%) rename test/core/integration/fuzz/{lockup => lockup-base}/withdrawMax.t.sol (94%) rename test/core/integration/fuzz/{lockup => lockup-base}/withdrawMaxAndTransfer.t.sol (94%) rename test/core/integration/fuzz/{lockup => lockup-base}/withdrawMultiple.t.sol (70%) rename test/core/integration/fuzz/lockup-dynamic/{createWithDurations.t.sol => createWithDurationsLD.t.sol} (61%) rename test/core/integration/fuzz/lockup-dynamic/{createWithTimestamps.t.sol => createWithTimestampsLD.t.sol} (72%) rename test/core/integration/fuzz/lockup-linear/{createWithDurations.t.sol => createWithDurationsLL.t.sol} (61%) rename test/core/integration/fuzz/lockup-linear/{createWithTimestamps.t.sol => createWithTimestampsLL.t.sol} (62%) rename test/core/integration/fuzz/lockup-tranched/{createWithDurations.t.sol => createWithDurationsLT.t.sol} (61%) rename test/core/integration/fuzz/lockup-tranched/{createWithTimestamps.t.sol => createWithTimestampsLT.t.sol} (72%) delete mode 100644 test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol delete mode 100644 test/core/integration/shared/lockup-linear/LockupLinear.t.sol delete mode 100644 test/core/integration/shared/lockup-tranched/LockupTranched.t.sol create mode 100644 test/core/integration/shared/lockup/Lockup.t.sol create mode 100644 test/core/integration/shared/lockup/LockupDynamic.t.sol create mode 100644 test/core/integration/shared/lockup/LockupLinear.t.sol create mode 100644 test/core/integration/shared/lockup/LockupTranched.t.sol delete mode 100644 test/core/integration/shared/lockup/cancelMultiple.t.sol delete mode 100644 test/core/integration/shared/lockup/withdrawMultiple.t.sol delete mode 100644 test/core/invariant/Lockup.t.sol delete mode 100644 test/core/invariant/LockupDynamic.t.sol delete mode 100644 test/core/invariant/LockupLinear.t.sol delete mode 100644 test/core/invariant/LockupTranched.t.sol create mode 100644 test/core/invariant/handlers/LockupCreateHandler.sol delete mode 100644 test/core/invariant/handlers/LockupDynamicCreateHandler.sol delete mode 100644 test/core/invariant/handlers/LockupDynamicHandler.sol delete mode 100644 test/core/invariant/handlers/LockupLinearCreateHandler.sol delete mode 100644 test/core/invariant/handlers/LockupLinearHandler.sol delete mode 100644 test/core/invariant/handlers/LockupTranchedCreateHandler.sol delete mode 100644 test/core/invariant/handlers/LockupTranchedHandler.sol diff --git a/.solhint.json b/.solhint.json index 63dd2f71c..7ac084cfe 100644 --- a/.solhint.json +++ b/.solhint.json @@ -9,6 +9,7 @@ "func-name-mixedcase": "off", "func-visibility": ["error", { "ignoreConstructors": true }], "gas-custom-errors": "off", + "max-states-count": ["warn", 20], "imports-order": "warn", "max-line-length": ["error", 124], "named-parameters-mapping": "warn", diff --git a/benchmark/BatchLockup.Gas.t.sol b/benchmark/BatchLockup.Gas.t.sol index 8a655d755..2ab0baedf 100644 --- a/benchmark/BatchLockup.Gas.t.sol +++ b/benchmark/BatchLockup.Gas.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { LockupDynamic, LockupTranched } from "../src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupTranched } from "../src/core/types/DataTypes.sol"; import { BatchLockup } from "../src/periphery/types/DataTypes.sol"; import { BatchLockupBuilder } from "../test/utils/BatchLockupBuilder.sol"; @@ -58,13 +58,14 @@ contract BatchLockup_Gas_Test is Benchmark_Test { //////////////////////////////////////////////////////////////////////////*/ function gasCreateWithDurationsLD(uint256 batchSize, uint256 segmentsCount) internal { - LockupDynamic.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNullLD(); + Lockup.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNull(); createParams.totalAmount = uint128(AMOUNT_PER_ITEM * segmentsCount); - createParams.segments = _generateSegmentsWithDuration(segmentsCount); - BatchLockup.CreateWithDurationsLD[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + LockupDynamic.SegmentWithDuration[] memory segments = _generateSegmentsWithDuration(segmentsCount); + BatchLockup.CreateWithDurationsLD[] memory params = + BatchLockupBuilder.fillBatch(createParams, segments, batchSize); uint256 initialGas = gasleft(); - batchLockup.createWithDurationsLD(lockupDynamic, dai, params); + batchLockup.createWithDurationsLD(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( @@ -82,14 +83,16 @@ contract BatchLockup_Gas_Test is Benchmark_Test { } function gasCreateWithTimestampsLD(uint256 batchSize, uint256 segmentsCount) internal { - LockupDynamic.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNullLD(); + Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNull(); + LockupDynamic.Segment[] memory segments = _generateSegments(segmentsCount); createParams.startTime = getBlockTimestamp(); + createParams.endTime = segments[segments.length - 1].timestamp; createParams.totalAmount = uint128(AMOUNT_PER_ITEM * segmentsCount); - createParams.segments = _generateSegments(segmentsCount); - BatchLockup.CreateWithTimestampsLD[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + BatchLockup.CreateWithTimestampsLD[] memory params = + BatchLockupBuilder.fillBatch(createParams, segments, batchSize); uint256 initialGas = gasleft(); - batchLockup.createWithTimestampsLD(lockupDynamic, dai, params); + batchLockup.createWithTimestampsLD(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( @@ -107,11 +110,14 @@ contract BatchLockup_Gas_Test is Benchmark_Test { } function gasCreateWithDurationsLL(uint256 batchSize) internal { - BatchLockup.CreateWithDurationsLL[] memory params = - BatchLockupBuilder.fillBatch({ params: defaults.createWithDurationsBrokerNullLL(), batchSize: batchSize }); + BatchLockup.CreateWithDurationsLL[] memory params = BatchLockupBuilder.fillBatch({ + params: defaults.createWithDurationsBrokerNull(), + durations: defaults.durations(), + batchSize: batchSize + }); uint256 initialGas = gasleft(); - batchLockup.createWithDurationsLL(lockupLinear, dai, params); + batchLockup.createWithDurationsLL(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( @@ -123,11 +129,14 @@ contract BatchLockup_Gas_Test is Benchmark_Test { } function gasCreateWithTimestampsLL(uint256 batchSize) internal { - BatchLockup.CreateWithTimestampsLL[] memory params = - BatchLockupBuilder.fillBatch({ params: defaults.createWithTimestampsBrokerNullLL(), batchSize: batchSize }); + BatchLockup.CreateWithTimestampsLL[] memory params = BatchLockupBuilder.fillBatch({ + params: defaults.createWithTimestampsBrokerNull(), + cliff: defaults.CLIFF_TIME(), + batchSize: batchSize + }); uint256 initialGas = gasleft(); - batchLockup.createWithTimestampsLL(lockupLinear, dai, params); + batchLockup.createWithTimestampsLL(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( @@ -139,13 +148,14 @@ contract BatchLockup_Gas_Test is Benchmark_Test { } function gasCreateWithDurationsLT(uint256 batchSize, uint256 tranchesCount) internal { - LockupTranched.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNullLT(); + Lockup.CreateWithDurations memory createParams = defaults.createWithDurationsBrokerNull(); + LockupTranched.TrancheWithDuration[] memory tranches = _generateTranchesWithDuration(tranchesCount); createParams.totalAmount = uint128(AMOUNT_PER_ITEM * tranchesCount); - createParams.tranches = _generateTranchesWithDuration(tranchesCount); - BatchLockup.CreateWithDurationsLT[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + BatchLockup.CreateWithDurationsLT[] memory params = + BatchLockupBuilder.fillBatch(createParams, tranches, batchSize); uint256 initialGas = gasleft(); - batchLockup.createWithDurationsLT(lockupTranched, dai, params); + batchLockup.createWithDurationsLT(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( @@ -163,14 +173,16 @@ contract BatchLockup_Gas_Test is Benchmark_Test { } function gasCreateWithTimestampsLT(uint256 batchSize, uint256 tranchesCount) internal { - LockupTranched.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNullLT(); + Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestampsBrokerNull(); + LockupTranched.Tranche[] memory tranches = _generateTranches(tranchesCount); createParams.startTime = getBlockTimestamp(); + createParams.endTime = tranches[tranches.length - 1].timestamp; createParams.totalAmount = uint128(AMOUNT_PER_ITEM * tranchesCount); - createParams.tranches = _generateTranches(tranchesCount); - BatchLockup.CreateWithTimestampsLT[] memory params = BatchLockupBuilder.fillBatch(createParams, batchSize); + BatchLockup.CreateWithTimestampsLT[] memory params = + BatchLockupBuilder.fillBatch(createParams, tranches, batchSize); uint256 initialGas = gasleft(); - batchLockup.createWithTimestampsLT(lockupTranched, dai, params); + batchLockup.createWithTimestampsLT(lockup, dai, params); string memory gasUsed = vm.toString(initialGas - gasleft()); contentToAppend = string.concat( diff --git a/benchmark/Benchmark.t.sol b/benchmark/Benchmark.t.sol index 4e249e816..72ba000ae 100644 --- a/benchmark/Benchmark.t.sol +++ b/benchmark/Benchmark.t.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierLockup } from "../src/core/interfaces/ISablierLockup.sol"; import { Base_Test } from "../test/Base.t.sol"; /// @notice Benchmark contract with common logic needed by all tests. @@ -24,8 +23,6 @@ abstract contract Benchmark_Test is Base_Test { /// @dev A variable used to store the content to append to the results file. string internal contentToAppend; - ISablierLockup internal lockup; - uint256[7] internal streamIds = [50, 51, 52, 53, 54, 55, 56]; /*////////////////////////////////////////////////////////////////////////// @@ -167,9 +164,9 @@ abstract contract Benchmark_Test is Base_Test { /// @dev Internal function to creates a few streams in each Lockup contract. function _createFewStreams() internal { for (uint128 i = 0; i < 100; ++i) { - lockupDynamic.createWithTimestamps(defaults.createWithTimestampsLD()); - lockupLinear.createWithTimestamps(defaults.createWithTimestampsLL()); - lockupTranched.createWithTimestamps(defaults.createWithTimestampsLT()); + lockup.createWithTimestampsLD(defaults.createWithTimestamps(), defaults.segments()); + lockup.createWithTimestampsLL(defaults.createWithTimestamps(), defaults.CLIFF_TIME()); + lockup.createWithTimestampsLT(defaults.createWithTimestamps(), defaults.tranches()); } } } diff --git a/benchmark/EstimateMaxCount.t.sol b/benchmark/EstimateMaxCount.t.sol index ac8d110ec..a5f90d7a1 100644 --- a/benchmark/EstimateMaxCount.t.sol +++ b/benchmark/EstimateMaxCount.t.sol @@ -4,8 +4,8 @@ pragma solidity >=0.8.22 <0.9.0; import { console2 } from "forge-std/src/console2.sol"; import { Test } from "forge-std/src/Test.sol"; -import { LockupDynamic_Gas_Test } from "./LockupDynamic.Gas.t.sol"; -import { LockupTranched_Gas_Test } from "./LockupTranched.Gas.t.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 { @@ -39,7 +39,7 @@ contract EstimateMaxCount is Test { /// @notice Estimate the maximum number of segments allowed in LockupDynamic. function test_EstimateSegments() public { - LockupDynamic_Gas_Test lockupDynamicGasTest = new LockupDynamic_Gas_Test(); + Lockup_Dynamic_Gas_Test lockupDynamicGasTest = new Lockup_Dynamic_Gas_Test(); lockupDynamicGasTest.setUp(); for (uint256 i = 0; i < chains.length; ++i) { @@ -56,7 +56,7 @@ contract EstimateMaxCount is Test { lastGasConsumed = gasConsumed; // Estimate the gas consumed by adding 10 segments. - gasConsumed = lockupDynamicGasTest.computeGas_CreateWithDurations(count + 10); + gasConsumed = lockupDynamicGasTest.computeGas_CreateWithDurationsLD(count + 10); } console2.log("count: %d and gasUsed: %d and chainId: %d", count, lastGasConsumed, chains[i].chainId); @@ -65,7 +65,7 @@ contract EstimateMaxCount is Test { /// @notice Estimate the maximum number of tranches allowed in LockupTranched. function test_EstimateTranches() public { - LockupTranched_Gas_Test lockupTranchedGasTest = new LockupTranched_Gas_Test(); + Lockup_Tranched_Gas_Test lockupTranchedGasTest = new Lockup_Tranched_Gas_Test(); lockupTranchedGasTest.setUp(); for (uint256 i = 0; i < chains.length; ++i) { @@ -82,7 +82,7 @@ contract EstimateMaxCount is Test { lastGasConsumed = gasConsumed; // Estimate the gas consumed by adding 10 tranches. - gasConsumed = lockupTranchedGasTest.computeGas_CreateWithDurations(count + 10); + 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 021fbe9d1..b528d9cbc 100644 --- a/benchmark/LockupDynamic.Gas.t.sol +++ b/benchmark/LockupDynamic.Gas.t.sol @@ -4,13 +4,13 @@ pragma solidity >=0.8.22; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { LockupDynamic } from "../src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; -/// @notice Tests used to benchmark LockupDynamic. +/// @notice Tests used to benchmark Lockup streams created using Dynamic model. /// @dev This contract creates a Markdown file with the gas usage of each function. -contract LockupDynamic_Gas_Test is Benchmark_Test { +contract Lockup_Dynamic_Gas_Test is Benchmark_Test { /*////////////////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ @@ -19,12 +19,11 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { uint256[] internal _streamIdsForWithdraw = new uint256[](4); /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION + SETUP //////////////////////////////////////////////////////////////////////////*/ + function setUp() public override { Benchmark_Test.setUp(); - - lockup = lockupDynamic; } /*////////////////////////////////////////////////////////////////////////// @@ -33,12 +32,14 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupDynamic.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockup_Dynamic.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: benchmarkResultsFile, - data: string.concat("# Benchmarks for LockupDynamic\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") + data: string.concat( + "# Benchmarks for Lockup Dynamic\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + ) }); vm.warp({ newTimestamp: defaults.END_TIME() }); @@ -52,8 +53,8 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { // Create streams with different number of segments. for (uint256 i; i < _segments.length; ++i) { - gasCreateWithDurations({ totalSegments: _segments[i] }); - gasCreateWithTimestamps({ totalSegments: _segments[i] }); + gasCreateWithDurationsLD({ totalSegments: _segments[i] }); + gasCreateWithTimestampsLD({ totalSegments: _segments[i] }); gasWithdraw_ByRecipient( _streamIdsForWithdraw[0], @@ -72,85 +73,89 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { GAS BENCHMARKS FOR CREATE FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - // The following function is used in the estimations of `MAX_SEGMENT_COUNT`. - function computeGas_CreateWithDurations(uint128 totalSegments) public returns (uint256 gasUsed) { - LockupDynamic.CreateWithDurations memory params = - _createWithDurationParams(totalSegments, defaults.BROKER_FEE()); + // The following function is used in the estimations of `MAX_COUNT`. + function computeGas_CreateWithDurationsLD(uint128 totalSegments) public returns (uint256 gasUsed) { + (Lockup.CreateWithDurations memory params, LockupDynamic.SegmentWithDuration[] memory segments) = + _createWithDurationParamsLD(totalSegments, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupDynamic.createWithDurations(params); + lockup.createWithDurationsLD(params, segments); gasUsed = beforeGas - gasleft(); } - function gasCreateWithDurations(uint128 totalSegments) internal { + function gasCreateWithDurationsLD(uint128 totalSegments) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); - LockupDynamic.CreateWithDurations memory params = - _createWithDurationParams(totalSegments, defaults.BROKER_FEE()); + (Lockup.CreateWithDurations memory params, LockupDynamic.SegmentWithDuration[] memory segments) = + _createWithDurationParamsLD(totalSegments, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupDynamic.createWithDurations(params); + lockup.createWithDurationsLD(params, segments); string memory gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithDurations` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" + "| `createWithDurationsLD` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" ); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); // Calculate gas usage without broker fee. - params = _createWithDurationParams(totalSegments, ud(0)); + (params, segments) = _createWithDurationParamsLD(totalSegments, ud(0)); beforeGas = gasleft(); - lockupDynamic.createWithDurations(params); + lockup.createWithDurationsLD(params, segments); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithDurations` (", vm.toString(totalSegments), " segments) (Broker fee not set) | ", gasUsed, " |" + "| `createWithDurationsLD` (", + vm.toString(totalSegments), + " segments) (Broker fee not set) | ", + gasUsed, + " |" ); _appendToFile(benchmarkResultsFile, contentToAppend); // Store the last 2 streams IDs for withdraw gas benchmark. - _streamIdsForWithdraw[0] = lockupDynamic.nextStreamId() - 2; - _streamIdsForWithdraw[1] = lockupDynamic.nextStreamId() - 1; + _streamIdsForWithdraw[0] = lockup.nextStreamId() - 2; + _streamIdsForWithdraw[1] = lockup.nextStreamId() - 1; // Create 2 more streams for withdraw gas benchmark. - _streamIdsForWithdraw[2] = lockupDynamic.createWithDurations(params); - _streamIdsForWithdraw[3] = lockupDynamic.createWithDurations(params); + _streamIdsForWithdraw[2] = lockup.createWithDurationsLD(params, segments); + _streamIdsForWithdraw[3] = lockup.createWithDurationsLD(params, segments); } - function gasCreateWithTimestamps(uint128 totalSegments) internal { + function gasCreateWithTimestampsLD(uint128 totalSegments) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time resetPrank({ msgSender: users.sender }); - LockupDynamic.CreateWithTimestamps memory params = - _createWithTimestampParams(totalSegments, defaults.BROKER_FEE()); + (Lockup.CreateWithTimestamps memory params, LockupDynamic.Segment[] memory segments) = + _createWithTimestampParamsLD(totalSegments, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupDynamic.createWithTimestamps(params); + lockup.createWithTimestampsLD(params, segments); string memory gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithTimestamps` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" + "| `createWithTimestampsLD` (", vm.toString(totalSegments), " segments) (Broker fee set) | ", gasUsed, " |" ); // Append the data to the file _appendToFile(benchmarkResultsFile, contentToAppend); // Calculate gas usage without broker fee. - params = _createWithTimestampParams(totalSegments, ud(0)); + (params, segments) = _createWithTimestampParamsLD(totalSegments, ud(0)); beforeGas = gasleft(); - lockupDynamic.createWithTimestamps(params); + lockup.createWithTimestampsLD(params, segments); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithTimestamps` (", + "| `createWithTimestampsLD` (", vm.toString(totalSegments), " segments) (Broker fee not set) | ", gasUsed, @@ -165,15 +170,15 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { HELPERS //////////////////////////////////////////////////////////////////////////*/ - function _createWithDurationParams( + function _createWithDurationParamsLD( uint128 totalSegments, UD60x18 brokerFee ) private view - returns (LockupDynamic.CreateWithDurations memory params) + returns (Lockup.CreateWithDurations memory params, LockupDynamic.SegmentWithDuration[] memory segments_) { - LockupDynamic.SegmentWithDuration[] memory segments_ = new LockupDynamic.SegmentWithDuration[](totalSegments); + segments_ = new LockupDynamic.SegmentWithDuration[](totalSegments); // Populate segments. for (uint256 i = 0; i < totalSegments; ++i) { @@ -188,22 +193,21 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; - params = defaults.createWithDurationsLD(); + params = defaults.createWithDurations(); params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); - params.segments = segments_; params.broker.fee = brokerFee; - return params; + return (params, segments_); } - function _createWithTimestampParams( + function _createWithTimestampParamsLD( uint128 totalSegments, UD60x18 brokerFee ) private view - returns (LockupDynamic.CreateWithTimestamps memory params) + returns (Lockup.CreateWithTimestamps memory params, LockupDynamic.Segment[] memory segments_) { - LockupDynamic.Segment[] memory segments_ = new LockupDynamic.Segment[](totalSegments); + segments_ = new LockupDynamic.Segment[](totalSegments); // Populate segments. for (uint256 i = 0; i < totalSegments; ++i) { @@ -218,11 +222,11 @@ contract LockupDynamic_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalSegments; - params = defaults.createWithTimestampsLD(); + params = defaults.createWithTimestamps(); params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); - params.segments = segments_; params.startTime = getBlockTimestamp(); + params.endTime = segments_[totalSegments - 1].timestamp; params.broker.fee = brokerFee; - return params; + return (params, segments_); } } diff --git a/benchmark/LockupLinear.Gas.t.sol b/benchmark/LockupLinear.Gas.t.sol index 457821882..b4f9af45a 100644 --- a/benchmark/LockupLinear.Gas.t.sol +++ b/benchmark/LockupLinear.Gas.t.sol @@ -3,35 +3,25 @@ pragma solidity >=0.8.22; import { ud } from "@prb/math/src/UD60x18.sol"; -import { LockupLinear } from "../src/core/types/DataTypes.sol"; +import { Lockup, LockupLinear } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; -/// @notice Tests used to benchmark LockupLinear. +/// @notice Tests used to benchmark Lockup streams created using Linear model. /// @dev This contract creates a Markdown file with the gas usage of each function. -contract LockupLinear_Gas_Test is Benchmark_Test { - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public override { - Benchmark_Test.setUp(); - - lockup = lockupLinear; - } - +contract Lockup_Linear_Gas_Test is Benchmark_Test { /*////////////////////////////////////////////////////////////////////////// TEST FUNCTION //////////////////////////////////////////////////////////////////////////*/ function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupLinear.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockup_Linear.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: benchmarkResultsFile, - data: string.concat("# Benchmarks for LockupLinear\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") + data: string.concat("# Benchmarks for Lockup Linear\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n") }); vm.warp({ newTimestamp: defaults.END_TIME() }); @@ -42,11 +32,11 @@ contract LockupLinear_Gas_Test is Benchmark_Test { gasRenounce(); - gasCreateWithDurations({ cliffDuration: 0 }); - gasCreateWithDurations({ cliffDuration: defaults.CLIFF_DURATION() }); + gasCreateWithDurationsLL({ cliffDuration: 0 }); + gasCreateWithDurationsLL({ cliffDuration: defaults.CLIFF_DURATION() }); - gasCreateWithTimestamps({ cliffTime: 0 }); - gasCreateWithTimestamps({ cliffTime: defaults.CLIFF_TIME() }); + gasCreateWithTimestampsLL({ cliffTime: 0 }); + gasCreateWithTimestampsLL({ cliffTime: defaults.CLIFF_TIME() }); gasWithdraw_ByRecipient(streamIds[3], streamIds[4], ""); gasWithdraw_ByAnyone(streamIds[5], streamIds[6], ""); @@ -56,20 +46,22 @@ contract LockupLinear_Gas_Test is Benchmark_Test { GAS BENCHMARKS FOR CREATE FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - function gasCreateWithDurations(uint40 cliffDuration) internal { + function gasCreateWithDurationsLL(uint40 cliffDuration) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); - LockupLinear.CreateWithDurations memory params = defaults.createWithDurationsLL(); - params.durations.cliff = cliffDuration; + Lockup.CreateWithDurations memory params = defaults.createWithDurations(); + LockupLinear.Durations memory durations = defaults.durations(); + durations.cliff = cliffDuration; uint256 beforeGas = gasleft(); - lockupLinear.createWithDurations(params); + lockup.createWithDurationsLL(params, durations); string memory gasUsed = vm.toString(beforeGas - gasleft()); string memory cliffSetOrNot = cliffDuration == 0 ? " (cliff not set)" : " (cliff set)"; - contentToAppend = string.concat("| `createWithDurations` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); + contentToAppend = + string.concat("| `createWithDurationsLL` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); @@ -79,31 +71,30 @@ contract LockupLinear_Gas_Test is Benchmark_Test { params.totalAmount = _calculateTotalAmount(defaults.DEPOSIT_AMOUNT(), ud(0)); beforeGas = gasleft(); - lockupLinear.createWithDurations(params); + lockup.createWithDurationsLL(params, durations); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = - string.concat("| `createWithDurations` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); + string.concat("| `createWithDurationsLL` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); } - function gasCreateWithTimestamps(uint40 cliffTime) internal { + function gasCreateWithTimestampsLL(uint40 cliffTime) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsLL(); - params.timestamps.cliff = cliffTime; + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); uint256 beforeGas = gasleft(); - lockupLinear.createWithTimestamps(params); + lockup.createWithTimestampsLL(params, cliffTime); string memory gasUsed = vm.toString(beforeGas - gasleft()); string memory cliffSetOrNot = cliffTime == 0 ? " (cliff not set)" : " (cliff set)"; contentToAppend = - string.concat("| `createWithTimestamps` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); + string.concat("| `createWithTimestampsLL` (Broker fee set)", cliffSetOrNot, " | ", gasUsed, " |"); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); @@ -113,11 +104,11 @@ contract LockupLinear_Gas_Test is Benchmark_Test { params.totalAmount = _calculateTotalAmount(defaults.DEPOSIT_AMOUNT(), ud(0)); beforeGas = gasleft(); - lockupLinear.createWithTimestamps(params); + lockup.createWithTimestampsLL(params, cliffTime); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = - string.concat("| `createWithTimestamps` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); + string.concat("| `createWithTimestampsLL` (Broker fee not set)", cliffSetOrNot, " | ", gasUsed, " |"); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); diff --git a/benchmark/LockupTranched.Gas.t.sol b/benchmark/LockupTranched.Gas.t.sol index 665bf9def..cbedc39a4 100644 --- a/benchmark/LockupTranched.Gas.t.sol +++ b/benchmark/LockupTranched.Gas.t.sol @@ -3,13 +3,13 @@ pragma solidity >=0.8.22; import { UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { LockupTranched } from "../src/core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "../src/core/types/DataTypes.sol"; import { Benchmark_Test } from "./Benchmark.t.sol"; -/// @notice Tests used to benchmark LockupTranched. +/// @notice Tests used to benchmark Lockup streams created using Tranched model. /// @dev This contract creates a Markdown file with the gas usage of each function. -contract LockupTranched_Gas_Test is Benchmark_Test { +contract Lockup_Tranched_Gas_Test is Benchmark_Test { /*////////////////////////////////////////////////////////////////////////// STATE VARIABLES //////////////////////////////////////////////////////////////////////////*/ @@ -17,29 +17,19 @@ contract LockupTranched_Gas_Test is Benchmark_Test { uint128[] internal _tranches = [2, 10, 100]; uint256[] internal _streamIdsForWithdraw = new uint256[](4); - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public override { - Benchmark_Test.setUp(); - - lockup = lockupTranched; - } - /*////////////////////////////////////////////////////////////////////////// TEST FUNCTION //////////////////////////////////////////////////////////////////////////*/ function testGas_Implementations() external { // Set the file path. - benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockupTranched.md"); + benchmarkResultsFile = string.concat(benchmarkResults, "SablierLockup_Tranched.md"); // Create the file if it doesn't exist, otherwise overwrite it. vm.writeFile({ path: benchmarkResultsFile, data: string.concat( - "# Benchmarks for LockupTranched\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" + "# Benchmarks for Lockup Tranched\n\n", "| Implementation | Gas Usage |\n", "| --- | --- |\n" ) }); @@ -54,8 +44,8 @@ contract LockupTranched_Gas_Test is Benchmark_Test { // Create streams with different number of tranches. for (uint256 i; i < _tranches.length; ++i) { - gasCreateWithDurations({ totalTranches: _tranches[i] }); - gasCreateWithTimestamps({ totalTranches: _tranches[i] }); + gasCreateWithDurationsLT({ totalTranches: _tranches[i] }); + gasCreateWithTimestampsLT({ totalTranches: _tranches[i] }); gasWithdraw_ByRecipient( _streamIdsForWithdraw[0], @@ -74,79 +64,86 @@ contract LockupTranched_Gas_Test is Benchmark_Test { GAS BENCHMARKS FOR CREATE FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ - // The following function is used in the estimation of `MAX_TRANCHE_COUNT` - function computeGas_CreateWithDurations(uint128 totalTranches) public returns (uint256 gasUsed) { - LockupTranched.CreateWithDurations memory params = - _createWithDurationParams(totalTranches, defaults.BROKER_FEE()); + // The following function is used in the estimation of `MAX_COUNT` + function computeGas_CreateWithDurationsLT(uint128 totalTranches) public returns (uint256 gasUsed) { + (Lockup.CreateWithDurations memory params, LockupTranched.TrancheWithDuration[] memory tranches) = + _createWithDurationParamsLT(totalTranches, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupTranched.createWithDurations(params); + lockup.createWithDurationsLT(params, tranches); gasUsed = beforeGas - gasleft(); } - function gasCreateWithDurations(uint128 totalTranches) internal { + function gasCreateWithDurationsLT(uint128 totalTranches) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); - LockupTranched.CreateWithDurations memory params = - _createWithDurationParams(totalTranches, defaults.BROKER_FEE()); + (Lockup.CreateWithDurations memory params, LockupTranched.TrancheWithDuration[] memory tranches) = + _createWithDurationParamsLT(totalTranches, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupTranched.createWithDurations(params); + lockup.createWithDurationsLT(params, tranches); string memory gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithDurations` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" + "| `createWithDurationsLT` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" ); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); // Calculate gas usage without broker fee. - params = _createWithDurationParams(totalTranches, ud(0)); + (params, tranches) = _createWithDurationParamsLT(totalTranches, ud(0)); beforeGas = gasleft(); - lockupTranched.createWithDurations(params); + lockup.createWithDurationsLT(params, tranches); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithDurations` (", vm.toString(totalTranches), " tranches) (Broker fee not set) | ", gasUsed, " |" + "| `createWithDurationsLT` (", + vm.toString(totalTranches), + " tranches) (Broker fee not set) | ", + gasUsed, + " |" ); _appendToFile(benchmarkResultsFile, contentToAppend); // Store the last 2 streams IDs for withdraw gas benchmark. - _streamIdsForWithdraw[0] = lockupTranched.nextStreamId() - 2; - _streamIdsForWithdraw[1] = lockupTranched.nextStreamId() - 1; + _streamIdsForWithdraw[0] = lockup.nextStreamId() - 2; + _streamIdsForWithdraw[1] = lockup.nextStreamId() - 1; // Create 2 more streams for withdraw gas benchmark. - _streamIdsForWithdraw[2] = lockupTranched.createWithDurations(params); - _streamIdsForWithdraw[3] = lockupTranched.createWithDurations(params); + _streamIdsForWithdraw[2] = lockup.createWithDurationsLT(params, tranches); + _streamIdsForWithdraw[3] = lockup.createWithDurationsLT(params, tranches); } - function gasCreateWithTimestamps(uint128 totalTranches) internal { + function gasCreateWithTimestampsLT(uint128 totalTranches) internal { // Set the caller to the Sender for the next calls and change timestamp to before end time. resetPrank({ msgSender: users.sender }); + (Lockup.CreateWithTimestamps memory params, LockupTranched.Tranche[] memory tranches) = + _createWithTimestampParamsLT(totalTranches, defaults.BROKER_FEE()); uint256 beforeGas = gasleft(); - lockupTranched.createWithTimestamps({ params: _createWithTimestampParams(totalTranches, defaults.BROKER_FEE()) }); + lockup.createWithTimestampsLT(params, tranches); string memory gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithTimestamps` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" + "| `createWithTimestampsLT` (", vm.toString(totalTranches), " tranches) (Broker fee set) | ", gasUsed, " |" ); // Append the content to the file. _appendToFile(benchmarkResultsFile, contentToAppend); + (params, tranches) = _createWithTimestampParamsLT(totalTranches, ud(0)); beforeGas = gasleft(); - lockupTranched.createWithTimestamps({ params: _createWithTimestampParams(totalTranches, ud(0)) }); + lockup.createWithTimestampsLT(params, tranches); gasUsed = vm.toString(beforeGas - gasleft()); contentToAppend = string.concat( - "| `createWithTimestamps` (", + "| `createWithTimestampsLT` (", vm.toString(totalTranches), " tranches) (Broker fee not set) | ", gasUsed, @@ -161,15 +158,15 @@ contract LockupTranched_Gas_Test is Benchmark_Test { HELPERS //////////////////////////////////////////////////////////////////////////*/ - function _createWithDurationParams( + function _createWithDurationParamsLT( uint128 totalTranches, UD60x18 brokerFee ) private view - returns (LockupTranched.CreateWithDurations memory params) + returns (Lockup.CreateWithDurations memory params, LockupTranched.TrancheWithDuration[] memory tranches_) { - LockupTranched.TrancheWithDuration[] memory tranches_ = new LockupTranched.TrancheWithDuration[](totalTranches); + tranches_ = new LockupTranched.TrancheWithDuration[](totalTranches); // Populate tranches for (uint256 i = 0; i < totalTranches; ++i) { @@ -180,22 +177,21 @@ contract LockupTranched_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; - params = defaults.createWithDurationsLT(); + params = defaults.createWithDurations(); params.broker.fee = brokerFee; params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); - params.tranches = tranches_; - return params; + return (params, tranches_); } - function _createWithTimestampParams( + function _createWithTimestampParamsLT( uint128 totalTranches, UD60x18 brokerFee ) private view - returns (LockupTranched.CreateWithTimestamps memory params) + returns (Lockup.CreateWithTimestamps memory params, LockupTranched.Tranche[] memory tranches_) { - LockupTranched.Tranche[] memory tranches_ = new LockupTranched.Tranche[](totalTranches); + tranches_ = new LockupTranched.Tranche[](totalTranches); // Populate tranches. for (uint256 i = 0; i < totalTranches; ++i) { @@ -209,11 +205,11 @@ contract LockupTranched_Gas_Test is Benchmark_Test { uint128 depositAmount = AMOUNT_PER_SEGMENT * totalTranches; - params = defaults.createWithTimestampsLT(); + params = defaults.createWithTimestamps(); params.broker.fee = brokerFee; params.startTime = getBlockTimestamp(); + params.endTime = tranches_[totalTranches - 1].timestamp; params.totalAmount = _calculateTotalAmount(depositAmount, brokerFee); - params.tranches = tranches_; - return params; + return (params, tranches_); } } diff --git a/benchmark/results/SablierBatchLockup.md b/benchmark/results/SablierBatchLockup.md index 112175f33..8bb8db383 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 | 770796 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 5 | 730532 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 5 | 3935335 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 5 | 3797841 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 5 | 3844973 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 5 | 3726799 | -| `createWithDurationsLL` | Lockup Linear | N/A | 10 | 1413200 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 10 | 1410133 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 10 | 7785667 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 10 | 7547946 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 10 | 7596904 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 10 | 7406060 | -| `createWithDurationsLL` | Lockup Linear | N/A | 20 | 2775981 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 20 | 2771033 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 20 | 15547587 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 20 | 15056228 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 20 | 15143062 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 20 | 14770870 | -| `createWithDurationsLL` | Lockup Linear | N/A | 30 | 4133268 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 30 | 4136198 | -| `createWithDurationsLD` | Lockup Dynamic | 24 | 30 | 23351853 | -| `createWithTimestampsLD` | Lockup Dynamic | 24 | 30 | 22583299 | -| `createWithDurationsLT` | Lockup Tranched | 24 | 30 | 22691758 | -| `createWithTimestampsLT` | Lockup Tranched | 24 | 30 | 22152793 | -| `createWithDurationsLL` | Lockup Linear | N/A | 50 | 6854756 | -| `createWithTimestampsLL` | Lockup Linear | N/A | 50 | 6872537 | -| `createWithDurationsLD` | Lockup Dynamic | 12 | 50 | 22883512 | -| `createWithTimestampsLD` | Lockup Dynamic | 12 | 50 | 22241640 | -| `createWithDurationsLT` | Lockup Tranched | 12 | 50 | 22314003 | -| `createWithTimestampsLT` | Lockup Tranched | 12 | 50 | 21891398 | +| `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 | diff --git a/benchmark/results/SablierLockupDynamic.md b/benchmark/results/SablierLockupDynamic.md deleted file mode 100644 index 7ca0a2fcd..000000000 --- a/benchmark/results/SablierLockupDynamic.md +++ /dev/null @@ -1,31 +0,0 @@ -# Benchmarks for LockupDynamic - -| Implementation | Gas Usage | -| ---------------------------------------------------------- | --------- | -| `burn` | 15716 | -| `cancel` | 74341 | -| `renounce` | 39001 | -| `createWithDurations` (2 segments) (Broker fee set) | 200605 | -| `createWithDurations` (2 segments) (Broker fee not set) | 185039 | -| `createWithTimestamps` (2 segments) (Broker fee set) | 184785 | -| `createWithTimestamps` (2 segments) (Broker fee not set) | 180023 | -| `withdraw` (2 segments) (After End Time) (by Recipient) | 19109 | -| `withdraw` (2 segments) (Before End Time) (by Recipient) | 27554 | -| `withdraw` (2 segments) (After End Time) (by Anyone) | 14241 | -| `withdraw` (2 segments) (Before End Time) (by Anyone) | 27485 | -| `createWithDurations` (10 segments) (Broker fee set) | 395105 | -| `createWithDurations` (10 segments) (Broker fee not set) | 390350 | -| `createWithTimestamps` (10 segments) (Broker fee set) | 385155 | -| `createWithTimestamps` (10 segments) (Broker fee not set) | 380410 | -| `withdraw` (10 segments) (After End Time) (by Recipient) | 14295 | -| `withdraw` (10 segments) (Before End Time) (by Recipient) | 32545 | -| `withdraw` (10 segments) (After End Time) (by Anyone) | 14249 | -| `withdraw` (10 segments) (Before End Time) (by Anyone) | 32476 | -| `createWithDurations` (100 segments) (Broker fee set) | 2741072 | -| `createWithDurations` (100 segments) (Broker fee not set) | 2737309 | -| `createWithTimestamps` (100 segments) (Broker fee set) | 2643302 | -| `createWithTimestamps` (100 segments) (Broker fee not set) | 2639574 | -| `withdraw` (100 segments) (After End Time) (by Recipient) | 14295 | -| `withdraw` (100 segments) (Before End Time) (by Recipient) | 88968 | -| `withdraw` (100 segments) (After End Time) (by Anyone) | 14226 | -| `withdraw` (100 segments) (Before End Time) (by Anyone) | 88899 | diff --git a/benchmark/results/SablierLockupLinear.md b/benchmark/results/SablierLockupLinear.md deleted file mode 100644 index 32085722d..000000000 --- a/benchmark/results/SablierLockupLinear.md +++ /dev/null @@ -1,19 +0,0 @@ -# Benchmarks for LockupLinear - -| Implementation | Gas Usage | -| ----------------------------------------------------------- | --------- | -| `burn` | 15694 | -| `cancel` | 56832 | -| `renounce` | 19378 | -| `createWithDurations` (Broker fee set) (cliff not set) | 129276 | -| `createWithDurations` (Broker fee not set) (cliff not set) | 113680 | -| `createWithDurations` (Broker fee set) (cliff set) | 138071 | -| `createWithDurations` (Broker fee not set) (cliff set) | 133274 | -| `createWithTimestamps` (Broker fee set) (cliff not set) | 115334 | -| `createWithTimestamps` (Broker fee not set) (cliff not set) | 110530 | -| `createWithTimestamps` (Broker fee set) (cliff set) | 137629 | -| `createWithTimestamps` (Broker fee not set) (cliff set) | 132827 | -| `withdraw` (After End Time) (by Recipient) | 29704 | -| `withdraw` (Before End Time) (by Recipient) | 19107 | -| `withdraw` (After End Time) (by Anyone) | 24802 | -| `withdraw` (Before End Time) (by Anyone) | 19005 | diff --git a/benchmark/results/SablierLockupTranched.md b/benchmark/results/SablierLockupTranched.md deleted file mode 100644 index edb9330a8..000000000 --- a/benchmark/results/SablierLockupTranched.md +++ /dev/null @@ -1,31 +0,0 @@ -# Benchmarks for LockupTranched - -| Implementation | Gas Usage | -| ---------------------------------------------------------- | --------- | -| `burn` | 15738 | -| `cancel` | 63994 | -| `renounce` | 26495 | -| `createWithDurations` (2 tranches) (Broker fee set) | 199538 | -| `createWithDurations` (2 tranches) (Broker fee not set) | 183973 | -| `createWithTimestamps` (2 tranches) (Broker fee set) | 195734 | -| `createWithTimestamps` (2 tranches) (Broker fee not set) | 190260 | -| `withdraw` (2 tranches) (After End Time) (by Recipient) | 20102 | -| `withdraw` (2 tranches) (Before End Time) (by Recipient) | 14797 | -| `withdraw` (2 tranches) (After End Time) (by Anyone) | 15201 | -| `withdraw` (2 tranches) (Before End Time) (by Anyone) | 14695 | -| `createWithDurations` (10 tranches) (Broker fee set) | 388774 | -| `createWithDurations` (10 tranches) (Broker fee not set) | 384017 | -| `createWithTimestamps` (10 tranches) (Broker fee set) | 403722 | -| `createWithTimestamps` (10 tranches) (Broker fee not set) | 398385 | -| `withdraw` (10 tranches) (After End Time) (by Recipient) | 17857 | -| `withdraw` (10 tranches) (Before End Time) (by Recipient) | 19616 | -| `withdraw` (10 tranches) (After End Time) (by Anyone) | 17763 | -| `withdraw` (10 tranches) (Before End Time) (by Anyone) | 19514 | -| `createWithDurations` (100 tranches) (Broker fee set) | 2673124 | -| `createWithDurations` (100 tranches) (Broker fee not set) | 2668870 | -| `createWithTimestamps` (100 tranches) (Broker fee set) | 2747871 | -| `createWithTimestamps` (100 tranches) (Broker fee not set) | 2744348 | -| `withdraw` (100 tranches) (After End Time) (by Recipient) | 46746 | -| `withdraw` (100 tranches) (Before End Time) (by Recipient) | 73989 | -| `withdraw` (100 tranches) (After End Time) (by Anyone) | 46644 | -| `withdraw` (100 tranches) (Before End Time) (by Anyone) | 73887 | diff --git a/benchmark/results/SablierLockup_Dynamic.md b/benchmark/results/SablierLockup_Dynamic.md new file mode 100644 index 000000000..43b56f6a9 --- /dev/null +++ b/benchmark/results/SablierLockup_Dynamic.md @@ -0,0 +1,31 @@ +# Benchmarks for Lockup Dynamic + +| 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 | diff --git a/benchmark/results/SablierLockup_Linear.md b/benchmark/results/SablierLockup_Linear.md new file mode 100644 index 000000000..8b9e9819f --- /dev/null +++ b/benchmark/results/SablierLockup_Linear.md @@ -0,0 +1,19 @@ +# Benchmarks for Lockup Linear + +| 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 | diff --git a/benchmark/results/SablierLockup_Tranched.md b/benchmark/results/SablierLockup_Tranched.md new file mode 100644 index 000000000..f1839a92f --- /dev/null +++ b/benchmark/results/SablierLockup_Tranched.md @@ -0,0 +1,31 @@ +# Benchmarks for Lockup Tranched + +| 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 | diff --git a/foundry.toml b/foundry.toml index 562d35df1..70f9532a8 100644 --- a/foundry.toml +++ b/foundry.toml @@ -38,10 +38,17 @@ # Compile only the production code and the test mocks with via IR [profile.optimized] + # https://book.getfoundry.sh/reference/config/solidity-compiler#libraries + # TODO: Update addresses once deployed. + libraries = [ + "src/core/libraries/Helpers.sol:Helpers:0x7715bE116061E014Bb721b46Dc78Dd57C91FDF9b", + "src/core/libraries/VestingMath.sol:VestingMath:0x26F9d826BDed47Fc472526aE8095B75ac336963C" + ] out = "out-optimized" test = "test/mocks" via_ir = true + # See "SMTChecker and Formal Verification" in the Solidity docs [profile.smt] ignored_error_codes = [ diff --git a/package.json b/package.json index 937411579..b0d9bd3a6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@sablier/lockup", "description": "Core smart contracts of the Lockup token distribution protocol", "license": "BUSL-1.1", - "version": "1.2.0", + "version": "1.3.0", "author": { "name": "Sablier Labs Ltd", "url": "https://sablier.com" diff --git a/precompiles/Precompiles.sol b/precompiles/Precompiles.sol index 8a90f3539..36a27a3ca 100644 --- a/precompiles/Precompiles.sol +++ b/precompiles/Precompiles.sol @@ -21,11 +21,11 @@ contract Precompiles { bytes public constant BYTECODE_BATCH_LOCKUP = hex"60808060405234601557611888908161001a8239f35b5f80fdfe60806040526004361015610011575f80fd5b5f3560e01c806337266dd314610e1357806349a32c4014610b81578063606ef875146109205780639e743f2914610649578063a514f83e146103875763f7ca34eb1461005b575f80fd5b346102e157610069366110a0565b92839291921561035f579092905f90815b83811061032e57506001600160a01b036100979116918583611548565b6100a082611212565b926001600160a01b035f9516945b8381106100c757604051806100c3878261111c565b0390f35b6100df6100d582868561145c565b60c08101906113e2565b6100ed6100d584888761145c565b5f190191821015905061031a576060020160400161010a9061147f565b9061011681868561145c565b61011f90611244565b9161012b82878661145c565b60200161013790611244565b9061014383888761145c565b60400161014f90611177565b61015a84898861145c565b60600161016690611258565b610171858a8961145c565b60800161017d90611258565b90610189868b8a61145c565b60a0016101959061147f565b926101a1878c8b61145c565b60e00195604051986101b28a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b031660408801528b606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e08401523661020f91611265565b61010083015261022081868561145c565b60c0810161022d916113e2565b9290836040519485937f53ac8bc30000000000000000000000000000000000000000000000000000000085526101648501906004860161026c91611491565b61016061014486015252610184830191905f905b8082106102f857505050908060209203815f885af180156102ed575f906102b7575b600192506102b082886113bd565b52016100ae565b506020823d82116102e5575b816102d0602093836111d8565b810103126102e157600191516102a2565b5f80fd5b3d91506102c3565b6040513d5f823e3d90fd5b919350916060808261030c60019488611418565b019401920185939291610280565b634e487b7160e01b5f52603260045260245ffd5b916001906001600160801b03610353604061034d87898b9c9a9c61145c565b01611177565b1601920194929461007a565b7f36186274000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e15760603660031901126102e1576103a0611074565b6103a861108a565b6044359067ffffffffffffffff82116102e157366023830112156102e157816004013567ffffffffffffffff81116102e15760248301926024369161014084020101116102e157801561035f57905f935f5b83811061061e57506001600160a01b036104179116948286611548565b61042082611212565b926001600160a01b035f9216915b83811061044357604051806100c3878261111c565b61044e818584611537565b61045790611244565b90610463818685611537565b60200161046f90611244565b61047a828786611537565b60400161048690611177565b610491838887611537565b60600161049d90611258565b6104a8848988611537565b6080016104b490611258565b6104bf858a89611537565b60a0016104cb9061147f565b916104d7868b8a611537565b60e0016104e39061147f565b936104ef878c8b611537565b6101000195604051986105018a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b0316604088015288606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e08401523661055e91611265565b61010083015261056f818685611537565b60c00161057b9061147f565b604051927f9e7f5dbb000000000000000000000000000000000000000000000000000000008452600484016105af91611491565b64ffffffffff166101448301528180885a925f61016492602095f180156102ed575f906105ec575b600192506105e582886113bd565b520161042e565b506020823d8211610616575b81610605602093836111d8565b810103126102e157600191516105d7565b3d91506105f8565b946001906001600160801b0361063d604061034d8a898b9a999a611537565b160195019291926103fa565b346102e157610657366110a0565b92839291921561035f579092905f90815b8381106108f557506001600160a01b036106859116918583611548565b61068e82611212565b926001600160a01b035f9516945b8381106106b157604051806100c3878261111c565b6106c96106bf82868561145c565b60c08101906112af565b6106d76106bf84888761145c565b5f190191821015905061031a5760061b016020016106f49061147f565b9061070081868561145c565b61070990611244565b9161071582878661145c565b60200161072190611244565b9061072d83888761145c565b60400161073990611177565b61074484898861145c565b60600161075090611258565b61075b858a8961145c565b60800161076790611258565b90610773868b8a61145c565b60a00161077f9061147f565b9261078b878c8b61145c565b60e001956040519861079c8a6111bb565b6001600160a01b031689526001600160a01b031660208901526001600160801b031660408801528b606088015215156080870152151560a086015264ffffffffff1660c085015264ffffffffff1660e0840152366107f991611265565b61010083015261080a81868561145c565b60c08101610817916112af565b9290836040519485937f56b955e80000000000000000000000000000000000000000000000000000000085526101648501906004860161085691611491565b61016061014486015252610184830191905f905b8082106108d357505050908060209203815f885af180156102ed575f906108a1575b6001925061089a82886113bd565b520161069c565b506020823d82116108cb575b816108ba602093836111d8565b810103126102e1576001915161088c565b3d91506108ad565b91935091604080826108e760019488611390565b01940192018593929161086a565b916001906001600160801b03610914604061034d87898b9c9a9c61145c565b16019201949294610668565b346102e15761092e366110a0565b92839291921561035f579092905f90815b838110610b5657506001600160a01b0361095c9116918583611548565b61096582611212565b926001600160a01b035f9516945b83811061098857604051806100c3878261111c565b610993818584611155565b61099c90611244565b906109a8818685611155565b6020016109b490611244565b6109bf828786611155565b6040016109cb90611177565b6109d6838887611155565b6060016109e290611258565b6109ed848988611155565b6080016109f990611258565b91610a05858a89611155565b60c0019360405196610a168861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a084015236610a5b91611265565b60c0830152610a6b818685611155565b60a08101610a78916113e2565b9290836040519485937f42e94a7b00000000000000000000000000000000000000000000000000000000855261012485019060048601610ab7916112e5565b61012061010486015252610144830191905f905b808210610b3457505050908060209203815f885af180156102ed575f90610b02575b60019250610afb82886113bd565b5201610973565b506020823d8211610b2c575b81610b1b602093836111d8565b810103126102e15760019151610aed565b3d9150610b0e565b9193509160608082610b4860019488611418565b019401920185939291610acb565b916001906001600160801b03610b75604061034d87898b9c9a9c611155565b1601920194929461093f565b346102e15760603660031901126102e157610b9a611074565b610ba261108a565b6044359067ffffffffffffffff82116102e157366023830112156102e157816004013567ffffffffffffffff81116102e15760248301926024369161012084020101116102e157801561035f57905f935f5b838110610de857506001600160a01b03610c119116948286611548565b610c1a82611212565b926001600160a01b035f9216915b838110610c3d57604051806100c3878261111c565b610c488185846113d1565b610c5190611244565b90610c5d8186856113d1565b602001610c6990611244565b610c748287866113d1565b604001610c8090611177565b610c8b8388876113d1565b606001610c9790611258565b610ca28489886113d1565b608001610cae90611258565b91610cba858a896113d1565b60e0019360405196610ccb8861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015286606086015215156080850152151560a084015236610d1091611265565b60c0830152610d208186856113d1565b604051927f8222b69400000000000000000000000000000000000000000000000000000000845260048401610d54916112e5565b610d6060a0820161137e565b64ffffffffff1661010484015260c001610d799061137e565b64ffffffffff166101248301528180885a925f61014492602095f180156102ed575f90610db6575b60019250610daf82886113bd565b5201610c28565b506020823d8211610de0575b81610dcf602093836111d8565b810103126102e15760019151610da1565b3d9150610dc2565b946001906001600160801b03610e07604061034d8a898b9a999a6113d1565b16019501929192610bf4565b346102e157610e21366110a0565b92839291921561035f579092905f90815b83811061104957506001600160a01b03610e4f9116918583611548565b610e5882611212565b926001600160a01b035f9516945b838110610e7b57604051806100c3878261111c565b610e86818584611155565b610e8f90611244565b90610e9b818685611155565b602001610ea790611244565b610eb2828786611155565b604001610ebe90611177565b610ec9838887611155565b606001610ed590611258565b610ee0848988611155565b608001610eec90611258565b91610ef8858a89611155565b60c0019360405196610f098861118b565b6001600160a01b031687526001600160a01b031660208701526001600160801b0316604086015289606086015215156080850152151560a084015236610f4e91611265565b60c0830152610f5e818685611155565b60a08101610f6b916112af565b9290836040519485937f6611ceab00000000000000000000000000000000000000000000000000000000855261012485019060048601610faa916112e5565b61012061010486015252610144830191905f905b80821061102757505050908060209203815f885af180156102ed575f90610ff5575b60019250610fee82886113bd565b5201610e66565b506020823d821161101f575b8161100e602093836111d8565b810103126102e15760019151610fe0565b3d9150611001565b919350916040808261103b60019488611390565b019401920185939291610fbe565b916001906001600160801b03611068604061034d87898b9c9a9c611155565b16019201949294610e32565b600435906001600160a01b03821682036102e157565b602435906001600160a01b03821682036102e157565b9060606003198301126102e1576004356001600160a01b03811681036102e157916024356001600160a01b03811681036102e1579160443567ffffffffffffffff81116102e15760040182601f820112156102e15780359267ffffffffffffffff84116102e1576020808301928560051b0101116102e1579190565b60206040818301928281528451809452019201905f5b81811061113f5750505090565b8251845260209384019390920191600101611132565b919081101561031a5760051b8101359060fe19813603018212156102e1570190565b356001600160801b03811681036102e15790565b60e0810190811067ffffffffffffffff8211176111a757604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff8211176111a757604052565b90601f8019910116810190811067ffffffffffffffff8211176111a757604052565b67ffffffffffffffff81116111a75760051b60200190565b9061121c826111fa565b61122960405191826111d8565b828152809261123a601f19916111fa565b0190602036910137565b356001600160a01b03811681036102e15790565b3580151581036102e15790565b91908260409103126102e1576040516040810181811067ffffffffffffffff8211176111a757604052809280356001600160a01b03811681036102e1578252602090810135910152565b903590601e19813603018212156102e1570180359067ffffffffffffffff82116102e157602001918160061b360383136102e157565b9060c080611368936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a08501520151910190602080916001600160a01b0381511684520151910152565b565b35906001600160801b03821682036102e157565b359064ffffffffff821682036102e157565b64ffffffffff6113b7602080936001600160801b036113ae8261136a565b1686520161137e565b16910152565b805182101561031a5760209160051b010190565b919081101561031a57610120020190565b903590601e19813603018212156102e1570180359067ffffffffffffffff82116102e1576020019160608202360383136102e157565b6001600160801b036114298261136a565b168252602081013567ffffffffffffffff81168091036102e1576113b76040809364ffffffffff9360208701520161137e565b919081101561031a5760051b8101359061011e19813603018212156102e1570190565b3564ffffffffff811681036102e15790565b9061010080611368936001600160a01b0381511684526001600160a01b0360208201511660208501526001600160801b0360408201511660408501526001600160a01b03606082015116606085015260808101511515608085015260a0810151151560a085015264ffffffffff60c08201511660c085015264ffffffffff60e08201511660e08501520151910190602080916001600160a01b0381511684520151910152565b919081101561031a57610140020190565b919061159d6040517f23b872dd000000000000000000000000000000000000000000000000000000006020820152336024820152306044820152836064820152606481526115976084826111d8565b8261172b565b6001600160a01b0381166001600160a01b03604051947fdd62ed3e0000000000000000000000000000000000000000000000000000000086523060048701521693846024820152602081604481855afa80156102ed5784915f916116de575b5010611609575b50505050565b5f8060405194602086019063095ea7b360e01b82528760248801526044870152604486526116386064876111d8565b85519082855af1906116486117b0565b826116ac575b50816116a1575b5015611662575b80611603565b611694611699936040519063095ea7b360e01b602083015260248201525f6044820152604481526115976064826111d8565b61172b565b5f808061165c565b90503b15155f611655565b805191925081159182156116c4575b5050905f61164e565b6116d79250602080918301019101611713565b5f806116bb565b9150506020813d60201161170b575b816116fa602093836111d8565b810103126102e1578390515f6115fc565b3d91506116ed565b908160209103126102e1575180151581036102e15790565b5f806001600160a01b0361175493169360208151910182865af161174d6117b0565b90836117ef565b8051908115159182611795575b505061176a5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6117a89250602080918301019101611713565b155f80611761565b3d156117ea573d9067ffffffffffffffff82116111a757604051916117df601f8201601f1916602001846111d8565b82523d5f602084013e565b606090565b9061182c575080511561180457805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611872575b61183d575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561183556fea164736f6c634300081a000a"; bytes public constant BYTECODE_LOCKUP = - hex"60c0604052346103e157615a506060813803918261001c816103e5565b9384928339810103126103e15780516001600160a01b038116908190036103e15760208201516001600160a01b03811692908390036103e1576040015161006360406103e5565b92601a84527f5361626c696572204c6f636b75702044796e616d6963204e4654000000000000602085015261009860406103e5565b600e81526d29a0a116a627a1a5aaa816a22ca760911b602082015230608052845190946001600160401b0382116102e45760015490600182811c921680156103d7575b60208310146102c65781601f849311610369575b50602090601f8311600114610303575f926102f8575b50508160011b915f199060031b1c1916176001555b83516001600160401b0381116102e457600254600181811c911680156102da575b60208210146102c657601f8111610263575b50602094601f8211600114610200579481929394955f926101f5575b50508160011b915f199060031b1c1916176002555b5f80546001600160a01b031990811685178255600880549091169290921790915560405192907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a360a0526001600755615645908161040b823960805181613938015260a051818181610bcc0152613a020152f35b015190505f80610169565b601f1982169560025f52805f20915f5b88811061024b57508360019596979810610233575b505050811b0160025561017e565b01515f1960f88460031b161c191690555f8080610225565b91926020600181928685015181550194019201610210565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102bc575b601f0160051c01905b8181106102b1575061014d565b5f81556001016102a4565b909150819061029b565b634e487b7160e01b5f52602260045260245ffd5b90607f169061013b565b634e487b7160e01b5f52604160045260245ffd5b015190505f80610105565b60015f9081528281209350601f198516905b8181106103515750908460019594939210610339575b505050811b0160015561011a565b01515f1960f88460031b161c191690555f808061032b565b92936020600181928786015181550195019301610315565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c810191602085106103cd575b90601f859493920160051c01905b8181106103bf57506100ef565b5f81558493506001016103b2565b90915081906103a4565b91607f16916100db565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102e45760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a7146127c957508063027b6744146127a757806306fdde03146126ec578063081812fc146126ce578063095ea7b3146125c95780631400ecec146125185780631c1cdd4c146124b45780631e99d5691461249757806323b872dd14612480578063303acc851461244357806331df3d4814612330578063406887cb146121c157806340e58ee514611ea8578063425d30dd14611e5857806342842e0e14611e2f57806342966c6814611c6b5780634426757014611c455780634857501f14611bd45780634869e12d14611b9a5780634cc55e1114611aa257806354c02292146117f157806357404b12146117635780636352211e146117345780636d0cee751461173457806370a08231146116ca57806375829def1461165c5780637cad6cd11461156b5780637de6b1db146113ec5780638659c27014610fed578063894e9a0d14610cbe5780638f69b99314610c3e5780639067b67714610bef5780639188ec8414610bb557806395d89b4114610aad578063a22cb465146109f9578063a80fc071146109a8578063ad35efd414610949578063b2564569146108f9578063b637b865146108a0578063b88d4fde14610818578063b8a3be66146107e3578063b971302a14610795578063bc2be1be14610746578063c156a11d1461060f578063c87b56dd146104f9578063d4dbd20b146104a8578063d511609f1461045d578063d975dfed14610423578063e985e9c5146103ca578063ea5ead1914610386578063eac8f5b814610335578063f590c176146102d9578063f851a440146102b45763fdd46d601461026e575f80fd5b346102b05760603660031901126102b0576102876128f6565b6044356001600160801b03811681036102b0576102ae916102a661392e565b6004356133e2565b005b5f80fd5b346102b0575f3660031901126102b05760206001600160a01b035f5416604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060405f205460f81c6040519015158152f35b63699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b346102b05760403660031901126102b05760206004356103b96103a76128f6565b916103b181614209565b928391613085565b6001600160801b0360405191168152f35b346102b05760403660031901126102b0576103e36128e0565b6001600160a01b036103f36128f6565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614209565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a6020526020600260405f20015460801c604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600360405f20015416604051908152f35b346102b05760203660031901126102b057600435610516816136b0565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610604575f90610587575b610583906040519182916020835260208301906128bb565b0390f35b503d805f833e6105978183612a79565b8101906020818303126102b05780519067ffffffffffffffff82116102b057019080601f830112156102b0578151916105cf83612a9b565b916105dd6040519384612a79565b838352602084830101116102b057610583926105ff916020808501910161289a565b61056b565b6040513d5f823e3d90fd5b346102b05760403660031901126102b05760043561062b6128f6565b61063361392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f5260036020526001600160a01b0360405f205416908133036107135761067583614209565b6001600160801b0381169182610703575b6001600160a01b038116156106f0576106a7856001600160a01b03926137f4565b1692836106c15784637e27328960e01b5f5260045260245ffd5b80859185036106d557602084604051908152f35b8492506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b61070e828587613085565b610686565b82632082501160e01b5f526004526001600160a01b03331660245260445ffd5b5063699d2de960e01b5f5260045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160a01b0360405f205416604051908152f35b346102b05760203660031901126102b0576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346102b05760803660031901126102b0576108316128e0565b6108396128f6565b6064359167ffffffffffffffff83116102b057366023840112156102b05782600401359161086683612a9b565b926108746040519485612a79565b80845236602482870101116102b0576020815f9260246102ae9801838801378501015260443591612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600b6020526105836108e560405f20612f0e565b60405191829160208352602083019061298b565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c16156103235761098190613760565b6040516005821015610994576020918152f35b634e487b7160e01b5f52602160045260245ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a60205260206001600160801b03600260405f20015416604051908152f35b346102b05760403660031901126102b057610a126128e0565b602435908115158092036102b0576001600160a01b0316908115610a8157335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0575f3660031901126102b0576040515f6002548060011c90600181168015610bab575b602083108114610b9757828552908115610b735750600114610b15575b61058383610b0181850382612a79565b6040519182916020835260208301906128bb565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210610b5957509091508101602001610b01610af1565b919260018160209254838588010152019101909291610b41565b60ff191660208086019190915291151560051b84019091019150610b019050610af1565b634e487b7160e01b5f52602260045260245ffd5b91607f1691610ad4565b346102b0575f3660031901126102b05760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c161561032357610c7690613760565b6005811015806109945760028214908115610cb2575b8115610ca0575b6020826040519015158152f35b90506109945760046020911482610c93565b5050600381145f610c8c565b346102b05760203660031901126102b057600435604051610180810181811067ffffffffffffffff821117610fd957606091610160916040525f81525f60208201525f60408201525f838201525f60808201525f60a08201525f60c08201525f60e08201525f6101008201525f610120820152610d39612ebe565b6101408201520152805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260405f20604051610d7481612a5c565b8154906001600160a01b0382168152602081019264ffffffffff8360a01c1684526040820164ffffffffff8460c81c168152606083019160ff8560f01c1615158352608084019460f81c1515855260018101549160a08501946001600160a01b038416865260c0810160ff8560a01c1615158152610e13600260e084019560ff8860a81c161515875260ff61010086019860b01c161515885201612edc565b61012083019081526002610e268c613760565b610e2f816129fd565b14610fd1575b5196516001600160a01b0316925164ffffffffff1695511515905115159351151594511515958a5f52600360205260405f20546001600160a01b03169a5f52600b60205260405f2092516001600160a01b0316995164ffffffffff1698511515926040519a610ea66101808d612a79565b8b5260208b019b8c5260408b01998a5260608b0191825260808b0192835260a08b0193845260c08b0194855260e08b019586526101008b019687526101208b019788526101408b01988952610efa90612f0e565b986101608b01998a526040519b8c9b60208d52516001600160a01b031660208d0152516001600160a01b031660408c01525164ffffffffff1660608b01525164ffffffffff1660808a015251151560a089015251151560c0880152516001600160a01b031660e08701525115156101008601525115156101208501525115156101408401525180516001600160801b031661016084015260208101516001600160801b0316610180840152604001516001600160801b03166101a0830152516101c082016101c090526101e082016105839161298b565b5f8752610e35565b634e487b7160e01b5f52604160045260245ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761101e90369060040161295a565b9061102761392e565b5f915b80831061103357005b61103e838284612e4d565b359261104861392e565b835f52600a60205260ff600160405f20015460a81c16156113d857835f52600a60205260ff600160405f20015460a01c165f1461109257836315efa0f360e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c6113c6576110c7815f52600a6020526001600160a01b0360405f205416331490565b156113b0576110d5816136d1565b90805f52600a6020526110ed600260405f2001612edc565b916001600160801b038351166001600160801b038216101561139c57815f52600a60205260ff60405f205460f01c161561138857806001600160801b03602081611141948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611363575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa5061125c6001600160a01b03600160405f2001541694611234888588614663565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a160ff6112a6866001600160a01b03165f52600960205260405f2090565b54166112bc575b5050505050600101919061102a565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91611335575b50160361131957808080806112ad565b636ade251160e01b5f526001600160a01b03602491166004525ffd5b611356915060203d811161135c575b61134e8183612a79565b810190613690565b87611309565b503d611344565b825f52600a602052600160405f2001600160a01b60ff60a01b1982541617905561118b565b50635dd950cb60e11b5f526024906004525ffd5b506308aca53f60e21b5f526024906004525ffd5b632082501160e01b5f526004523360245260445ffd5b63d0a172b360e01b5f5260045260245ffd5b8363699d2de960e01b5f526024906004525ffd5b346102b05760203660031901126102b05760043561140861392e565b805f52600a60205260ff600160405f20015460a81c16156103235761142c81613760565b611435816129fd565b6004810361145057506315efa0f360e11b5f5260045260245ffd5b611459816129fd565b60038103611474575063d0a172b360e01b5f5260045260245ffd5b600290611480816129fd565b14611559576114a3815f52600a6020526001600160a01b0360405f205416331490565b1561153a57805f52600a60205260ff60405f205460f01c1615611528576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635dd950cb60e11b5f5260045260245ffd5b632082501160e01b5f526004526001600160a01b03331660245260445ffd5b6308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576004356001600160a01b0381168091036102b0576001600160a01b035f5416338103611646575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f1981019081116116325760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b634e487b7160e01b5f52601160045260245ffd5b6331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b0576116756128e0565b5f546001600160a01b03811633810361164657506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b346102b05760203660031901126102b0576001600160a01b036116eb6128e0565b168015611708575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b346102b05760203660031901126102b05760206117526004356136b0565b6001600160a01b0360405191168152f35b346102b05760203660031901126102b05760043561177f612ea6565b50805f52600a60205260ff600160405f20015460a81c1615610323575f908152600a6020526040908190205481519064ffffffffff60c882901c81169160a01c166117c983612a40565b825260208201526117ef8251809264ffffffffff60208092828151168552015116910152565bf35b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b0578036036101206003198201126102b05761182c61392e565b60c482013590602219018112156102b057810160048101359067ffffffffffffffff82116102b05760240160608202360381136102b05761186e913691612d69565b9081519161187b83612d51565b926118896040519485612a79565b808452601f1961189882612d51565b015f5b818110611a8b57505064ffffffffff4216916001600160801b036118be82613988565b51511667ffffffffffffffff60206118d584613988565b5101511664ffffffffff8060406118eb86613988565b51015116860116906040519261190084612a24565b83526020830152604082015261191586613988565b5261191f85613988565b5060015b8281106119f75750505061193982600401612e85565b9261194660248401612e85565b9261195360448201612e71565b916064820135936001600160a01b0385168095036102b0576020966119ef966119af966001600160801b036119e4976001600160a01b0361199660848a01612e99565b94816119a460a48c01612e99565b976040519d8e612a07565b168c52168c8b0152166040890152606088015215156080870152151560a086015260c085015260e084015260e4369101612e06565b6101008201526139a9565b604051908152f35b806001600160801b03611a0c60019385613995565b51511667ffffffffffffffff6020611a248487613995565b5101511664ffffffffff806040611a3e5f1987018d613995565b51015116816040611a4f878a613995565b5101511601169060405192611a6384612a24565b835260208301526040820152611a798289613995565b52611a848188613995565b5001611923565b602090611a96612ebe565b8282890101520161189b565b346102b05760403660031901126102b05760043567ffffffffffffffff81116102b057611ad390369060040161295a565b9060243567ffffffffffffffff81116102b057611af490369060040161295a565b9091611afe61392e565b818403611b6a575f5b848110611b1057005b80611b64611b216001938886612e4d565b35611b2d838987612e4d565b355f5260036020526001600160a01b0360405f205416611b56611b5185898b612e4d565b612e71565b91611b5f61392e565b6133e2565b01611b07565b50827fa5ed43e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576103b9602091614159565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f611c0d82613760565b600581101561099457600203611c2b575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16611c1e565b346102b0575f3660031901126102b05760206001600160a01b0360085416604051908152f35b346102b05760203660031901126102b057600435611c8761392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c1615611e0457611cc6816140e7565b156113b057805f5260036020526001600160a01b0360405f205416151580611dfd575b80611de0575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115611d97575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450611d8557005b637e27328960e01b5f5260045260245ffd5b611db6835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055611d3d565b634274c8e160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615611cef565b505f611ce9565b7f6121eb36000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102b0576102ae611e4036612920565b9060405192611e50602085612a79565b5f8452612f95565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b346102b05760203660031901126102b057600435611ec461392e565b805f52600a60205260ff600160405f20015460a81c161561032357805f52600a60205260ff600160405f20015460a01c165f14611f0d576315efa0f360e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c6113c657611f3f815f52600a6020526001600160a01b0360405f205416331490565b1561153a57611f4d816136d1565b90805f52600a602052611f65600260405f2001612edc565b916001600160801b038351166001600160801b03821610156121ae57815f52600a60205260ff60405f205460f01c161561219b57806001600160801b03602081611fb9948188511603169501511690612aed565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115612176575b825f52600a602052600360405f20016001600160801b0382166fffffffffffffffffffffffffffffffff19825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506120ac6001600160a01b03600160405f2001541694611234888588614663565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f2054166120ef57005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561060457630d4af11f60e31b916001600160e01b0319915f91612157575b50160361214557005b636ade251160e01b5f5260045260245ffd5b612170915060203d60201161135c5761134e8183612a79565b8461213c565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055612003565b50635dd950cb60e11b5f5260045260245ffd5b506308aca53f60e21b5f5260045260245ffd5b346102b05760203660031901126102b0576121da6128e0565b6001600160a01b035f54169033820361231957806001600160a01b03913b156122ed57166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610604575f916122be575b501561229357805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7ff1dc125d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6122e0915060203d6020116122e6575b6122d88183612a79565b810190612e35565b82612248565b503d6122ce565b7f295097c8000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b346102b05760203660031901126102b05760043567ffffffffffffffff81116102b05761014060031982360301126102b05761236a61392e565b6040519061237782612a07565b6123838160040161290c565b82526123916024820161290c565b60208301526123a260448201612ab7565b604083015260648101356001600160a01b03811681036102b05760608301526123cd608482016129f0565b60808301526123de60a482016129f0565b60a08301526123ef60c48201612d3f565b60c083015260e481013567ffffffffffffffff81116102b057810191366023840112156102b0576119e46119ef926124336020953690602460048201359101612d69565b60e0840152610104369101612e06565b346102b05760203660031901126102b0576001600160a01b036124646128e0565b165f526009602052602060ff60405f2054166040519015158152f35b346102b0576102ae61249136612920565b91612b0d565b346102b0575f3660031901126102b0576020600754604051908152f35b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576124ec90613760565b600581101561099457806020911590811561250d575b506040519015158152f35b600191501482612502565b346102b05760203660031901126102b057600435805f52600a60205260ff600160405f20015460a81c1615610323576020905f90805f52600a835260ff60405f205460f01c16806125ad575b61257b575b506001600160801b0360405191168152f35b6125a79150805f52600a83526125a16001600160801b03600260405f20015416916136d1565b90612aed565b82612569565b50805f52600a835260ff600160405f20015460a01c1615612564565b346102b05760403660031901126102b0576125e26128e0565b6024356125ee816136b0565b331515806126bb575b80612688575b61265c5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156125fd565b50336001600160a01b03821614156125f7565b346102b05760203660031901126102b0576020611752600435612acb565b346102b0575f3660031901126102b0576040515f6001548060011c9060018116801561279d575b602083108114610b9757828552908115610b73575060011461273f5761058383610b0181850382612a79565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061278357509091508101602001610b01610af1565b91926001816020925483858801015201910190929161276b565b91607f1691612713565b346102b0575f3660031901126102b057602060405167016345785d8a00008152f35b346102b05760203660031901126102b057600435906001600160e01b031982168092036102b057817f490649060000000000000000000000000000000000000000000000000000000060209314908115612825575b5015158152f35b7f80ac58cd00000000000000000000000000000000000000000000000000000000811491508115612870575b811561285f575b508361281e565b6301ffc9a760e01b91501483612858565b7f5b5e139f0000000000000000000000000000000000000000000000000000000081149150612851565b5f5b8381106128ab5750505f910152565b818101518382015260200161289c565b906020916128d48151809281855285808601910161289a565b601f01601f1916010190565b600435906001600160a01b03821682036102b057565b602435906001600160a01b03821682036102b057565b35906001600160a01b03821682036102b057565b60609060031901126102b0576004356001600160a01b03811681036102b057906024356001600160a01b03811681036102b0579060443590565b9181601f840112156102b05782359167ffffffffffffffff83116102b0576020808501948460051b0101116102b057565b90602080835192838152019201905f5b8181106129a85750505090565b9091926020606060019264ffffffffff604088516001600160801b03815116845267ffffffffffffffff8682015116868501520151166040820152019401910191909161299b565b359081151582036102b057565b6005111561099457565b610120810190811067ffffffffffffffff821117610fd957604052565b6060810190811067ffffffffffffffff821117610fd957604052565b6040810190811067ffffffffffffffff821117610fd957604052565b610140810190811067ffffffffffffffff821117610fd957604052565b90601f8019910116810190811067ffffffffffffffff821117610fd957604052565b67ffffffffffffffff8111610fd957601f01601f191660200190565b35906001600160801b03821682036102b057565b612ad4816136b0565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161163257565b91906001600160a01b031680156106f057815f5260036020526001600160a01b0360405f205416151580612d37575b80612d1a575b612d07577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283612c52575b6001600160a01b03935085612c1b575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303612c0357505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b612c3a825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055612ba2565b9192905080612cb0575b15612c6957828291612b92565b8284612c8157637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015612cde575b80612c5c5750825f526005602052336001600160a01b0360405f20541614612c5c565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416612cbb565b50634274c8e160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615612b42565b506001612b3c565b359064ffffffffff821682036102b057565b67ffffffffffffffff8111610fd95760051b60200190565b929192612d7582612d51565b93612d836040519586612a79565b60606020868581520193028201918183116102b057925b828410612da75750505050565b6060848303126102b05760405190612dbe82612a24565b612dc785612ab7565b825260208501359067ffffffffffffffff821682036102b05782602092836060950152612df660408801612d3f565b6040820152815201930192612d9a565b91908260409103126102b057604051612e1e81612a40565b6020808294612e2c8161290c565b84520135910152565b908160209103126102b0575180151581036102b05790565b9190811015612e5d5760051b0190565b634e487b7160e01b5f52603260045260245ffd5b356001600160801b03811681036102b05790565b356001600160a01b03811681036102b05790565b3580151581036102b05790565b60405190612eb382612a40565b5f6020838281520152565b60405190612ecb82612a24565b5f6040838281528260208201520152565b90604051612ee981612a24565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b908154612f1a81612d51565b92612f286040519485612a79565b81845260208401905f5260205f205f915b838310612f465750505050565b600160208192604051612f5881612a24565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190612f39565b90612fa1838284612b0d565b803b612fae575b50505050565b602091612ff46001600160a01b03809316956040519586948594630a85bd0160e11b865233600487015216602485015260448401526080606484015260848301906128bb565b03815f865af15f9181613064575b5061303057506130106141da565b8051908161302b5782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361305257505f808080612fa8565b633250574960e11b5f5260045260245ffd5b61307e91925060203d60201161135c5761134e8183612a79565b905f613002565b9061308e61392e565b815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613367575b613333576001600160801b0361311a86614209565b16808511613300575061313f90855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff191691909117815561318290612edc565b6001600160801b036131a68160208401511692826040818351169201511690612aed565b1611156132ce575b835f52600a6020526131d2836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a183331415806132b8575b61323c5750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f91613299575b50160361214557808080612fa8565b6132b2915060203d60201161135c5761134e8183612a79565b5f61328a565b50835f52600960205260ff60405f205416613232565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b191690556131ae565b84867f066920d7000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b82857f6a166406000000000000000000000000000000000000000000000000000000005f526004523360245260445260645ffd5b50613371856140e7565b15613105565b837fb2ae7633000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b827f2da33e5b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b506315efa0f360e11b5f5260045260245ffd5b90815f52600a60205260ff600160405f20015460a81c161561073357815f52600a60205260ff600160405f20015460a01c166133cf576001600160a01b03811680156133a3576001600160801b03841691821561337757835f5260036020526001600160a01b0360405f205416948583141580613680575b613333576001600160801b0361346f86614209565b16808511613300575061349490855f52600a602052600260405f20015460801c61422f565b5f858152600a6020526040902060020180546001600160801b031660809290921b6fffffffffffffffffffffffffffffffff19169190911781556134d790612edc565b6001600160801b036134fb8160208401511692826040818351169201511690612aed565b16111561364e575b835f52600a602052613527836001600160a01b03600160405f200154169283614663565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580613629575b6135915750505050565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610604576392b9102b60e01b916001600160e01b0319915f9161360a575b5016036135ee57808080612fa8565b6001600160a01b0390636ade251160e01b5f521660045260245ffd5b613623915060203d60201161135c5761134e8183612a79565b5f6135df565b5060ff613647856001600160a01b03165f52600960205260405f2090565b5416613587565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055613503565b5061368a856140e7565b1561345a565b908160209103126102b057516001600160e01b0319811681036102b05790565b805f5260036020526001600160a01b0360405f205416908115611d85575090565b64ffffffffff4216815f52600a6020528064ffffffffff60405f205460a01c16101561375a57815f52600a60205264ffffffffff60405f205460c81c16111561373f57805f52600b602052600160405f2054115f14613736576137339061430f565b90565b6137339061424f565b5f52600a6020526001600160801b03600260405f2001541690565b50505f90565b805f52600a60205260ff600160405f20015460a01c165f146137825750600490565b805f52600a60205260405f205460f81c6137ee57805f52600a60205264ffffffffff60405f205460a01c1642106137e9576137bc816136d1565b905f52600a6020526001600160801b0380600260405f200154169116105f146137e457600190565b600290565b505f90565b50600390565b90805f5260036020526001600160a01b0360405f20541615158061391c575b806138ff575b611dce577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836138c8575b16806138b0575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f206001815401905561386c565b6138e7835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f198154019055613865565b50805f52600a60205260ff600160405f20015460b01c1615613819565b506001600160a01b0382161515613813565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361396057565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b805115612e5d5760200190565b8051821015612e5d5760209160051b010190565b906139cb6001600160801b036040840151166020610100850151015190614525565b916001600160801b038351169060e08101519160c082019264ffffffffff84511682156140bf578015614097578151801561406f577f00000000000000000000000000000000000000000000000000000000000000008111614044575064ffffffffff6040613a3984613988565b5101511681101561400057505f905f905f81515f905b808210613f78575050505064ffffffffff80421691169081811015613f4a5750506001600160801b031690818103613f1c57505060075493845f52600a60205260405f20916001600160801b038251166001600160801b036002850191166fffffffffffffffffffffffffffffffff198254161790556001600160a01b03606082015116916001600160a01b036001850193166001600160a01b031984541617835560808201948551151560ff60f01b197eff00000000000000000000000000000000000000000000000000000000000087549260f01b169116178555835493750100000000000000000000000000000000000000000060a08501957fffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffff76ff000000000000000000000000000000000000000000008851151560b01b169116171790556001600160a01b0380845116166001600160a01b03198654161785555184549060e0840151917fffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff78ffffffffff00000000000000000000000000000000000000007dffffffffff000000000000000000000000000000000000000000000000006040613c248751975f19890190613995565b51015160c81b169360a01b169116171785555f5b818110613e0e575050600187016007556001600160a01b0360208301511680156106f057613c6e886001600160a01b03926137f4565b16613de2578682613cbc6001600160a01b0360607f33eb09bbf19ea3fb22c760d5164234f8bf62ca07dcf5a437ad389e96b0bd6443960151166001600160801b038551169030903390614602565b6001600160801b0360208401511680613db2575b506001600160a01b0381511694613da7613d896001600160a01b03602085015116986001600160a01b036060860151169a511515935115156001600160a01b0361010060e088015193549764ffffffffff60405199613d2e8b612a40565b818160a01c168b5260c81c1660208a015201515116946001600160801b0360206040519a8b9a8b5233828c01528281511660408c01520151166060890152608088015260a087015261014060c087015261014086019061298b565b9260e085019064ffffffffff60208092828151168552015116910152565b6101208301520390a4565b613ddc906001600160a01b036060840151166001600160a01b036101008501515116903390614602565b5f613cd0565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b885f52600b60205260405f2090613e298160e0870151613995565b51825468010000000000000000811015610fd95760018101808555811015612e5d576001935f5260205f2001906001600160801b0380825116166fffffffffffffffffffffffffffffffff198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501613c38565b7f0fa99c11000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f879842de000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b9193509193613f9c906001600160801b03613f938588613995565b5151169061422f565b9364ffffffffff806040613fb08685613995565b51015116941680851115613fcc57506001849301909291613a4f565b8490847f4b90504d000000000000000000000000000000000000000000000000000000005f5260045260245260445260645ffd5b64ffffffffff604061401184613988565b51015116907f93c315e6000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f099c714b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7f5fbab612000000000000000000000000000000000000000000000000000000005f5260045ffd5b7feaa6c316000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f779f8816000000000000000000000000000000000000000000000000000000005f5260045ffd5b805f5260036020526001600160a01b0360405f2054169081331491821561412d575b508115614114575090565b90506001600160a01b036141283392612acb565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f614109565b805f52600a602052614170600260405f2001612edc565b90805f52600a60205260ff600160405f20015460a01c165f1461419e5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6141bd5750613733906136d1565b61373391506001600160801b036040818351169201511690612aed565b3d15614204573d906141eb82612a9b565b916141f96040519384612a79565b82523d5f602084013e565b606090565b6137339061421681614159565b905f52600a602052600260405f20015460801c90612aed565b906001600160801b03809116911601906001600160801b03821161163257565b5f818152600a60205260409020546142869064ffffffffff60a082901c811660c89290921c811682900381169142821603166146b3565b90805f52600b60205260405f20805415612e5d575f526142db67ffffffffffffffff60205f205460801c1692825f52600a6020526142d66001600160801b03600260405f20015416948592614793565b614806565b9182136142f857506142f46001600160801b03916148e1565b1690565b90505f52600a602052600260405f20015460801c90565b9064ffffffffff421691805f52600a60205260405f20906040519061433382612a5c565b6101206143c660028554956001600160a01b0387168652602086019664ffffffffff8160a01c16885264ffffffffff8160c81c16604088015260ff8160f01c161515606088015260f81c1515608087015260ff60018201546001600160a01b03811660a0890152818160a01c16151560c0890152818160a81c16151560e089015260b01c16151561010087015201612edc565b92019182525f52600b6020526143de60405f20612f0e565b915f9264ffffffffff60406143f283613988565b510151168664ffffffffff5f925b16106144e6578161447764ffffffffff9697988784816001600160801b0361442f6142d69861447c9b9a613995565b5151169a8b9867ffffffffffffffff602061444a868b613995565b510151169782604061445c8784613995565b5101511694806144c9575050511680925b03169203166146b3565b614793565b91821361449d5750906001600160801b0361449781936148e1565b16011690565b6001600160801b03915060209051015116806001600160801b038316115f146144c4575090565b905090565b60409250906144db915f190190613995565b51015116809261446d565b936001600160801b03600191816144fd8886613995565b51511601169401958064ffffffffff8060406145198b87613995565b51015116989298614400565b91909160405161453481612a40565b5f81525f6020820152926001600160801b0382169081156145e55767016345785d8a000081116145ae576145706001600160801b0391836154fe565b166020850191818352111561459a576001600160801b03918261459592511690612aed565b168252565b634e487b7160e01b5f52600160045260245ffd5b7ffc8a7df4000000000000000000000000000000000000000000000000000000005f5260045267016345785d8a000060245260445ffd5b50505090506040516145f681612a40565b5f81525f602082015290565b9091926001600160a01b036146619481604051957f23b872dd00000000000000000000000000000000000000000000000000000000602088015216602486015216604484015260648301526064825261465c608483612a79565b614916565b565b614661926001600160a01b03604051937fa9059cbb00000000000000000000000000000000000000000000000000000000602086015216602484015260448301526044825261465c606483612a79565b600160ff1b81148015614786575b61475e575f811215614755576146e5815f035b5f84121561474e57835f039061499b565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161471f575f199118131561471a5790565b5f0390565b907fd49c26b3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b839061499b565b6146e5816146d4565b7f9fe2b450000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b82146146c1565b806147ad57506147a957670de0b6b3a764000090565b5f90565b90670de0b6b3a764000082146147f857806147d0575050670de0b6b3a764000090565b670de0b6b3a764000081146147f4576147ef906142d661373393614aa1565b614bf8565b5090565b5050670de0b6b3a764000090565b600160ff1b811480156148d4575b6148ac575f8112156148a357614838815f035b5f84121561489c57835f03906154fe565b917f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831161486d575f199118131561471a5790565b907f120b5b43000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b83906154fe565b61483881614827565b7fa6070c25000000000000000000000000000000000000000000000000000000005f5260045ffd5b50600160ff1b8214614814565b5f81126148eb5790565b7f2463f3d5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f806001600160a01b0361493f93169360208151910182865af16149386141da565b90836155ac565b8051908115159182614980575b50506149555750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6149939250602080918301019101612e35565b155f8061494c565b5f19670de0b6b3a7640000820991670de0b6b3a7640000820291828085109403938085039414614a665781841015614a2c57670de0b6b3a7640000829109600182190182168092046002816003021880820260020302808202600203028082026002030280820260020302808202600203028091026002030293600183805f03040190848311900302920304170290565b7f63a05778000000000000000000000000000000000000000000000000000000005f52600452670de0b6b3a764000060245260445260645ffd5b5091508115614a73570490565b634e487b7160e01b5f52601260045260245ffd5b8015614a73576ec097ce7bc90715b34b9f10000000000590565b805f811315614bcd57670de0b6b3a76400008112614bad57506001905b670de0b6b3a764000081056001600160801b03811160071b90811c67ffffffffffffffff811160061b90811c63ffffffff811160051b90811c61ffff811160041b90811c9060ff821160031b91821c92600f841160021b93841c94600160038711811b96871c119617171717171717670de0b6b3a7640000810291811d90670de0b6b3a76400008214614b9a57506706f05b59d3b20000905b5f8213614b645750500290565b80670de0b6b3a764000091020590671bc16d674ec80000821215614b8c575b60011d90614b57565b809192019160011d90614b83565b9050670de0b6b3a7640000929150020290565b5f1991508015614a73576ec097ce7bc90715b34b9f100000000005614abe565b7f059b101b000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b5f811215614c255768033dd1780914b971141981126137e957614c1c905f03614bf8565b61373390614a87565b680a688906bd8affffff81136154d357670de0b6b3a76400009060401b057780000000000000000000000000000000000000000000000067ff00000000000000821661539e575b670de0b6b3a76400009066ff000000000000831661528e575b65ff00000000008316615186575b64ff000000008316615086575b63ff0000008316614f8e575b62ff00008316614e9e575b61ff008316614db6575b60ff8316614cd6575b029060401c60bf031c90565b60808316614da3575b60408316614d90575b60208316614d7d575b60108316614d6a575b60088316614d57575b60048316614d44575b60028316614d31575b6001831615614cca57680100000000000000010260401c614cca565b680100000000000000010260401c614d15565b680100000000000000030260401c614d0c565b680100000000000000060260401c614d03565b6801000000000000000b0260401c614cfa565b680100000000000000160260401c614cf1565b6801000000000000002c0260401c614ce8565b680100000000000000590260401c614cdf565b6180008316614e8b575b6140008316614e78575b6120008316614e65575b6110008316614e52575b6108008316614e3f575b6104008316614e2c575b6102008316614e19575b610100831615614cc157680100000000000000b10260401c614cc1565b680100000000000001630260401c614dfc565b680100000000000002c60260401c614df2565b6801000000000000058c0260401c614de8565b68010000000000000b170260401c614dde565b6801000000000000162e0260401c614dd4565b68010000000000002c5d0260401c614dca565b680100000000000058b90260401c614dc0565b628000008316614f7b575b624000008316614f68575b622000008316614f55575b621000008316614f42575b620800008316614f2f575b620400008316614f1c575b620200008316614f09575b62010000831615614cb7576801000000000000b1720260401c614cb7565b680100000000000162e40260401c614eeb565b6801000000000002c5c80260401c614ee0565b68010000000000058b910260401c614ed5565b680100000000000b17210260401c614eca565b68010000000000162e430260401c614ebf565b680100000000002c5c860260401c614eb4565b6801000000000058b90c0260401c614ea9565b63800000008316615073575b63400000008316615060575b6320000000831661504d575b6310000000831661503a575b63080000008316615027575b63040000008316615014575b63020000008316615001575b6301000000831615614cac5768010000000000b172180260401c614cac565b6801000000000162e4300260401c614fe2565b68010000000002c5c8600260401c614fd6565b680100000000058b90c00260401c614fca565b6801000000000b17217f0260401c614fbe565b680100000000162e42ff0260401c614fb2565b6801000000002c5c85fe0260401c614fa6565b68010000000058b90bfc0260401c614f9a565b6480000000008316615173575b6440000000008316615160575b642000000000831661514d575b641000000000831661513a575b6408000000008316615127575b6404000000008316615114575b6402000000008316615101575b640100000000831615614ca057680100000000b17217f80260401c614ca0565b68010000000162e42ff10260401c6150e1565b680100000002c5c85fe30260401c6150d4565b6801000000058b90bfce0260401c6150c7565b68010000000b17217fbb0260401c6150ba565b6801000000162e42fff00260401c6150ad565b68010000002c5c8601cc0260401c6150a0565b680100000058b90c0b490260401c615093565b65800000000000831661527b575b654000000000008316615268575b652000000000008316615255575b651000000000008316615242575b65080000000000831661522f575b65040000000000831661521c575b650200000000008316615209575b65010000000000831615614c93576801000000b1721835510260401c614c93565b680100000162e430e5a20260401c6151e8565b6801000002c5c863b73f0260401c6151da565b68010000058b90cf1e6e0260401c6151cc565b680100000b1721bcfc9a0260401c6151be565b68010000162e43f4f8310260401c6151b0565b680100002c5c89d5ec6d0260401c6151a2565b6801000058b91b5bc9ae0260401c615194565b6680000000000000831661538b575b66400000000000008316615378575b66200000000000008316615365575b66100000000000008316615352575b6608000000000000831661533f575b6604000000000000831661532c575b66020000000000008316615319575b6601000000000000831615614c855768010000b17255775c040260401c614c85565b6801000162e525ee05470260401c6152f7565b68010002c5cc37da94920260401c6152e8565b680100058ba01fb9f96d0260401c6152d9565b6801000b175effdc76ba0260401c6152ca565b680100162f3904051fa10260401c6152bb565b6801002c605e2e8cec500260401c6152ac565b68010058c86da1c09ea20260401c61529d565b67800000000000000082166154b4575b670de0b6b3a76400009067400000000000000083166154a1575b672000000000000000831661548e575b671000000000000000831661547b575b6708000000000000008316615468575b6704000000000000008316615455575b6702000000000000008316615442575b670100000000000000831661542f575b9050614c6c565b680100b1afa5abcbed610260401c615428565b68010163da9fb33356d80260401c615418565b680102c9a3e778060ee70260401c615408565b6801059b0d31585743ae0260401c6153f8565b68010b5586cf9890f62a0260401c6153e8565b6801172b83c7d517adce0260401c6153d8565b6801306fe0a31b7152df0260401c6153c8565b5077b504f333f9de6484800000000000000000000000000000006153ae565b7f0360d028000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f198382098382029182808310920391808303921461559b57670de0b6b3a764000082101561556b577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b906155e957508051156155c157805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b8151158061562f575b6155fa575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b156155f256fea164736f6c634300081a000a"; + hex"60c0604052346103ce5761612b6060813803918261001c816103d2565b9384928339810103126103ce5780516001600160a01b038116908190036103ce5760208201516001600160a01b03811692908390036103ce576040015161006360406103d2565b92601284527114d8589b1a595c88131bd8dadd5c0813919560721b602085015261008d60406103d2565b600a81526905341422d4c4f434b55560b41b6020820152306080525f80546001600160a01b031916851781559093907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a383516001600160401b0381116102df57600154600181811c911680156103c4575b60208210146102c157601f8111610361575b50602094601f82116001146102fe579481929394955f926102f3575b50508160011b915f199060031b1c1916176001555b82516001600160401b0381116102df57600254600181811c911680156102d5575b60208210146102c157601f811161025e575b506020601f82116001146101fb57819293945f926101f0575b50508160011b915f199060031b1c1916176002555b600880546001600160a01b03191691909117905560a0526001600755604051615d3390816103f882396080518161485e015260a05181818161202d01528181614a47015261518b0152f35b015190505f80610190565b601f1982169060025f52805f20915f5b8181106102465750958360019596971061022e575b505050811b016002556101a5565b01515f1960f88460031b161c191690555f8080610220565b9192602060018192868b01518155019401920161020b565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c810191602084106102b7575b601f0160051c01905b8181106102ac5750610177565b5f815560010161029f565b9091508190610296565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610165565b634e487b7160e01b5f52604160045260245ffd5b015190505f8061012f565b601f1982169560015f52805f20915f5b88811061034957508360019596979810610331575b505050811b01600155610144565b01515f1960f88460031b161c191690555f8080610323565b9192602060018192868501518155019401920161030e565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c810191602084106103ba575b601f0160051c01905b8181106103af5750610113565b5f81556001016103a2565b9091508190610399565b90607f1690610101565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176102df5760405256fe6080806040526004361015610012575f80fd5b5f3560e01c90816301ffc9a71461388757508063027b67441461386557806306fdde03146137aa578063081812fc1461378c578063095ea7b3146136875780631400ecec146135d65780631c1cdd4c146135725780631e897afb1461348d5780631e99d5691461347057806323b872dd14613459578063303acc851461341c578063406887cb146132ad57806340e58ee514612fd6578063425d30dd14612f8657806342842e0e14612f5d57806342966c6814612d8357806342e94a7b14612ac55780634426757014612a9f5780634857501f14612a2e5780634869e12d146129f45780634cc55e111461264d57806353ac8bc31461256d57806356b955e81461249f57806357404b12146123d95780636352211e146121285780636611ceab146121575780636d0cee751461212857806370a08231146120be57806375829def1461205057806377163c1d14612016578063780a82c814611fca5780637cad6cd114611eed5780637de6b1db14611da05780637f5799f914611c745780638222b69414611b3a5780638659c270146117825780638f69b993146117025780639067b677146116b357806395d89b41146115ab5780639e7f5dbb1461155a578063a22cb465146114a6578063a80fc07114611455578063ad35efd41461140a578063b2564569146113ba578063b637b8651461127b578063b88d4fde146111f1578063b8a3be66146111bc578063b971302a1461116e578063bc2be1be1461111f578063c156a11d14610d00578063c87b56dd14610bf5578063d4dbd20b14610ba4578063d511609f14610b59578063d975dfed14610b0e578063e6c417eb14610aa3578063e985e9c514610a4a578063ea5ead1914610707578063eac8f5b8146106b6578063f590c1761461065a578063f851a440146106355763fdd46d60146102bb575f80fd5b34610631576060366003190112610631576004356102d76139b4565b906044356001600160801b038116809103610631576102f4614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f52600a60205260ff600160405f20015460a01c1661060b576001600160a01b03831680156105f857825f5260036020526001600160a01b0360405f2054169384821415806105e7575b6105cd5782156105ba576001600160801b0361037585615b3e565b168084116105a05750835f52600a60205282600260405f20015460801c016001600160801b03811161058c576103d490855f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b835f52600a6020526103eb600260405f20016148ae565b6001600160801b0361040f8160208401511692826040818351169201511690613c65565b16111561055a575b835f52600a60205261043b836001600160a01b03600160405f200154169283615b64565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580610544575b6104a157005b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f9161050a575b5016036104f857005b635f3a039d60e01b5f5260045260245ffd5b61052c915060203d602011610532575b6105248183613bf1565b810190614262565b5f6104ef565b503d61051a565b6040513d5f823e3d90fd5b50835f52600960205260ff60405f20541661049b565b5f848152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610417565b634e487b7160e01b5f52601160045260245ffd5b8385632176546160e01b5f5260045260245260445260645ffd5b83633dd1eadf60e21b5f5260045260245ffd5b50826297d0a360e61b5f526004523360245260445260645ffd5b506105f285856148e0565b1561035a565b826316c90d2760e21b5f5260045260245ffd5b5063449491f560e11b5f5260045260245ffd5b50631643770160e21b5f5260045260245ffd5b5f80fd5b34610631575f3660031901126106315760206001600160a01b035f5416604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060405f205460f81c6040519015158152f35b631643770160e21b5f5260045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160a01b03600160405f20015416604051908152f35b34610631576040366003190112610631576004356107236139b4565b61072c82615b3e565b91610735614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c16610a38576001600160a01b0382168015610a2557815f5260036020526001600160a01b0360405f205416938482141580610a14575b6109fa576001600160801b03169283156109e7576001600160801b036107c084615b3e565b168085116109cd5750825f52600a60205283600260405f20015460801c016001600160801b03811161058c5761081f90845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a602052610836600260405f20016148ae565b6001600160801b0361085a8160208401511692826040818351169201511690613c65565b16111561099b575b825f52600a602052610886846001600160a01b03600160405f200154169283615b64565b81837f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a18333141580610985575b6108f6575b602083604051908152f35b604051916392b9102b60e01b8352600483015233602483015260448201528160648201526020816084815f875af1908115610539576392b9102b60e01b916001600160e01b0319915f91610966575b5016036109535781806108eb565b50635f3a039d60e01b5f5260045260245ffd5b61097f915060203d602011610532576105248183613bf1565b85610945565b50835f52600960205260ff60405f2054166108e6565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610862565b8484632176546160e01b5f5260045260245260445260645ffd5b82633dd1eadf60e21b5f5260045260245ffd5b50906297d0a360e61b5f526004523360245260445260645ffd5b50610a1f85846148e0565b1561079b565b506316c90d2760e21b5f5260045260245ffd5b63449491f560e11b5f5260045260245ffd5b3461063157604036600319011261063157610a6361399e565b6001600160a01b03610a736139b4565b91165f5260066020526001600160a01b0360405f2091165f52602052602060ff60405f2054166040519015158152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260ff600160405f20015460b81c166040516003821015610afa576020918152f35b634e487b7160e01b5f52602160045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457610b48602091615b3e565b6001600160801b0360405191168152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a6020526020600260405f20015460801c604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160801b03600360405f20015416604051908152f35b3461063157602036600319011261063157600435610c1281614282565b505f6001600160a01b0360085416916044604051809481937fe9dc637500000000000000000000000000000000000000000000000000000000835230600484015260248301525afa8015610539575f90610c83575b610c7f90604051918291602083526020830190613979565b0390f35b503d805f833e610c938183613bf1565b8101906020818303126106315780519067ffffffffffffffff821161063157019080601f8301121561063157815191610ccb83613c13565b91610cd96040519384613bf1565b8383526020848301011161063157610c7f92610cfb9160208085019101613958565b610c67565b3461063157604036600319011261063157600435610d1c6139b4565b610d24614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f5260036020526001600160a01b0360405f20541690610d6082846148e0565b15611108576001600160801b03610d7684615b3e565b169081158015610dff575b506001600160a01b03811615610dec57610da3846001600160a01b039261471a565b169182610dbd5783637e27328960e01b5f5260045260245ffd5b8084918403610dd157602083604051908152f35b9091506364283d7b60e01b5f5260045260245260445260645ffd5b633250574960e11b5f525f60045260245ffd5b610e07614854565b845f52600a60205260ff600160405f20015460a81c16156110f557845f52600a60205260ff600160405f20015460a01c166110e25783156110cf57845f5260036020526001600160a01b0360405f2054169081851415806110be575b6110a457611091576001600160801b03610e7c86615b3e565b168084116110775750845f52600a60205282600260405f20015460801c016001600160801b03811161058c57610edb90865f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b845f52600a602052610ef2600260405f20016148ae565b6001600160801b03610f168160208401511692826040818351169201511690613c65565b161115611045575b845f52600a6020526001600160a01b03600160405f20015416610f42848683615b64565b84867f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051888152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051878152a1803314158061102f575b15610d81576040516392b9102b60e01b81528560048201523360248201528460448201528360648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f91611010575b501614610d8157635f3a039d60e01b5f5260045260245ffd5b611029915060203d602011610532576105248183613bf1565b88610ff7565b50805f52600960205260ff60405f205416610fa2565b5f858152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055610f1e565b8386632176546160e01b5f5260045260245260445260645ffd5b84633dd1eadf60e21b5f5260045260245ffd5b84866297d0a360e61b5f526004523360245260445260645ffd5b506110c982876148e0565b15610e63565b846316c90d2760e21b5f5260045260245ffd5b8463449491f560e11b5f5260045260245ffd5b84631643770160e21b5f5260045260245ffd5b82634dda2c3960e11b5f526004523360245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602064ffffffffff60405f205460a01c16604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160a01b0360405f205416604051908152f35b34610631576020366003190112610631576004355f52600a602052602060ff600160405f20015460a81c166040519015158152f35b346106315760803660031901126106315761120a61399e565b6112126139b4565b6064359167ffffffffffffffff831161063157366023840112156106315782600401359161123f83613c13565b9261124d6040519485613bf1565b8084523660248287010111610631576020815f9260246112799801838801378501015260443591614172565b005b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460b81c166003811015610afa57600103611371575f52600c60205260405f2080546112e681613efe565b916112f46040519384613bf1565b81835260208301905f5260205f205f915b8383106113225760405160208082528190610c7f90820188613b00565b60016020819260405161133481613b6b565b64ffffffffff86546001600160801b038116835267ffffffffffffffff8160801c168584015260c01c166040820152815201920192019190611305565b5f52600a60205260ff600160405f20015460b81c167fb2a2ea58000000000000000000000000000000000000000000000000000000005f526003811015610afa5760045260245ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060ff600160405f20015460b01c166040519015158152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576114429061468b565b6040516005821015610afa576020918152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a60205260206001600160801b03600260405f20015416604051908152f35b34610631576040366003190112610631576114bf61399e565b60243590811515809203610631576001600160a01b031690811561152e57335f52600660205260405f20825f5260205260405f2060ff1981541660ff83161790556040519081527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b507f5b08ba18000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461063157366003190161016081126106315761014013610631576101443564ffffffffff81168103610631576115a3602091611595614854565b61159e36614038565b61563e565b604051908152f35b34610631575f366003190112610631576040515f6002548060011c906001811680156116a9575b602083108114611695578285529081156116715750600114611613575b610c7f836115ff81850382613bf1565b604051918291602083526020830190613979565b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b808210611657575090915081016020016115ff6115ef565b91926001816020925483858801015201910190929161163f565b60ff191660208086019190915291151560051b840190910191506115ff90506115ef565b634e487b7160e01b5f52602260045260245ffd5b91607f16916115d2565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602064ffffffffff60405f205460c81c16604051908152f35b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a45761173a9061468b565b600581101580610afa5760028214908115611776575b8115611764575b6020826040519015158152f35b9050610afa5760046020911482611757565b5050600381145f611750565b346106315760203660031901126106315760043567ffffffffffffffff8111610631576117b39036906004016139ca565b906117bc614854565b5f915b8083106117c857005b6117d3838284614028565b35926117dd614854565b835f52600a60205260ff600160405f20015460a81c1615611b2757835f52600a60205260ff600160405f20015460a01c165f14611827578363449491f560e11b5f5260045260245ffd5b909192805f52600a60205260405f205460f81c611b155761185c815f52600a6020526001600160a01b0360405f205416331490565b15611aff5761186a816142a3565b90805f52600a602052611882600260405f20016148ae565b916001600160801b038351166001600160801b0382161015611aec57815f52600a60205260ff60405f205460f01c1615611ad957806001600160801b036020816118d6948188511603169501511690613c65565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115611ab4575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506119e86001600160a01b03600160405f20015416946119c0888588615b64565b604080518b81526001600160801b03808b166020830152909216908201529081906060820190565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f205416611a39575b505050505060010191906117bf565b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561053957630d4af11f60e31b916001600160e01b0319915f91611a96575b5016036104f85780808080611a2a565b611aae915060203d8111610532576105248183613bf1565b87611a86565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055611920565b50635c7470b760e01b5f5260045260245ffd5b5063fa36c71760e01b5f5260045260245ffd5b634dda2c3960e11b5f526004523360245260445ffd5b63e707ae4f60e01b5f5260045260245ffd5b83631643770160e21b5f5260045260245ffd5b34610631573660031901610140811261063157610100136106315760403661010319011261063157611b6a614854565b611b7261413f565b64ffffffffff42169081815264ffffffffff611b8c61415d565b16611c59575b610124359064ffffffffff821682036106315764ffffffffff60206001600160a01b0392819583866115a3975082011690816040840152611bd1613f51565b611bd9613f67565b87611be2613f7d565b6001600160801b03611bf2613f93565b9183611bfc613fa9565b95611c05613fb8565b976040519e8f91611c1583613b9b565b169052168a8d01521660408b015216606089015215156080880152151560a087015260c086015260e0850152611c4a36613fef565b6101008501520151169061563e565b64ffffffffff611c6761415d565b8301166020820152611b92565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460b81c166003811015610afa57600203611d57575f52600d60205260405f208054611cdf81613efe565b91611ced6040519384613bf1565b81835260208301905f5260205f205f915b838310611d1b5760405160208082528190610c7f90820188613a97565b600160208192604051611d2d81613bb8565b64ffffffffff86546001600160801b038116835260801c1683820152815201920192019190611cfe565b5f52600a60205260ff600160405f20015460b81c167fcfcba4ef000000000000000000000000000000000000000000000000000000005f526003811015610afa5760045260245ffd5b3461063157602036600319011261063157600435611dbc614854565b805f52600a60205260ff600160405f20015460a81c16156106a457611de08161468b565b6005811015610afa5760048103611e04575063449491f560e11b5f5260045260245ffd5b60038103611e1f575063e707ae4f60e01b5f5260045260245ffd5b600214611edb57611e44815f52600a6020526001600160a01b0360405f205416331490565b15611aff57805f52600a60205260ff60405f205460f01c1615611ec9576020817ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7925f52600a825260405f2060ff60f01b19815416905560405190807f0eb069207093cd3e51cd1370d2d369770057fbe29947e577e5fb428c6c6fc78f5f80a28152a1005b635c7470b760e01b5f5260045260245ffd5b63fa36c71760e01b5f5260045260245ffd5b34610631576020366003190112610631576004356001600160a01b038116809103610631576001600160a01b035f5416338103611fb4575060085490806001600160a01b03198316176008556001600160a01b036040519216825260208201527fa2548bd4b805e907c1558a47b5858324fe8bb4a2e1ddfca647eecbf65610eebc60403392a26007545f19810190811161058c5760407f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91815190600182526020820152a1005b6331b339a960e21b5f526004523360245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600b602052602064ffffffffff60405f205416604051908152f35b34610631575f3660031901126106315760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346106315760203660031901126106315761206961399e565b5f546001600160a01b038116338103611fb457506001600160a01b036001600160a01b0319921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b34610631576020366003190112610631576001600160a01b036120df61399e565b1680156120fc575f526004602052602060405f2054604051908152f35b7f89c62b64000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b34610631576020366003190112610631576020612146600435614282565b6001600160a01b0360405191168152f35b3461063157366003190161012081126106315761010013610631576101043567ffffffffffffffff811161063157612193903690600401613a66565b61219b614854565b6040519182917f66f401dd000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b81811061239557845f81808703817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916122d3575b50612215613f51565b61221d613f67565b91612226613f7d565b9161222f613f93565b93612238613fa9565b612240613fb8565b908451955f19870196871161058c576020976001600160801b036001600160a01b03928364ffffffffff8c6122786115a39d8d613fc7565b5101511697816040519a61228b8c613b9b565b168a52168b89015216604087015216606085015215156080840152151560a083015264ffffffffff421660c083015260e08201526122c836613fef565b6101008201526150eb565b90503d805f833e6122e48183613bf1565b8101906020818303126106315780519067ffffffffffffffff8211610631570181601f820112156106315780519061231b82613efe565b926123296040519485613bf1565b82845260208085019360061b8301019181831161063157602001925b82841061235657505050508161220c565b604084830312610631576020604091825161237081613bb8565b61237987613f16565b8152612386838801613f2a565b83820152815201930192612345565b919350916040806001926001600160801b036123b088613c2f565b16815264ffffffffff6123c560208901613aee565b1660208201520194019101918493926121d9565b34610631576020366003190112610631576004356123f561413f565b50805f52600a60205260ff600160405f20015460a81c16156106a457806060915f52600a60205264ffffffffff60405f205460a01c1690805f52600b60205264ffffffffff60405f205416905f52600a60205264ffffffffff60405f205460c81c16906040519261246584613b6b565b83526020830152604082015261249d604051809264ffffffffff60408092828151168552826020820151166020860152015116910152565bf35b3461063157366003190161016081126106315761014013610631576101443567ffffffffffffffff8111610631576124db903690600401613a66565b6124e3614854565b6124ec36614038565b906124f681613efe565b926125046040519485613bf1565b818452602084019160061b81019036821161063157915b81831061252e5760206115a386866150eb565b604083360312610631576020604091825161254881613bb8565b61255186613c2f565b815261255e838701613aee565b8382015281520192019161251b565b3461063157366003190161016081126106315761014013610631576101443567ffffffffffffffff8111610631576125a9903690600401613a35565b6125b1614854565b6125ba36614038565b906125c481613efe565b926125d26040519485613bf1565b818452606060208501920281019036821161063157915b8183106125fc5760206115a38686614991565b60608336031261063157602060609160405161261781613b6b565b61262086613c2f565b815261262d838701613f3c565b8382015261263d60408701613aee565b60408201528152019201916125e9565b346106315760403660031901126106315760043567ffffffffffffffff81116106315761267e9036906004016139ca565b60243567ffffffffffffffff81116106315761269e9036906004016139ca565b6126a9939193614854565b8083036129c5575f5b8381106126bb57005b6126c6818585614028565b356126d2828686614028565b355f5260036020526001600160a01b0360405f205416906126f4838589614028565b356001600160801b038116908181036106315750612710614854565b815f52600a60205260ff600160405f20015460a81c161561061e57815f52600a60205260ff600160405f20015460a01c1661060b578215610a2557815f5260036020526001600160a01b0360405f2054169283811415806129b4575b61299b5781156109e7576001600160801b0361278784615b3e565b168083116129815750825f52600a60205281600260405f20015460801c016001600160801b03811161058c576127e690845f52600a602052600260405f2001906001600160801b036001600160801b031983549260801b169116179055565b825f52600a6020526127fd600260405f20016148ae565b6001600160801b036128218160208401511692826040818351169201511690613c65565b16111561294f575b825f52600a6020526001600160a01b03600160405f2001541661284d838383615b64565b81847f40b88e5c41c5a97ffb7b6ef88a0a2d505aa0c634cf8a0275cb236ea7dd87ed4d6020604051878152a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051858152a18333141580612939575b6128be575b505050506001016126b2565b604051926392b9102b60e01b84526004840152336024840152604483015260648201526020816084815f865af1908115610539576392b9102b60e01b916001600160e01b0319915f9161291b575b5016036104f8578080806128b2565b612933915060203d8111610532576105248183613bf1565b8961290c565b50835f52600960205260ff60405f2054166128ad565b5f838152600a6020526040902060018101805460ff60a01b1916600160a01b179055805460ff60f01b19169055612829565b8284632176546160e01b5f5260045260245260445260645ffd5b826297d0a360e61b5f526004523360245260445260645ffd5b506129bf84846148e0565b1561276c565b827fc0a1a35a000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a457610b4860209161506a565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f612a678261468b565b6005811015610afa57600203612a85575b6020906040519015158152f35b505f52600a602052602060ff60405f205460f01c16612a78565b34610631575f3660031901126106315760206001600160a01b0360085416604051908152f35b3461063157366003190161012081126106315761010013610631576101043567ffffffffffffffff811161063157612b01903690600401613a35565b612b09614854565b6040519182917fca31a854000000000000000000000000000000000000000000000000000000008352806024840160206004860152526044830191905f5b818110612d2457845f81808703817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f91612c42575b50612b83613f51565b612b8b613f67565b91612b94613f7d565b91612b9d613f93565b93612ba6613fa9565b612bae613fb8565b908451955f19870196871161058c576020976001600160801b036001600160a01b03928364ffffffffff6040612be76115a39d8d613fc7565b5101511697816040519a612bfa8c613b9b565b168a52168b89015216604087015216606085015215156080840152151560a083015264ffffffffff421660c083015260e0820152612c3736613fef565b610100820152614991565b90503d805f833e612c538183613bf1565b8101906020818303126106315780519067ffffffffffffffff8211610631570181601f8201121561063157805190612c8a82613efe565b92612c986040519485613bf1565b8284526020606081860194028301019181831161063157602001925b828410612cc5575050505081612b7a565b6060848303126106315760405190612cdc82613b6b565b612ce585613f16565b825260208501519067ffffffffffffffff821682036106315782602092836060950152612d1460408801613f2a565b6040820152815201930192612cb4565b919350916060806001926001600160801b03612d3f88613c2f565b16815267ffffffffffffffff612d5760208901613f3c565b16602082015264ffffffffff612d6f60408901613aee565b166040820152019401910191849392612b47565b3461063157602036600319011261063157600435612d9f614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c1615612f3257805f526003602052612df46001600160a01b0360405f205416826148e0565b15611aff57805f5260036020526001600160a01b0360405f205416151580612f2b575b80612f0e575b612efc577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b0360405f2054168015908115612ec5575b825f52600360205260405f206001600160a01b03198154169055825f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a450612eb357005b637e27328960e01b5f5260045260245ffd5b612ee4835f52600560205260405f206001600160a01b03198154169055565b805f52600460205260405f205f198154019055612e6b565b6349d74b1160e11b5f5260045260245ffd5b50805f52600a60205260ff600160405f20015460b01c1615612e1d565b505f612e17565b7fa6ba32da000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b3461063157611279612f6e366139fb565b9060405192612f7e602085613bf1565b5f8452614172565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4575f52600a602052602060ff600160405f20015460a01c166040519015158152f35b3461063157602036600319011261063157600435612ff2614854565b805f52600a60205260ff600160405f20015460a81c16156106a457805f52600a60205260ff600160405f20015460a01c165f1461303b5763449491f560e11b5f5260045260245ffd5b805f52600a60205260405f205460f81c611b155761306d815f52600a6020526001600160a01b0360405f205416331490565b15611aff5761307b816142a3565b90805f52600a602052613093600260405f20016148ae565b916001600160801b038351166001600160801b0382161015611aec57815f52600a60205260ff60405f205460f01c1615611ad957806001600160801b036020816130e7948188511603169501511690613c65565b5f828152600a6020526040902080547dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16600160f81b179055916001600160801b038316908115613288575b825f52600a602052600360405f20016001600160801b0382166001600160801b0319825416179055825f52600a6020526001600160a01b0360405f205416835f5260036020526001600160a01b0360405f20541694845f52600a60205285827f5edb27d6c1a327513b90a792050debf074b7194444885e3144d4decc5caaaa506131d16001600160a01b03600160405f20015416946119c0888588615b64565b0390a47ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051868152a1845f52600960205260ff60405f20541661321457005b60405193630d4af11f60e31b855260048501526024840152604483015260648201526020816084815f865af190811561053957630d4af11f60e31b916001600160e01b0319915f91613269575016036104f857005b613282915060203d602011610532576105248183613bf1565b846104ef565b825f52600a602052600160405f2001600160a01b60ff60a01b19825416179055613131565b34610631576020366003190112610631576132c661399e565b6001600160a01b035f54169033820361340557806001600160a01b03913b156133d957166040516301ffc9a760e01b81527ff8ee98d3000000000000000000000000000000000000000000000000000000006004820152602081602481855afa908115610539575f916133aa575b501561337f57805f52600960205260405f20600160ff198254161790556040519081527fb4378d4e289cb3f40f4f75a99c9cafa76e3df1c4dc31309babc23dc91bd7280160203392a2005b7f976c0d64000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6133cc915060203d6020116133d2575b6133c48183613bf1565b810190613ee6565b82613334565b503d6133ba565b7f65453b0d000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b506331b339a960e21b5f526004523360245260445ffd5b34610631576020366003190112610631576001600160a01b0361343d61399e565b165f526009602052602060ff60405f2054166040519015158152f35b346106315761127961346a366139fb565b91613cb4565b34610631575f366003190112610631576020600754604051908152f35b346106315760203660031901126106315760043567ffffffffffffffff8111610631576134be9036906004016139ca565b9036819003601e1901905f5b83811015611279578060051b8201358381121561063157820180359067ffffffffffffffff821161063157602001813603811361063157815f92918392604051928392833781018381520390305af4613521613c85565b901561353057506001016134ca565b61356e906040519182917fd9354485000000000000000000000000000000000000000000000000000000008352602060048401526024830190613979565b0390fd5b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576135aa9061468b565b6005811015610afa5780602091159081156135cb575b506040519015158152f35b6001915014826135c0565b3461063157602036600319011261063157600435805f52600a60205260ff600160405f20015460a81c16156106a4576020905f90805f52600a835260ff60405f205460f01c168061366b575b613639575b506001600160801b0360405191168152f35b6136659150805f52600a835261365f6001600160801b03600260405f20015416916142a3565b90613c65565b82613627565b50805f52600a835260ff600160405f20015460a01c1615613622565b34610631576040366003190112610631576136a061399e565b6024356136ac81614282565b33151580613779575b80613746575b61371a5781906001600160a01b0380851691167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a45f5260056020526001600160a01b0360405f2091166001600160a01b03198254161790555f80f35b7fa9fbf51f000000000000000000000000000000000000000000000000000000005f523360045260245ffd5b506001600160a01b0381165f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416156136bb565b50336001600160a01b03821614156136b5565b34610631576020366003190112610631576020612146600435613c43565b34610631575f366003190112610631576040515f6001548060011c9060018116801561385b575b6020831081146116955782855290811561167157506001146137fd57610c7f836115ff81850382613bf1565b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210613841575090915081016020016115ff6115ef565b919260018160209254838588010152019101909291613829565b91607f16916137d1565b34610631575f36600319011261063157602060405167016345785d8a00008152f35b3461063157602036600319011261063157600435906001600160e01b0319821680920361063157817f4906490600000000000000000000000000000000000000000000000000000000602093149081156138e3575b5015158152f35b7f80ac58cd0000000000000000000000000000000000000000000000000000000081149150811561392e575b811561391d575b50836138dc565b6301ffc9a760e01b91501483613916565b7f5b5e139f000000000000000000000000000000000000000000000000000000008114915061390f565b5f5b8381106139695750505f910152565b818101518382015260200161395a565b9060209161399281518092818552858086019101613958565b601f01601f1916010190565b600435906001600160a01b038216820361063157565b602435906001600160a01b038216820361063157565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501948460051b01011161063157565b6060906003190112610631576004356001600160a01b038116810361063157906024356001600160a01b0381168103610631579060443590565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501946060850201011161063157565b9181601f840112156106315782359167ffffffffffffffff8311610631576020808501948460061b01011161063157565b90602080835192838152019201905f5b818110613ab45750505090565b9091926020604082613ae3600194885164ffffffffff602080926001600160801b038151168552015116910152565b019401929101613aa7565b359064ffffffffff8216820361063157565b90602080835192838152019201905f5b818110613b1d5750505090565b9091926020606082613b60600194885164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b019401929101613b10565b6060810190811067ffffffffffffffff821117613b8757604052565b634e487b7160e01b5f52604160045260245ffd5b610120810190811067ffffffffffffffff821117613b8757604052565b6040810190811067ffffffffffffffff821117613b8757604052565b610160810190811067ffffffffffffffff821117613b8757604052565b90601f8019910116810190811067ffffffffffffffff821117613b8757604052565b67ffffffffffffffff8111613b8757601f01601f191660200190565b35906001600160801b038216820361063157565b613c4c81614282565b505f5260056020526001600160a01b0360405f20541690565b906001600160801b03809116911603906001600160801b03821161058c57565b3d15613caf573d90613c9682613c13565b91613ca46040519384613bf1565b82523d5f602084013e565b606090565b91906001600160a01b03168015610dec57815f5260036020526001600160a01b0360405f205416151580613ede575b80613ec1575b613eae577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051848152a1815f5260036020526001600160a01b0360405f20541692823315159283613df9575b6001600160a01b03935085613dc2575b805f52600460205260405f2060018154019055815f52600360205260405f20816001600160a01b0319825416179055857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a416808303613daa57505050565b6364283d7b60e01b5f5260045260245260445260645ffd5b613de1825f52600560205260405f206001600160a01b03198154169055565b855f52600460205260405f205f198154019055613d49565b9192905080613e57575b15613e1057828291613d39565b8284613e2857637e27328960e01b5f5260045260245ffd5b7f177e802f000000000000000000000000000000000000000000000000000000005f523360045260245260445ffd5b503384148015613e85575b80613e035750825f526005602052336001600160a01b0360405f20541614613e03565b50835f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416613e62565b506349d74b1160e11b5f5260045260245ffd5b50815f52600a60205260ff600160405f20015460b01c1615613ce9565b506001613ce3565b90816020910312610631575180151581036106315790565b67ffffffffffffffff8111613b875760051b60200190565b51906001600160801b038216820361063157565b519064ffffffffff8216820361063157565b359067ffffffffffffffff8216820361063157565b6004356001600160a01b03811681036106315790565b6024356001600160a01b03811681036106315790565b6044356001600160801b03811681036106315790565b6064356001600160a01b03811681036106315790565b60843580151581036106315790565b60a43580151581036106315790565b8051821015613fdb5760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b60409060c3190112610631576040519061400882613bb8565b8160c4356001600160a01b0381168103610631578152602060e435910152565b9190811015613fdb5760051b0190565b906101406003198301126106315760405161405281613b9b565b80926004356001600160a01b03811681036106315782526024356001600160a01b03811681036106315760208301526044356001600160801b03811681036106315760408301526064356001600160a01b0381168103610631576060830152608435801515810361063157608083015260a43580151581036106315760a083015260c43564ffffffffff811681036106315760c083015260e43564ffffffffff811681036106315760e0830152604061010480920312610631576040519161411983613bb8565b81356001600160a01b038116810361063157610100926020918552013560208401520152565b6040519061414c82613b6b565b5f6040838281528260208201520152565b6101043564ffffffffff811681036106315790565b9061417e838284613cb4565b803b61418b575b50505050565b6020916141d16001600160a01b03809316956040519586948594630a85bd0160e11b86523360048701521660248501526044840152608060648401526084830190613979565b03815f865af15f9181614241575b5061420d57506141ed613c85565b805190816142085782633250574960e11b5f5260045260245ffd5b602001fd5b6001600160e01b0319630a85bd0160e11b91160361422f57505f808080614185565b633250574960e11b5f5260045260245ffd5b61425b91925060203d602011610532576105248183613bf1565b905f6141df565b9081602091031261063157516001600160e01b0319811681036106315790565b805f5260036020526001600160a01b0360405f205416908115612eb3575090565b5f64ffffffffff421690825f52600a6020528164ffffffffff60405f205460a01c16101561468457825f52600a6020528164ffffffffff60405f205460c81c16111561466757825f52600a60205260ff600160405f20015460b81c166003811015610afa57600103614451575050805f52600c60205260405f2090805f52600a602052600260405f20015460801c905f52600a60205264ffffffffff60405f205460a01c16906040519283917f6d0434810000000000000000000000000000000000000000000000000000000083526064830160606004850152825480915260848401925f5260205f20905f5b81811061440b575050509060209383926024840152604483015203817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b90506020813d602011614403575b816143ef60209383613bf1565b810103126106315761440090613f16565b90565b3d91506143e2565b82546001600160801b0381168652608081901c67ffffffffffffffff16602087015260c01c64ffffffffff16604086015287955060609094019360019283019201614390565b825f52600a60205260ff600160405f20015460b81c166003811015610afa576145355750815f52600b60205264ffffffffff60405f20541611614530575f908152600a60209081526040918290206002810154905492517ea57c350000000000000000000000000000000000000000000000000000000081526001600160801b038216600482015260809190911c602482015264ffffffffff60a084901c8116604483015260c89390931c9092166064830152816084817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b505f90565b92918091505f52600a60205260ff600160405f20015460b81c166003811015610afa576002146145625750565b9091505f52600d60205260405f2080549061457c82613efe565b9161458a6040519384613bf1565b8083526020830180925f5260205f205f915b83831061462b5750505050815115613fdb5764ffffffffff60204292510151161161453057602061460191604051809381927f5515a8160000000000000000000000000000000000000000000000000000000083528460048401526024830190613a97565b03817326f9d826bded47fc472526ae8095b75ac336963c5af4908115610539575f916143d4575090565b60016020819260405161463d81613bb8565b64ffffffffff86546001600160801b038116835260801c168382015281520192019201919061459c565b50505f52600a6020526001600160801b03600260405f2001541690565b5050505f90565b805f52600a60205260ff600160405f20015460a01c165f146146ad5750600490565b805f52600a60205260405f205460f81c61471457805f52600a60205264ffffffffff60405f205460a01c164210614530576146e7816142a3565b905f52600a6020526001600160801b0380600260405f200154169116105f1461470f57600190565b600290565b50600390565b90805f5260036020526001600160a01b0360405f205416151580614842575b80614825575b612efc577ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce76020604051838152a1805f5260036020526001600160a01b038060405f20541692836147ee575b16806147d6575b815f52600360205260405f20816001600160a01b0319825416179055827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a490565b805f52600460205260405f2060018154019055614792565b61480d835f52600560205260405f206001600160a01b03198154169055565b835f52600460205260405f205f19815401905561478b565b50805f52600a60205260ff600160405f20015460b01c161561473f565b506001600160a01b0382161515614739565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016300361488657565b7fa1c0d6e5000000000000000000000000000000000000000000000000000000005f5260045ffd5b906040516148bb81613b6b565b60406001600160801b03600183958054838116865260801c6020860152015416910152565b906001600160a01b03169081331491821561491a575b508115614901575090565b90506001600160a01b036149153392613c43565b161490565b9091505f52600660205260405f206001600160a01b0333165f5260205260ff60405f205416905f6148f6565b908160409103126106315761497460206040519261496384613bb8565b61496c81613f16565b845201613f16565b602082015290565b8054821015613fdb575f5260205f2001905f90565b91906001600160a01b038351169060c084019164ffffffffff8351169160e086019364ffffffffff855116936001600160801b0360408901511690610100890194602086510151926040519788937f8d86721600000000000000000000000000000000000000000000000000000000855261010485019360048601526024850152604484015260648301526101006084830152845180915261012482019060208601905f5b8181106150165750505081906040937f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af49182156105395787945f93614fe5575b506007549185516001600160a01b031696815164ffffffffff1691815164ffffffffff16986080890199868b5115159160608c019b8c516001600160a01b03169060a0019788511515928c516001600160801b03169560405196614b0a88613b6b565b8752602087015f9052604087015f905260405197614b2789613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860018a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b191617178955511515614c0090899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57614d34876001600160a01b039261471a565b16614fb957614d5c6001600160a01b038a51166001600160801b038951169030903390615c40565b6001600160801b0360208801511680614f90575b5060018601600755859b85515f5b818110614e7e57505092614e7994926001600160a01b03614e5f9364ffffffffff808380807fe4b2b82a71eaf8e03605924b1a288d8ea6d28734c85f6aec6f58f27f1473d1629f9e9d9b51169f51169f51169f5115159751151594511694511660405194614deb86613b6b565b85525f6020860152604085015251511693614e2c604051998a998a523360208b015260408a01906001600160801b0360208092828151168552015116910152565b608088015260a087015260c086019064ffffffffff60408092828151168552826020820151166020860152015116910152565b610120840152610160610140840152610160830190613b00565b0390a4565b885f52600c60205260405f2090614e95818a613fc7565b5191805468010000000000000000811015613b8757614eb99160018201815561497c565b614f7d57826001600160801b03806001955116166001600160801b03198354161782556020810151907fffffff00000000000000000000000000ffffffffffffffffffffffffffffffff7cffffffffff000000000000000000000000000000000000000000000000604077ffffffffffffffff0000000000000000000000000000000086549560801b1693847fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff8716178755015160c01b1692161717905501614d7e565b634e487b7160e01b5f525f60045260245ffd5b614fb3906001600160a01b038b51166001600160a01b0384515116903390615c40565b5f614d70565b7f73c6ac6e000000000000000000000000000000000000000000000000000000005f525f60045260245ffd5b61500891935060403d60401161500f575b6150008183613bf1565b810190614946565b915f614aa7565b503d614ff6565b9194935091602060608261505b600194895164ffffffffff604080926001600160801b03815116855267ffffffffffffffff6020820151166020860152015116910152565b01950191019188939492614a36565b805f52600a602052615081600260405f20016148ae565b90805f52600a60205260ff600160405f20015460a01c165f146150af5750602001516001600160801b031690565b90815f52600a60205260405f205460f81c6150ce5750614400906142a3565b61440091506001600160801b036040818351169201511690613c65565b91906001600160a01b038351169060c084019164ffffffffff8351169160e0860193604064ffffffffff865116946001600160801b03828a015116946101008a019560208751015190845198899485947f87edd65700000000000000000000000000000000000000000000000000000000865260048601526024850152604484015260648301526101006084830152615188610104830187613a97565b907f000000000000000000000000000000000000000000000000000000000000000060a484015260c483015267016345785d8a000060e48301520381737715be116061e014bb721b46dc78dd57c91fdf9b5af49182156105395787945f9361561d575b506007549185516001600160a01b031696815164ffffffffff1691815164ffffffffff16986080890199868b5115159160608c019b8c516001600160a01b03169060a0019788511515928c516001600160801b0316956040519661524e88613b6b565b8752602087015f9052604087015f90526040519761526b89613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b019860028a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561534490899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57615478876001600160a01b039261471a565b16614fb9576154a06001600160a01b038a51166001600160801b038951169030903390615c40565b6001600160801b03602088015116806155f4575b5060018601600755859b85515f5b81811061554957505092614e7994926001600160a01b0361552f9364ffffffffff808380807f3fbf4970c1a9f5fd9b4d744372d4e920f7f6283b4af7175bd002c6a063dfde539f9e9d9b51169f51169f51169f5115159751151594511694511660405194614deb86613b6b565b610120840152610160610140840152610160830190613a97565b885f52600d60205260405f2090615560818a613fc7565b5191805468010000000000000000811015613b87576155849160018201815561497c565b614f7d576020836001600160801b03806001965116166001600160801b031984541617835501517fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff74ffffffffff0000000000000000000000000000000083549260801b169116179055016154c2565b615617906001600160a01b038b51166001600160a01b0384515116903390615c40565b5f6154b4565b61563791935060403d60401161500f576150008183613bf1565b915f6151eb565b91906001600160a01b0383511660c0840164ffffffffff8151169060e0860164ffffffffff815116926001600160801b0360408901511664ffffffffff6101008a019760208951015193604051987f55572bf4000000000000000000000000000000000000000000000000000000008a5260048a0152602489015216948560448801526064870152608486015260a485015267016345785d8a000060c485015260408460e481737715be116061e014bb721b46dc78dd57c91fdf9b5af49081156105395787945f92615b1d575b506007549285516001600160a01b031696815164ffffffffff1690835164ffffffffff16986080890199878b5115159160608c019b8c516001600160a01b03169060a0019687511515928b516001600160801b0316956040519661576e88613b6b565b8752602087015f9052604087015f90526040519761578b89613bd4565b885260208801928352604088019182526060880190815260808801905f825260a0890194855260c08901925f845260e08a0194600186526101008b019788526101208b01985f8a526101408c019a8b525f52600a60205260405f209a516001600160a01b03166001600160a01b03168b546001600160a01b031916178b5551908a54905160c81b64ffffffffff60c81b169160a01b64ffffffffff60a01b169069ffffffffffffffffffff60a01b19161717895551151561586390899060ff60f01b1960ff60f01b835492151560f01b169116179055565b5187546001600160f81b031690151560f81b7fff00000000000000000000000000000000000000000000000000000000000000161787559151600187018054935160ff60a01b90151560a01b166001600160a01b0390921674ffffffffffffffffffffffffffffffffffffffffff19909416939093171782555115159381549251151560b01b60ff60b01b169351916003831015610afa5762ffffff60a81b1990931660a89590951b60ff60a81b169490941790921760b89290921b60ff60b81b16919091179055518051602082015160801b6001600160801b0319166001600160801b039182161760028401559060039082906040015116920191166001600160801b031982541617905560208b01966001600160a01b038851168015610dec57615997886001600160a01b039261471a565b16614fb9576159bf6001600160a01b038a51166001600160801b038851169030903390615c40565b6001600160801b0360208701511680615af4575b5060018701600755869b81615ad5575b516001600160a01b031697516001600160a01b031698516001600160a01b03169951151592511515935164ffffffffff16945164ffffffffff169060405195615a2b87613b6b565b86526020860152604085015251516001600160a01b03169360405195865233602087015260408601615a71916001600160801b0360208092828151168552015116910152565b608085015260a084015260c08301615aa79164ffffffffff60408092828151168552826020820151166020860152015116910152565b6101208201526101407f44cb432df42caa86b7ec73644ab8aec922bc44c71c98fc330addc75b88adbc7c91a4565b875f52600b60205260405f208264ffffffffff198254161790556159e3565b615b17906001600160a01b038b51166001600160a01b0385515116903390615c40565b5f6159d3565b615b3791925060403d60401161500f576150008183613bf1565b905f61570b565b61440090615b4b8161506a565b905f52600a602052600260405f20015460801c90613c65565b615bb9926001600160a01b03604051937fa9059cbb000000000000000000000000000000000000000000000000000000006020860152166024840152604483015260448252615bb4606483613bf1565b615bbb565b565b5f806001600160a01b03615be493169360208151910182865af1615bdd613c85565b9083615c9a565b8051908115159182615c25575b5050615bfa5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b615c389250602080918301019101613ee6565b155f80615bf1565b9091926001600160a01b03615bb99481604051957f23b872dd000000000000000000000000000000000000000000000000000000006020880152166024860152166044840152606483015260648252615bb4608483613bf1565b90615cd75750805115615caf57805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580615d1d575b615ce8575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15615ce056fea164736f6c634300081a000a"; bytes public constant BYTECODE_MERKLE_FACTORY = hex"608034609357601f615a8a38819003918201601f19168301916001600160401b03831184841017609757808492602094604052833981010312609357516001600160a01b038116908190036093575f80546001600160a01b0319168217815560405191907fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a36159de90816100ac8239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffdfe60806040526004361015610011575f80fd5b5f3560e01c8063070a6b8414610d0e5780631134f19414610cf157806345aa9357146109735780634d7c0f11146108a05780636f71d8f41461083057806375829def146107aa5780638af96dfe14610723578063b3ee17cc146102f9578063d498fcf514610265578063f255527814610135578063f851a440146101105763f946eef21461009d575f80fd5b3461010c57602036600319011261010c576004356001600160a01b035f54163381036100f65750806001556040519081527f7d41b7bcff330c958826f81c5de08357f286914f0758727ca23717d24f158fcc60203392a2005b6331b339a960e21b5f526004523360245260445ffd5b5f80fd5b3461010c575f36600319011261010c5760206001600160a01b035f5416604051908152f35b3461010c57604036600319011261010c576004356001600160a01b03811680910361010c57602435906001600160a01b03821680920361010c576001600160a01b035f54163381036100f65750801561023d576040517f164e68de0000000000000000000000000000000000000000000000000000000081528160048201526020816024815f875af1908115610232575f91610200575b5060405191825260208201527ff65e64e219c3199240f0fe17a71d01821ed2dd08283833094e12a9ad6883786560403392a3005b90506020813d60201161022a575b8161021b60209383610f14565b8101031261010c5751836101cc565b3d915061020e565b6040513d5f823e3d90fd5b7f38da7036000000000000000000000000000000000000000000000000000000005f5260045ffd5b3461010c57604036600319011261010c5761027e610f5c565b602435906001600160a01b035f54163381036100f657506001600160a01b031690815f52600260205280600160405f20805460ff8116156102eb575b5001556040519081527f314737fce28d10af73c184056111a030c8124d005478d4a11f5978545779ed9a60203392a3005b60ff191682178155856102ba565b3461010c5761010036600319011261010c5760043567ffffffffffffffff811161010c5761032b903690600401610fc8565b610333611089565b9061033c61109f565b906103456110ae565b9061034e610f36565b60a4359167ffffffffffffffff831161010c573660238401121561010c57826004013567ffffffffffffffff8111610683576040519361039460208360051b0186610f14565b8185526024602086019260061b8201019036821161010c57602401915b8183106106d65750505082515f905f905b808210610697575050336103d5906111e3565b825160208401516040850151908760608701519a604051809c602082016020905260408201610403916110de565b03601f1981018d52610415908d610f14565b6080880151908d60a08a015160405181819251908160208401916020019161043c926110bd565b81010380825261044f9060200182610f14565b61045890611103565b6040519e8f806020810197602089526040820161047491611193565b03601f198101825261048591610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d880152805190816061890191602001916104ee926110bd565b860193606185015260818401526001600160a01b03169d6bffffffffffffffffffffffff199060601b1660a183015215159a8b60f81b60b583015215159b8c60f81b60b683015264ffffffffff8a169960d81b6001600160d81b03191660b783015251918260bc8301610560926110bd565b0160610103605b01601f19810182526105799082610f14565b519020604051611e7b80820182811067ffffffffffffffff821117610683578460c06105de8e8e8e8897613b57893960e087526105ba8d60e0890190611125565b926020880152604087015260608601528b608086015284810360a08601528c611193565b92015203905ff58015610232576020987f4507eb2a4efc5eacd7bf717901bdc881a42a88f0e7c45a050d6d1375521883649661063a966001600160a01b0361065b94169a8b9a604051998a996101408b526101408b0190611125565b948e8a015260408901526060880152608087015285820360a0870152611193565b9160c084015260c43560e084015260e4356101008401526101208301520390a2604051908152f35b634e487b7160e01b5f52604160045260245ffd5b909185518310156106c25760019064ffffffffff6020808660051b8a010151015116019201906103c2565b634e487b7160e01b5f52603260045260245ffd5b60408336031261010c57604051906106ed82610ef8565b83359067ffffffffffffffff8216820361010c578260209260409452610714838701610f4a565b838201528152019201916103b1565b3461010c57602036600319011261010c5761073c610f5c565b6001600160a01b035f541690338203610793576001600160a01b0316805f5260026020525f6001604082208281550155337f8cebf46c84bf401fa7816b701dfac1f1fdf41e6e601b9a501e7639d2aff5582f5f80a3005b506331b339a960e21b5f526004523360245260445ffd5b3461010c57602036600319011261010c576107c3610f5c565b5f546001600160a01b0381163381036100f657506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b3461010c57602036600319011261010c576001600160a01b03610851610f5c565b5f602060405161086081610ef8565b8281520152165f5260026020526040805f20815161087d81610ef8565b6020600160ff845416151593848452015491019081528251918252516020820152f35b3461010c57602036600319011261010c5760043567ffffffffffffffff811161010c573660238201121561010c5780600401359067ffffffffffffffff821161010c573660248360061b8301011161010c575f90815b838310156109545760248360061b830101359067ffffffffffffffff821680920361010c5767ffffffffffffffff160167ffffffffffffffff8111610940576001909201916108f6565b634e487b7160e01b5f52601160045260245ffd5b602090670de0b6b3a764000067ffffffffffffffff6040519216148152f35b3461010c5761012036600319011261010c5760043567ffffffffffffffff811161010c576109a5903690600401610fc8565b6109ad611089565b6109b561109f565b906109be6110ae565b90606036608319011261010c576040516060810181811067ffffffffffffffff821117610683576040526109f0610f36565b815260a43564ffffffffff8116810361010c57602082015260c43564ffffffffff8116810361010c576040820152845160208601516040870151906060880151966040519081602081019960208b5260408201610a4c916110de565b03601f1981018352610a5e9083610f14565b60808a01519060a08b0151604051818192519081602084019160200191610a84926110bd565b810103808252610a979060200182610f14565b610aa090611103565b6040519a60208c0194610ad2868b64ffffffffff60408092828151168552826020820151166020860152015116910152565b60608d52610ae160808e610f14565b604051978897602089019a3360601b8c526bffffffffffffffffffffffff199060601b1660348a015260d81b6001600160d81b03191660488901526bffffffffffffffffffffffff199060601b16604d88015251908160618801610b44926110bd565b850192606184015260818301526001600160a01b038816976bffffffffffffffffffffffff199060601b1660a18301521515978860f81b60b58301521515988960f81b60b683015251918260b78301610b9c926110bd565b0160610103605601601f1981018252610bb59082610f14565b51902094610bc2336111e3565b9560405161182380820182811067ffffffffffffffff821117610683578291612334833961010081528960e0610bfc610100840188611125565b928960208201528a60408201528b6060820152610c3b608082018a64ffffffffff60408092828151168552826020820151166020860152015116910152565b015203905ff592831561023257602096610cce610c96946001600160a01b037fe7c4d633a3f64a821f1283e2a399b368e633c17776b3cb932e4105d76ca299e397169889986040519788976101408952610140890190611125565b958c88015260408701526060860152608085019064ffffffffff60408092828151168552826020820151166020860152015116910152565b60e43560e0840152610104356101008401526101208301520390a2604051908152f35b3461010c575f36600319011261010c576020600154604051908152f35b3461010c57606036600319011261010c5760043567ffffffffffffffff811161010c57610d3f903690600401610fc8565b80516001600160d81b0319610e3e60406061602086015182870151606088015190845191610d8a83610d7c602082019360208552898301906110de565b03601f198101855284610f14565b610e2360808b015193610dcc60a08d0151610dc760208b5183610db682955180928580860191016110bd565b81010301601f198101835282610f14565b611103565b9388519a8b97602089019d8e3360601b90526bffffffffffffffffffffffff199060601b1660348a015260d81b1660488801526bffffffffffffffffffffffff199060601b16604d870152518092878701906110bd565b83019184830152608182015203016020810184520182610f14565b51902090610e4b336111e3565b9160405161111880820182811067ffffffffffffffff82111761068357829161121c833960408152856020610e836040840188611125565b92015203905ff5918215610232577f12188a644c16704b9e77e2ecd3bb77e911693c22ffb0fcf44d9e4b36638b5d01610ed86001600160a01b0360209516938493604051928392608084526080840190611125565b9060243588840152604435604084015260608301520390a2604051908152f35b6040810190811067ffffffffffffffff82111761068357604052565b90601f8019910116810190811067ffffffffffffffff82111761068357604052565b6084359064ffffffffff8216820361010c57565b359064ffffffffff8216820361010c57565b600435906001600160a01b038216820361010c57565b81601f8201121561010c5780359067ffffffffffffffff82116106835760405192610fa7601f8401601f191660200185610f14565b8284526020838301011161010c57815f926020809301838601378301015290565b919060c08382031261010c576040519060c0820182811067ffffffffffffffff82111761068357604052819380356001600160a01b038116810361010c57835261101460208201610f4a565b602084015260408101356001600160a01b038116810361010c576040840152606081013567ffffffffffffffff811161010c5782611053918301610f72565b60608401526080810135608084015260a08101359167ffffffffffffffff831161010c5760a0926110849201610f72565b910152565b602435906001600160a01b038216820361010c57565b60443590811515820361010c57565b60643590811515820361010c57565b5f5b8381106110ce5750505f910152565b81810151838201526020016110bf565b906020916110f7815180928185528580860191016110bd565b601f01601f1916010190565b602081519101519060208110611117575090565b5f199060200360031b1b1690565b611190916001600160a01b03825116815264ffffffffff60208301511660208201526001600160a01b03604083015116604082015260a0611175606084015160c0606085015260c08401906110de565b926080810151608084015201519060a08184039101526110de565b90565b90602080835192838152019201905f5b8181106111b05750505090565b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152604090940193909201916001016111a3565b6001600160a01b0316805f52600260205260ff60405f2054165f14611214575f526002602052600160405f20015490565b506001549056fe61014080604052346103d457611118803803809161001d82856103d8565b83398101906040818303126103d45780516001600160401b0381116103d45781019060c0828403126103d4576040519160c083016001600160401b038111848210176103a95760405280516001600160a01b03811681036103d4578352602081015164ffffffffff811681036103d457602084019081526040820151936001600160a01b03851685036103d4576040810194855260608301516001600160401b0381116103d457866100d091850161041c565b92606082019384526080810151966080830197885260a082015160018060401b0381116103d457610101920161041c565b60a082018181526020959095015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a351602081116103bd5750516001600160a01b03166080525164ffffffffff1660a0523360c0525180519093906001600160401b0381116103a957600154600181811c9116801561039f575b602082101461038b57601f8111610328575b50602094601f82116001146102c5579481929394955f926102ba575b50508160011b915f199060031b1c1916176001555b5160e052516040516102146020828161020381830196878151938492016103fb565b81010301601f1981018352826103d8565b51905190602081106102a9575b506101005261012052604051610ca7908161047182396080518181816103f50152818161062a0152610811015260a051818181610181015281816107370152818161089f0152610b07015260c05181818161077e015261093d015260e05181818161028b01526105af015261010051816109fa01526101205181818161014101526104af0152f35b5f199060200360031b1b165f610221565b015190505f806101cc565b601f1982169560015f52805f20915f5b888110610310575083600195969798106102f8575b505050811b016001556101e1565b01515f1960f88460031b161c191690555f80806102ea565b919260206001819286850151815501940192016102d5565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610381575b601f0160051c01905b81811061037657506101b0565b5f8155600101610369565b9091508190610360565b634e487b7160e01b5f52602260045260245ffd5b90607f169061019e565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b5f80fd5b601f909101601f19168101906001600160401b038211908210176103a957604052565b5f5b83811061040c5750505f910152565b81810151838201526020016103fd565b81601f820112156103d45780516001600160401b0381116103a9576040519261044f601f8301601f1916602001856103d8565b818452602082840101116103d45761046d91602080850191016103fb565b9056fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146109e457508063164e68de1461090e5780631686c909146107a25780632dd310001461075f5780633f31ae3f146104195780634800d97f146103d657806349fc73dd146102d25780634e390d3e146102ae57806351e75e8b1461027457806375829def146101bf57806390e64d13146101a5578063bb4b573414610164578063bba72cd31461012a578063ce516507146100ea5763f851a440146100c1575f80fd5b346100e6575f3660031901126100e65760206001600160a01b035f5416604051908152f35b5f80fd5b346100e65760203660031901126100e657602061012060043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e6575f3660031901126100e6576020610120610aff565b346100e65760203660031901126100e6576101d8610a74565b5f546001600160a01b03811633810361024557506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e65760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100e6575f3660031901126100e657602064ffffffffff60035416604051908152f35b346100e6575f3660031901126100e6576040515f6001548060011c906001811680156103cc575b6020831081146103b8578285529081156103945750600114610336575b6103328361032681850382610a8a565b60405191829182610a2d565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b80821061037a57509091508101602001610326610316565b919260018160209254838588010152019101909291610362565b60ff191660208086019190915291151560051b840190910191506103269050610316565b634e487b7160e01b5f52602260045260245ffd5b91607f16916102f9565b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b60803660031901126100e657600435602435906001600160a01b038216918281036100e657604435926fffffffffffffffffffffffffffffffff84168094036100e6576064359367ffffffffffffffff85116100e657366023860112156100e657846004013567ffffffffffffffff81116100e6578060051b95602487820101903682116100e6576104a9610aff565b610708577f00000000000000000000000000000000000000000000000000000000000000008034106106d957506104f78760ff6001918060081c5f526002602052161b60405f205416151590565b6106ad57604051602081019088825286604082015285606082015260608152610521608082610a8a565b519020604051602081019182526020815261053d604082610a8a565b5190209261055160206040519a018a610a8a565b8852602401602088015b82821061069d57505050925f935b86518510156105ab5760208560051b88010151908181105f1461059a575f52602052600160405f205b940193610569565b905f52602052600160405f20610592565b85907f000000000000000000000000000000000000000000000000000000000000000003610675578261064e7f1dcd2362ae467d43bf31cbcac0526c0958b23eb063e011ab49a5179c839ed9a99460409460035464ffffffffff81161561065b575b508460081c5f526002602052855f20600160ff87161b81541790557f0000000000000000000000000000000000000000000000000000000000000000610b3c565b82519182526020820152a2005b64ffffffffff19164264ffffffffff16176003558861060d565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b813581526020918201910161055b565b867febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b346100e6575f3660031901126100e65760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100e65760403660031901126100e6576107bb610a74565b602435906fffffffffffffffffffffffffffffffff82168092036100e6576001600160a01b035f5416338103610245575064ffffffffff60035416801515806108d9575b806108ca575b610870575061083582827f0000000000000000000000000000000000000000000000000000000000000000610b3c565b7f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b03805f5416936040519586521693a3005b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506108d3610aff565b15610805565b5062093a80810164ffffffffff81116108fa5764ffffffffff1642116107ff565b634e487b7160e01b5f52601160045260245ffd5b346100e65760203660031901126100e6576004356001600160a01b0381168091036100e6576001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168033036109b5575047905f80808085855af1610977610ac0565b501561098857602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b346100e6575f3660031901126100e657610332907f0000000000000000000000000000000000000000000000000000000000000000602082015260208152610326604082610a8a565b9190916020815282518060208301525f5b818110610a5e575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610a3e565b600435906001600160a01b03821682036100e657565b90601f8019910116810190811067ffffffffffffffff821117610aac57604052565b634e487b7160e01b5f52604160045260245ffd5b3d15610afa573d9067ffffffffffffffff8211610aac5760405191610aef601f8201601f191660200184610a8a565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610b34575090565b905042101590565b5f610ba9926001600160a01b038293604051968260208901947fa9059cbb000000000000000000000000000000000000000000000000000000008652166024890152604488015260448752610b92606488610a8a565b1694519082865af1610ba2610ac0565b9083610c0e565b8051908115159182610bea575b5050610bbf5750565b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126100e657602001518015908115036100e6575f80610bb6565b90610c4b5750805115610c2357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610c91575b610c5c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610c5456fea164736f6c634300081a000a6101a0806040523461049a57611823803803809161001d82856105d8565b8339810190808203610100811261049a5781516001600160401b03811161049a5782019160c08385031261049a576040519160c083016001600160401b038111848210176105ad5760405283516001600160a01b038116810361049a578352610088602085016105fb565b6020840190815260408501519091906001600160a01b038116810361049a576040850190815260608601516001600160401b03811161049a57876100cd918801610649565b95606086019687526080810151976080870198895260a082015160018060401b03811161049a576100fe9201610649565b60a0860190815260208501516001600160a01b038116979092909188840361049a5761012c6040880161068e565b92606061013a818a0161068e565b96607f19011261049a5760405196606088016001600160401b038111898210176105ad5760405261016d60808a016105fb565b885261017b60a08a016105fb565b99602089019a8b5260e061019160c08c016105fb565b60408b019081529a015194515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3835151602081116105c15750516001600160a01b03166080525164ffffffffff1660a0523360c052518051909a906001600160401b0381116105ad57600154600181811c911680156105a3575b602082101461058f57601f811161052c575b506020601f82116001146104ba57819064ffffffffff9a9b9c9d5f926104af575b50508160011b915f199060031b1c1916176001555b5160e052516040516102a7602082816102968183019687815193849201610628565b81010301601f1981018352826105d8565b519051906020811061049e575b50610100526101205261014052610160526101805251166effffffffff0000000000000000000069ffffffffff0000000000600454945160281b16925160501b169260018060781b03191617171760045560018060a01b0360805116604051905f806020840163095ea7b360e01b815285602486015281196044860152604485526103406064866105d8565b84519082855af161034f61069b565b81610463575b5080610459575b15610414575b604051611087908161079c823960805181818161049e015281816107830152610c65015260a0518181816101ad01528181610abc01528181610d650152610fb9015260c051818181610b030152610e03015260e051818181610334015261065601526101005181610ec001526101205181818161016d01526105560152610140518181816107b40152610b7a01526101605181818161024401526108dd0152610180518181816107de0152610b3e0152f35b61044c610451936040519063095ea7b360e01b602083015260248201525f6044820152604481526104466064826105d8565b826106ca565b6106ca565b5f8080610362565b50803b151561035c565b8051801592508215610478575b50505f610355565b819250906020918101031261049a576020610493910161068e565b5f80610470565b5f80fd5b5f199060200360031b1b165f6102b4565b015190505f8061025f565b601f1982169c60015f52815f209d5f5b81811061050f57509164ffffffffff9b9c9d9e918460019594106104f7575b505050811b01600155610274565b01515f1960f88460031b161c191690555f80806104e9565b919e8f60016020928684930151815501940192019e91929e6104ca565b60015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f830160051c81019160208410610585575b601f0160051c01905b81811061057a575061023e565b5f815560010161056d565b9091508190610564565b634e487b7160e01b5f52602260045260245ffd5b90607f169061022c565b634e487b7160e01b5f52604160045260245ffd5b6371935f2960e11b5f52600452602060245260445ffd5b601f909101601f19168101906001600160401b038211908210176105ad57604052565b519064ffffffffff8216820361049a57565b6001600160401b0381116105ad57601f01601f191660200190565b5f5b8381106106395750505f910152565b818101518382015260200161062a565b81601f8201121561049a57805161065f8161060d565b9261066d60405194856105d8565b8184526020828401011161049a5761068b9160208085019101610628565b90565b5190811515820361049a57565b3d156106c5573d906106ac8261060d565b916106ba60405193846105d8565b82523d5f602084013e565b606090565b5f806106f29260018060a01b03169360208151910182865af16106eb61069b565b908361073d565b805190811515918261071a575b50506107085750565b635274afe760e01b5f5260045260245ffd5b819250906020918101031261049a576020610735910161068e565b155f806106ff565b90610761575080511561075257805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610792575b610772575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b1561076a56fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde0314610eaa57508063164e68de14610dd45780631686c90914610b9f57806316c3549d14610b635780631bfd681414610b275780632dd3100014610ae45780633f31ae3f146104c25780634800d97f1461047f57806349fc73dd1461037b5780634e390d3e1461035757806351e75e8b1461031d57806375829def14610268578063845aef4b1461022557806390e64d131461020b578063b0604a26146101d1578063bb4b573414610190578063bba72cd314610156578063ce516507146101165763f851a440146100ed575f80fd5b34610112575f3660031901126101125760206001600160a01b035f5416604051908152f35b5f80fd5b3461011257602036600319011261011257602061014c60043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f36600319011261011257606060045464ffffffffff604051918181168352818160281c16602084015260501c166040820152f35b34610112575f36600319011261011257602061014c610fb1565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461011257602036600319011261011257610281610f3a565b5f546001600160a01b0381163381036102ee57506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f3660031901126101125760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610112575f36600319011261011257602064ffffffffff60035416604051908152f35b34610112575f366003190112610112576040515f6001548060011c90600181168015610475575b6020831081146104615782855290811561043d57506001146103df575b6103db836103cf81850382610f50565b60405191829182610ef3565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b808210610423575090915081016020016103cf6103bf565b91926001816020925483858801015201910190929161040b565b60ff191660208086019190915291151560051b840190910191506103cf90506103bf565b634e487b7160e01b5f52602260045260245ffd5b91607f16916103a2565b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261011257600435602435906001600160a01b038216809203610112576044356fffffffffffffffffffffffffffffffff8116809103610112576064359067ffffffffffffffff8211610112573660238301121561011257816004013567ffffffffffffffff8111610112578060051b926024848201019036821161011257610550610fb1565b610a8d577f0000000000000000000000000000000000000000000000000000000000000000803410610a5e575061059e8660ff6001918060081c5f526002602052161b60405f205416151590565b610a32576040516020810190878252886040820152856060820152606081526105c8608082610f50565b51902060405160208101918252602081526105e4604082610f50565b519020926105f86020604051970187610f50565b8552602401602085015b828210610a2257505050935f945b83518610156106525760208660051b85010151908181105f14610641575f52602052600160405f205b950194610610565b905f52602052600160405f20610639565b84907f0000000000000000000000000000000000000000000000000000000000000000036109fa5760035464ffffffffff8116156109e0575b508060081c5f52600260205260405f20600160ff83161b815417905560405192606084019380851067ffffffffffffffff8611176109b057604094855260208101905f82526004549064ffffffffff821680155f146109d9575064ffffffffff421681525b64ffffffffff8260281c16806109c4575b5064ffffffffff80808351169360501c1683011696879101526001600160a01b035f541695604051916040830183811067ffffffffffffffff8211176109b0576040525f83525f602084015260405197610120890189811067ffffffffffffffff8211176109b057604052885260208801938785526040890186815260608a017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316815260808b01917f00000000000000000000000000000000000000000000000000000000000000001515835260a08c01937f00000000000000000000000000000000000000000000000000000000000000001515855260c08d0195865260e08d019687526101008d019788525164ffffffffff1697604051809d7f9e7f5dbb000000000000000000000000000000000000000000000000000000008252516001600160a01b03169060040152516001600160a01b031660248d0152516fffffffffffffffffffffffffffffffff1660448c0152516001600160a01b031660648b015251151560848a015251151560a48901525164ffffffffff1660c48801525164ffffffffff1660e48701525180516001600160a01b03166101048701526020015161012486015261014485015283807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165a925f61016492602095f19384156109a5575f94610951575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d60201161099d575b8161096d60209383610f50565b810103126101125751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d61091e565b3d9150610960565b6040513d5f823e3d90fd5b634e487b7160e01b5f52604160045260245ffd5b64ffffffffff90818351160116835287610701565b81526106f0565b64ffffffffff19164264ffffffffff16176003558361068b565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b8135815260209182019101610602565b857febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610112575f3660031901126101125760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610112575f3660031901126101125760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461011257604036600319011261011257610bb8610f3a565b6024356fffffffffffffffffffffffffffffffff8116809103610112576001600160a01b035f54163381036102ee575064ffffffffff6003541680151580610d9f575b80610d90575b610d365750604051610c9b5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610c5b606486610f50565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610c94610f72565b9083610fee565b8051908115159182610d12575b5050610ce757507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101125760200151801590811503610112578480610ca8565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b50610d99610fb1565b15610c01565b5062093a80810164ffffffffff8111610dc05764ffffffffff164211610bfb565b634e487b7160e01b5f52601160045260245ffd5b34610112576020366003190112610112576004356001600160a01b038116809103610112576001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803303610e7b575047905f80808085855af1610e3d610f72565b5015610e4e57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610112575f366003190112610112576103db907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103cf604082610f50565b9190916020815282518060208301525f5b818110610f24575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201610f04565b600435906001600160a01b038216820361011257565b90601f8019910116810190811067ffffffffffffffff8211176109b057604052565b3d15610fac573d9067ffffffffffffffff82116109b05760405191610fa1601f8201601f191660200184610f50565b82523d5f602084013e565b606090565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610fe6575090565b905042101590565b9061102b575080511561100357805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611071575b61103c575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561103456fea164736f6c634300081a000a6101e080604052346104ba57611e7b803803809161001d828561071d565b833981019060e0818303126104ba5780516001600160401b0381116104ba5781019060c0828403126104ba576040519160c083016001600160401b038111848210176105745760405280516001600160a01b03811681036104ba57835261008660208201610740565b6020840190815260408201516001600160a01b03811681036104ba576040850190815260608301516001600160401b0381116104ba57866100c891850161078e565b6060860190815260808085015190870190815260a085015191949091906001600160401b0382116104ba576100ff9189910161078e565b60a087019081526020860151949091906001600160a01b03861686036104ba5761012b604088016107d3565b94610138606089016107d3565b9861014560808a01610740565b60a08a01519099906001600160401b0381116104ba5781018c601f820112156104ba578051906001600160401b038211610574576040519d8e8360051b60200161018f908261071d565b8381526020019260061b8201602001918183116104ba57602001925b8284106106c1575050505060c0015195515f80546001600160a01b0319166001600160a01b039290921691821781557fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf808180a3845151602081116106aa5750516001600160a01b03166080525164ffffffffff1660a0523360c052518051906001600160401b0382116105745760015490600182811c921680156106a0575b602083101461068c5781601f84931161061e575b50602090601f83116001146105b8575f926105ad575b50508160011b915f199060031b1c1916176001555b5160e052516040516102bc602082816102ab818301968781519384920161076d565b81010301601f19810183528261071d565b519051906020811061059c575b5061010052610120526101405261016052610180526101c0528051905f915f915b8183106104be57836101a05260018060a01b036080511660018060a01b03610160511690604051905f806020840163095ea7b360e01b8152856024860152811960448601526044855261033e60648661071d565b84519082855af161034d6107f4565b81610483575b5080610479575b15610434575b60405161158690816108f58239608051818181610578015281816109440152610f74015260a05181818161027d01528181610dd40152818161107401526112fc015260c051818181610e1b0152611112015260e05181818161040e015261072e015261010051816111cf01526101205181818161023d01526106270152610140518181816109740152610e9201526101605181818161031e0152610ac601526101805181818161018901526107bc01526101a0518181816102c1015261078a01526101c05181818161099e0152610e560152f35b61046c610471936040519063095ea7b360e01b602083015260248201525f60448201526044815261046660648261071d565b82610823565b610823565b808080610360565b50803b151561035a565b8051801592508215610498575b505084610353565b81925090602091810103126104ba5760206104b391016107d3565b8480610490565b5f80fd5b91929091906001600160401b036104d585846107e0565b5151166001600160401b039182160190811161058857926104f681836107e0565b519060045491680100000000000000008310156105745760018301806004558310156105605760019260045f5260205f200190838060401b038151166cffffffffff00000000000000006020845493015160401b1691858060681b031916171790550191906102ea565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f199060200360031b1b165f6102c9565b015190505f80610274565b60015f9081528281209350601f198516905b81811061060657509084600195949392106105ee575b505050811b01600155610289565b01515f1960f88460031b161c191690555f80806105e0565b929360206001819287860151815501950193016105ca565b60015f529091507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6601f840160051c81019160208510610682575b90601f859493920160051c01905b818110610674575061025e565b5f8155849350600101610667565b9091508190610659565b634e487b7160e01b5f52602260045260245ffd5b91607f169161024a565b6371935f2960e11b5f52600452602060245260445ffd5b6040848303126104ba5760408051919082016001600160401b03811183821017610574576040528451906001600160401b03821682036104ba57826020926040945261070e838801610740565b838201528152019301926101ab565b601f909101601f19168101906001600160401b0382119082101761057457604052565b519064ffffffffff821682036104ba57565b6001600160401b03811161057457601f01601f191660200190565b5f5b83811061077e5750505f910152565b818101518382015260200161076f565b81601f820112156104ba5780516107a481610752565b926107b2604051948561071d565b818452602082840101116104ba576107d0916020808501910161076d565b90565b519081151582036104ba57565b80518210156105605760209160051b010190565b3d1561081e573d9061080582610752565b91610813604051938461071d565b82523d5f602084013e565b606090565b5f8061084b9260018060a01b03169360208151910182865af16108446107f4565b9083610896565b8051908115159182610873575b50506108615750565b635274afe760e01b5f5260045260245ffd5b81925090602091810103126104ba57602061088e91016107d3565b155f80610858565b906108ba57508051156108ab57805190602001fd5b630a12f52160e11b5f5260045ffd5b815115806108eb575b6108cb575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156108c356fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146111b957508063164e68de146110e35780631686c90914610eb757806316c3549d14610e7b5780631bfd681414610e3f5780632dd3100014610dfc5780633f31ae3f1461059c5780634800d97f1461055957806349fc73dd146104555780634e390d3e1461043157806351e75e8b146103f757806375829def14610342578063845aef4b146102ff57806390e64d13146102e5578063936c63d9146102a1578063bb4b573414610260578063bba72cd314610226578063bf4ed03f146101ad578063ce36b3351461016c578063ce5165071461012c5763f851a44014610103575f80fd5b34610128575f3660031901126101285760206001600160a01b035f5416604051908152f35b5f80fd5b3461012857602036600319011261012857602061016260043560ff6001918060081c5f526002602052161b60405f205416151590565b6040519015158152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f366003190112610128576101c5611331565b6040518091602082016020835281518091526020604084019201905f5b8181106101f0575050500390f35b8251805167ffffffffffffffff16855260209081015164ffffffffff1681860152869550604090940193909201916001016101e2565b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f36600319011261012857602060405167ffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206101626112f4565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b346101285760203660031901126101285761035b611249565b5f546001600160a01b0381163381036103c857506001600160a01b037fffffffffffffffffffffffff0000000000000000000000000000000000000000921691829116175f55337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf805f80a3005b7fc6cce6a4000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f3660031901126101285760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610128575f36600319011261012857602064ffffffffff60035416604051908152f35b34610128575f366003190112610128576040515f6001548060011c9060018116801561054f575b60208310811461053b5782855290811561051757506001146104b9575b6104b5836104a98185038261127b565b60405191829182611202565b0390f35b91905060015f527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6915f905b8082106104fd575090915081016020016104a9610499565b9192600181602092548385880101520191019092916104e5565b60ff191660208086019190915291151560051b840190910191506104a99050610499565b634e487b7160e01b5f52602260045260245ffd5b91607f169161047c565b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b608036600319011261012857600435602435906001600160a01b03821680920361012857604435906001600160801b03821691828103610128576064359367ffffffffffffffff851161012857366023860112156101285784600401359467ffffffffffffffff86116101285760248660051b820101368111610128576106216112f4565b610da5577f0000000000000000000000000000000000000000000000000000000000000000803410610d76575061066f8560ff6001918060081c5f526002602052161b60405f205416151590565b610d4a5760405160208101908682528460408201528760608201526060815261069960808261127b565b51902060405160208101918252602081526106b560408261127b565b519020916106c2886112dc565b976106d0604051998a61127b565b8852602401602088015b828210610d3a57505050925f935b865185101561072a576106fb85886113e6565b519081811015610719575f52602052600160405f205b9401936106e8565b905f52602052600160405f20610711565b85907f000000000000000000000000000000000000000000000000000000000000000003610d125760035464ffffffffff811615610cf8575b508160081c5f52600260205260405f20600160ff84161b815417905567ffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016670de0b6b3a76400008103610ccd57507f000000000000000000000000000000000000000000000000000000000000000064ffffffffff8116610cc7575064ffffffffff4216935b6107fa611331565b90815191610807836112dc565b92610815604051948561127b565b808452601f19610824826112dc565b015f5b818110610ca457505061085661085167ffffffffffffffff610848856113c5565b5151168761143f565b6113fa565b64ffffffffff806020610868866113c5565b510151168a0116906001600160801b03604051916108858361125f565b16918282526020820152610898866113c5565b526108a2856113c5565b50916001905b828210610c105750506001600160801b038216858111610bfc578511610bd1575b50505064ffffffffff60206108e25f19845101846113e6565b510151166001600160a01b035f541690604051906108ff8261125f565b5f82525f602083015260405192610120840184811067ffffffffffffffff821117610bbd576040959493929552825260208201938785526040830198868a52606084017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152608085017f00000000000000000000000000000000000000000000000000000000000000001515815260a08601917f00000000000000000000000000000000000000000000000000000000000000001515835260c087019364ffffffffff16845260e0870194855261010087019586526040519c8d997f56b955e8000000000000000000000000000000000000000000000000000000008b526101648b0198516001600160a01b031660048c0152516001600160a01b031660248b0152516001600160801b031660448a0152516001600160a01b03166064890152511515608488015251151560a48701525164ffffffffff1660c48601525164ffffffffff1660e48501525180516001600160a01b031661010485015260200151610124840152610144830161016090528151809152610184830191602001905f5b818110610b8857505050908060209203815f6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af1938415610b7d575f94610b29575b507f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d9160409182519182526020820152a3005b9093506020813d602011610b75575b81610b456020938361127b565b810103126101285751927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d610af6565b3d9150610b38565b6040513d5f823e3d90fd5b825180516001600160801b0316855260209081015164ffffffffff168186015289955060409094019390920191600101610aaa565b634e487b7160e01b5f52604160045260245ffd5b6001600160801b0391610be883925f1901866113e6565b5193031681835116011690528580806108c9565b634e487b7160e01b5f52600160045260245ffd5b90926001600160801b03600191610c3f61085167ffffffffffffffff610c3689886113e6565b5151168b61143f565b9064ffffffffff806020610c565f198b018d6113e6565b51015116816020610c678b8a6113e6565b51015116011660405190610c7a8261125f565b84841682526020820152610c8e888b6113e6565b52610c99878a6113e6565b5001169301906108a8565b602090604051610cb38161125f565b5f81525f8382015282828901015201610827565b936107f2565b7f36d385ef000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b64ffffffffff19164264ffffffffff161760035584610763565b7fb4f06787000000000000000000000000000000000000000000000000000000005f5260045ffd5b81358152602091820191016106da565b847febe6f30d000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fa164c6b4000000000000000000000000000000000000000000000000000000005f523460045260245260445ffd5b7fdf4bae05000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445ffd5b34610128575f3660031901126101285760206040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b34610128575f3660031901126101285760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012857604036600319011261012857610ed0611249565b6024356001600160801b038116809103610128576001600160a01b035f54163381036103c8575064ffffffffff60035416801515806110ae575b8061109f575b6110455750604051610faa5f806001600160a01b0360208501967fa9059cbb000000000000000000000000000000000000000000000000000000008852169586602486015285604486015260448552610f6a60648661127b565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694519082865af1610fa361129d565b90836114ed565b8051908115159182611021575b5050610ff657507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f60206001600160a01b035f541692604051908152a3005b7f5274afe7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b81925090602091810103126101285760200151801590811503610128578480610fb7565b7fe2e40a0c000000000000000000000000000000000000000000000000000000005f524260045264ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660245260445260645ffd5b506110a86112f4565b15610f10565b5062093a80810164ffffffffff81116110cf5764ffffffffff164211610f0a565b634e487b7160e01b5f52601160045260245ffd5b34610128576020366003190112610128576004356001600160a01b038116809103610128576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001680330361118a575047905f80808085855af161114c61129d565b501561115d57602082604051908152f35b7e534073000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b7f4e3ddeed000000000000000000000000000000000000000000000000000000005f526004523360245260445ffd5b34610128575f366003190112610128576104b5907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526104a960408261127b565b9190916020815282518060208301525f5b818110611233575060409293505f838284010152601f8019910116010190565b8060208092870101516040828601015201611213565b600435906001600160a01b038216820361012857565b6040810190811067ffffffffffffffff821117610bbd57604052565b90601f8019910116810190811067ffffffffffffffff821117610bbd57604052565b3d156112d7573d9067ffffffffffffffff8211610bbd57604051916112cc601f8201601f19166020018461127b565b82523d5f602084013e565b606090565b67ffffffffffffffff8111610bbd5760051b60200190565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611329575090565b905042101590565b6004549061133e826112dc565b9161134c604051938461127b565b80835260045f9081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b602085015b8383106113885750505050565b60016020819260405161139a8161125f565b64ffffffffff865467ffffffffffffffff8116835260401c168382015281520192019201919061137b565b8051156113d25760200190565b634e487b7160e01b5f52603260045260245ffd5b80518210156113d25760209160051b010190565b6001600160801b038111611414576001600160801b031690565b7f4916adce000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b9091905f19838209838202918280831092039180830392146114dc57670de0b6b3a76400008210156114ac577faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac106699394670de0b6b3a7640000910990828211900360ee1b910360121c170290565b84907f5173648d000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b5050670de0b6b3a764000090049150565b9061152a575080511561150257805190602001fd5b7f1425ea42000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580611570575b61153b575090565b6001600160a01b03907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b1561153356fea164736f6c634300081a000aa164736f6c634300081a000a"; bytes public constant BYTECODE_NFT_DESCRIPTOR = - hex"60808060405234601557615f8d908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c0819052610300819052610320819052610340819052610360819052610380526103a08190526103c0526102e08190526100b6906100ad600435614824565b61030052614b1e565b610320526102e0516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c1a565b610260526102e0516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b5016610280526102e0516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614dbc565b610360526102e0516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d166154e9565b9701166154e9565b9801166154e9565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614ebc565b1690615022565b9061045a6001600160a01b036102405116614b1e565b906020610240015190602460206001600160a01b0360a0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360a0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610522945f91614589575b50169116615318565b610320516103a051939091906105ac600161054a6064610543818a06615994565b98046154e9565b602060405198826105648b945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810188520186614710565b61016061024001519561012061024001519760c061024001519560405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260e06101605101516108ec6109cb60046007602760586106e3610100610160510151610160515190615a95565b60b76106ee5f615d85565b985f6102205260206102205261071660405161070d6102205182614710565b5f8152846157b3565b1561456b57601b60909a5b61072a8c6154e9565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161077081846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d382518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109868251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ad82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108ec610a3960046007602760586040516109fe6102205182614710565b5f815260b7610a0d6001615d85565b98601b6028610a1b8c615e90565b610a2484615f08565b8082111561456457505b019a61072a8c6154e9565b61016083015261018082015260206101605101516108ec610a7a6004600760276058604051610a6b6102205182614710565b5f815260b7610a0d6002615d85565b8252602082015260286080610160510151604051610a9b6102205182614710565b5f81526108ec610ae56004600760276058610ab66003615d85565b9660b7610ac289615e90565b610acb8b615f08565b8082111561455c5750995b601b8c8c019a61072a8c6154e9565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7461010082015161016083015183519060a085015192614fb5565b60608201526101006101208190526040516101a0819052610b959190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf7610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d638183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119426118bd6073606b60405196610eec6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113516101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193d6014602261140a615a5a565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153f6025603589605e87519561022051890196611480818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e382518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165685602361154d615a5a565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d6818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161f82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117e060726023611665615a5a565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f4815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173882609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e8615a5a565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119068251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b614fb5565b60e052611956611950614d46565b856157b3565b938415614541575b5060c061010081905260405191906119769083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a538160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dce6102205182614710565b5f8152955b156141d957604051611de76101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b604051926120206107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ef9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0d926146ca565b016032018082518093610220510191612a25926146ca565b018082518093610220510191612a3a926146ca565b018082518093610220510191612a4f926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6f9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abf926146ca565b60805101815191826026830191610220510191612adb926146ca565b016026018082518093610220510191612af3926146ca565b0160a051519080826102205160a0510191612b0d926146ca565b0160e051519080826102205160e0510191612b27926146ca565b018082518093610220510191612b3c926146ca565b01610140515190808261022051610140510191612b58926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9a91614710565b6101605160a00151906101605160c00151916101605160400151906101605160600151612bc78583615cd9565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615cd9565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615d40565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615d40565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d906154e9565b916134a7906154e9565b906134b1906154e9565b936134bb906154e9565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b610380526102e0518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b610340819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516102e05182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b1e565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103005161026051610320516102405191939291613afc906001600160a01b0316614b1e565b613b076024356154e9565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61030051613e3e6024356154e9565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed690615648565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c081905261407690615648565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101205182015290612010565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd3565b61455591945061454f614d81565b906157b3565b925f61195e565b905099610ad6565b9050610a2e565b601b60d09a610721565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610519565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104ba565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614afa575b5060409161489483516148648582614710565b600e81527f5341422d4c4f434b55502d4c494e0000000000000000000000000000000000006020820152826157b3565b8015614ab5575b156148db5750506148ae81519182614710565b601581527f5361626c696572204c6f636b7570204c696e6561720000000000000000000000602082015290565b61491a83516148ea8582614710565b600e81527f5341422d4c4f434b55502d44594e0000000000000000000000000000000000006020820152826157b3565b8015614a70575b1561496157505061493481519182614710565b601681527f5361626c696572204c6f636b75702044796e616d696300000000000000000000602082015290565b6149a083516149708582614710565b600e81527f5341422d4c4f434b55502d5452410000000000000000000000000000000000006020820152826157b3565b8015614a2b575b156149e75750506149ba81519182614710565b601781527f5361626c696572204c6f636b7570205472616e63686564000000000000000000602082015290565b614a279083519384937f16ee429d0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614a6b8351614a3b8582614710565b601181527f5341422d56322d4c4f434b55502d5452410000000000000000000000000000006020820152826157b3565b6149a7565b50614ab08351614a808582614710565b601181527f5341422d56322d4c4f434b55502d44594e0000000000000000000000000000006020820152826157b3565b614921565b50614af58351614ac58582614710565b601181527f5341422d56322d4c4f434b55502d4c494e0000000000000000000000000000006020820152826157b3565b61489b565b614b179192503d805f833e614b0f8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614b37606084614710565b602a8352602083016040368237835115614c065760309053825160011015614c06576078602184015360295b60018111614ba45750614b74575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c06577f3031323334353637383961626364656600000000000000000000000000000000901a614bdf83866157e0565b5360041c908015614bf2575f1901614b63565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614c3e602482614710565b51915afa614c4a614793565b90158015614d3a575b614cfe5780602080614c6a935183010191016147c2565b601e8151115f14614cb15750604051614c84604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614cba816157f1565b15614cc25790565b50604051614cd1604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d0d604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614c53565b60405190614d55604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614d90604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614ea85760048103614dd65750614821614d81565b60038103614e1a5750604051614ded604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614e5e5750604051614e31604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614e6d57614821614d46565b604051614e7b604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614ef9602482614710565b51915afa614f05614793565b9080614f34575b15614f2f576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f0c565b60405190614f4e604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190614f89604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b90614fe09493615011602061502095615003828096816040519c8d8b83829d519485930191016146ca565b8901614ff4825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b9081156152f757806152e757505b806001811015615099575050615044614f7a565b614821600260206040518461506282965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615289576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516150d58482614710565b5f8152815260409182516150e98482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151228482614710565b600181527f4d000000000000000000000000000000000000000000000000000000000000008582015283830152825161515b8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516151958482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e882101561526f578451946151df8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b6007811061525c575050600160fd1b602786015250600884526152439061523d90615238602887614710565b6154e9565b91615994565b916005851015614c06576148219460051b015192614fb5565b818101830151878201840152820161520c565b9490915060016103e86064600a85040693049101946151c8565b50615292614f3f565b61482160086020604051846152b082965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e25704615030565b5050604051615307604082614710565b60018152600360fc1b602082015290565b6201518091030480615382575061532d614f7a565b614821600660206040518461534b82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154595760018103615415576148216153d76040516153a7604082614710565b600481527f20446179000000000000000000000000000000000000000000000000000000006020820152926154e9565b602060405193826153f186945180928580880191016146ca565b8301615405825180938580850191016146ca565b010103601f198101835282614710565b6148216153d7604051615429604082614710565b600581527f20446179730000000000000000000000000000000000000000000000000000006020820152926154e9565b50615462614f3f565b614821600a60206040518461548082965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b906154c182614777565b6154ce6040519182614710565b82815280926154df601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000821015615620575b806d04ee2d6d415b85acef8100000000600a921015615605575b662386f26fc100008110156155f1575b6305f5e1008110156155e0575b6127108110156155d1575b60648110156155c3575b10156155b8575b600a6021615573600185016154b7565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a83530480156155b357600a9091615578565b505090565b600190910190615563565b60646002910493019261555c565b61271060049104930192615552565b6305f5e10060089104930192615547565b662386f26fc100006010910493019261553a565b6d04ee2d6d415b85acef81000000006020910493019261552a565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f0100000000000000008104615510565b9081511561579d576040519161565f606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614bf257600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614bf2576156f59060021b6154b7565b90602082019080815182019560208701908151925f83525b88811061574f575050600393949596505251068060011461573d57600214615733575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761570d565b90506040516157ad602082614710565b5f815290565b90815181519081811493846157ca575b5050505090565b602092939450820120920120145f8080806157c3565b908151811015614c06570160200190565b8051905f5b82811061580557505050600190565b7fff0000000000000000000000000000000000000000000000000000000000000061583082846157e0565b5116600160fd1b811490600360fc1b8110158061596a575b7f4100000000000000000000000000000000000000000000000000000000000000821015908161593f575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615914575b84156158ea575b5083156158e2575b5082156158da575b5081156158d2575b50156158cb576001016157f6565b5050505f90565b90505f6158bd565b91505f6158b5565b92505f6158ad565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f6158a5565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061589e565b7f5a000000000000000000000000000000000000000000000000000000000000008311159150615873565b507f3900000000000000000000000000000000000000000000000000000000000000811115615848565b806159a857506040516157ad602082614710565b600a811015615a0e576159ba906154e9565b614821602260405180937f2e3000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b81010301601f198101835282614710565b615a17906154e9565b614821602160405180937f2e0000000000000000000000000000000000000000000000000000000000000060208301526159fd81518092602086860191016146ca565b60405190615a69604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615cc957615aa3615a5a565b9061271003906127108211614bf257602e6061916050615ac5614821956154e9565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615b52815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615bd982518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615c3a825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b50506040516157ad602082614710565b600d6150209193929360206040519582615cfc88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615d2f8251809385602d850191016146ca565b01010301601f198101845283614710565b60056150209193929360206040519582615d6388945180928580880191016146ca565b830164010714051160dd1b83820152615d2f82518093856025850191016146ca565b6004811015614ea85780615dcf5750604051615da2604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e135750604051615de6604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615e5557604051615e28604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615e63604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f90805180156158cb5790600d915f925f925b828410615eb65750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615eea88856157e0565b511614615f00575b820194600101929190615ea3565b859450615ef2565b5f90805180156158cb57906010915f925f925b828410615f2e575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f6288856157e0565b511614615f78575b820194600101929190615f1b565b859450615f6a56fea164736f6c634300081a000a"; + hex"6080806040523460155761600c908161001a8239f35b5f80fdfe6102406040526004361015610012575f80fd5b5f3560e01c63e9dc637514610025575f80fd5b346141bc5760403660031901126141bc576001600160a01b036004351680600435036141bc576103e06040525f61024081905260606102608190526102808290526102a08290526102c0819052610300819052610320819052610340819052610360819052610380526103a08190526103c0526102e08190526100b6906100ad600435614824565b61030052614b9d565b610320526102e0516040517feac8f5b80000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f91614681575b506001600160a01b0361012791168061024052614c99565b610260526102e0516040517fa80fc0710000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8576fffffffffffffffffffffffffffffffff915f91614662575b5016610280526102e0516040517fad35efd40000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa80156145b8575f90614625575b6101f59150614e3b565b610360526102e0516040517f4869e12d0000000000000000000000000000000000000000000000000000000081526024803560048301529091602091839182906001600160a01b03165afa9081156145b8575f916145f6575b50610280516fffffffffffffffffffffffffffffffff1680156145e2576fffffffffffffffffffffffffffffffff612710819302160416610160610240015260405160208101904682526bffffffffffffffffffffffff1960043560601b1660408201526024356054820152605481526102c9607482614710565b51902061040a60028061016861ffff8560101c160693600161031c63ffffffff601e61031482601461030c82604660ff6050818d60081c16069b16069d16615568565b970116615568565b980116615568565b60246040519788947f68736c2800000000000000000000000000000000000000000000000000000000602087015261035d815180926020868a0191016146ca565b85017f2c00000000000000000000000000000000000000000000000000000000000000838201526103988251809360206025850191016146ca565b01017f252c000000000000000000000000000000000000000000000000000000000000838201526103d38251809360206003850191016146ca565b01017f2529000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b6104446fffffffffffffffffffffffffffffffff604061024001511660ff61043d6001600160a01b036102405116614f3b565b16906150a1565b9061045a6001600160a01b036102405116614b9d565b906020610240015190602460206001600160a01b0360a0610240015116604051928380927fbc2be1be000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b8576024915f916145c3575b5060206001600160a01b0360a0610240015116604051938480927f9067b677000000000000000000000000000000000000000000000000000000008252823560048301525afa80156145b85764ffffffffff8091610522945f91614589575b50169116615397565b610320516103a051939091906105ac600161054a6064610543818a06615a13565b9804615568565b602060405198826105648b945180928580880191016146ca565b8301610578825180938580850191016146ca565b01017f2500000000000000000000000000000000000000000000000000000000000000815203601e19810188520186614710565b61016061024001519561012061024001519760c061024001519560405161016052610140610160510161016051811067ffffffffffffffff821117614575576040526101605152602061016051015260406101605101526060610160510152608061016051015260a061016051015260c061016051015260e06101605101526101006101605101526101206101605101526040516101c0810181811067ffffffffffffffff82111761457557604052606081525f60208201525f60408201526060808201525f6080820152606060a08201525f60c08201525f60e082015260606101008201525f6101208201525f61014082015260606101608201525f6101808201525f6101a082015260e06101605101516108ec6109cb60046007602760586106e3610100610160510151610160515190615b14565b60b76106ee5f615e04565b985f6102205260206102205261071660405161070d6102205182614710565b5f815284615832565b1561456b57601b60909a5b61072a8c615568565b906040519b8c9889937f3c672069643d220000000000000000000000000000000000000000000000000061022051860152835161077081846102205188019801886146ca565b8b017f222066696c6c3d2223666666223e000000000000000000000000000000000000838201527f3c726563742077696474683d220000000000000000000000000000000000000060358201526107d382518093604284019061022051016146ca565b0101917f22206865696768743d22313030222066696c6c2d6f7061636974793d222e3033858401527f222072783d223135222072793d22313522207374726f6b653d22236666662220603b8401527f7374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647468605b8401527f3d2234222f3e0000000000000000000000000000000000000000000000000000607b8401527f3c7465787420783d2232302220793d2233342220666f6e742d66616d696c793d60818401527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060a18401527f666f6e742d73697a653d2232327078223e00000000000000000000000000000060c184015251809360d28401906146ca565b0101661e17ba32bc3a1f60c91b838201527f3c7465787420783d2232302220793d2237322220666f6e742d66616d696c793d60be8201527f2227436f7572696572204e6577272c417269616c2c6d6f6e6f7370616365222060de8201527f666f6e742d73697a653d2232367078223e00000000000000000000000000000060fe8201526109868251809361010f84019061022051016146ca565b0101661e17ba32bc3a1f60c91b838201526109ad82518093605f84019061022051016146ca565b0101631e17b39f60e11b838201520301601b19810184520182614710565b6101008301526101208201526101206101605101516108ec610a3960046007602760586040516109fe6102205182614710565b5f815260b7610a0d6001615e04565b98601b6028610a1b8c615f0f565b610a2484615f87565b8082111561456457505b019a61072a8c615568565b61016083015261018082015260206101605101516108ec610a7a6004600760276058604051610a6b6102205182614710565b5f815260b7610a0d6002615e04565b8252602082015260286080610160510151604051610a9b6102205182614710565b5f81526108ec610ae56004600760276058610ab66003615e04565b9660b7610ac289615f0f565b610acb8b615f87565b8082111561455c5750995b601b8c8c019a61072a8c615568565b60a085015260c0840152602083015101016101208201510161018082015101603081016080830152602f19906103e8030160011c8061014083015261012082015101601081016101a083015261018082015101610220518101604083015260106102205191602084015101010160e0820152610b7461010082015161016083015183519060a085015192615034565b60608201526101006101208190526040516101a0819052610b959190614710565b60c76101a051527f3c726563742077696474683d223130302522206865696768743d223130302522610220516101a05101527f2066696c7465723d2275726c28234e6f69736529222f3e3c7265637420783d2260406101a05101527f37302220793d223730222077696474683d2238363022206865696768743d223860606101a05101527f3630222066696c6c3d2223666666222066696c6c2d6f7061636974793d222e3060806101a05101527f33222072783d223435222072793d22343522207374726f6b653d22236666662260a06101a05101527f207374726f6b652d6f7061636974793d222e3122207374726f6b652d7769647460c06101a05101527f683d2234222f3e0000000000000000000000000000000000000000000000000060e06101a05101526101605151610120610160510151906060830151610140525f610200526060610200526040516101e052610cf7610200516101e051614710565b60336101e051527f3c636972636c652069643d22476c6f772220723d22353030222066696c6c3d22610220516101e05101527f75726c282352616469616c476c6f7729222f3e0000000000000000000000000060406101e051015261014060405190610d638183614710565b61011c82527f3c66696c7465722069643d224e6f697365223e3c6665466c6f6f6420783d2230610220518301527f2220793d2230222077696474683d223130302522206865696768743d2231303060408301527f252220666c6f6f642d636f6c6f723d2268736c283233302c3231252c31312529610200518301527f2220666c6f6f642d6f7061636974793d22312220726573756c743d22666c6f6f60808301527f6446696c6c222f3e3c666554757262756c656e6365206261736546726571756560a08301527f6e63793d222e3422206e756d4f6374617665733d22332220726573756c743d2260c08301527f4e6f6973652220747970653d226672616374616c4e6f697365222f3e3c66654260e08301527f6c656e6420696e3d224e6f6973652220696e323d22666c6f6f6446696c6c2220610120518301527f6d6f64653d22736f66742d6c69676874222f3e3c2f66696c7465723e000000006101208301525f6101c0526103a06101c0526119426118bd6073606b60405196610eec6101c05189614710565b61037b88527f3c706174682069643d224c6f676f222066696c6c3d2223666666222066696c6c610220518901527f2d6f7061636974793d222e312220643d226d3133332e3535392c3132342e303360408901527f34632d2e3031332c322e3431322d312e3035392c342e3834382d322e3932332c610200518901527f362e3430322d322e3535382c312e3831392d352e3136382c332e3433392d372e60808901527f3838382c342e3939362d31342e34342c382e3236322d33312e3034372c31322e60a08901527f3536352d34372e3637342c31322e3536392d382e3835382e3033362d31372e3860c08901527f33382d312e3237322d32362e3332382d332e3636332d392e3830362d322e373660e08901527f362d31392e3038372d372e3131332d32372e3536322d31322e3737382d31332e610120518901527f3834322d382e3032352c392e3436382d32382e3630362c31362e3135332d33356101208901527f2e323635683063322e3033352d312e3833382c342e3235322d332e3534362c36868901527f2e3436332d352e323234683063362e3432392d352e3635352c31362e3231382d6101608901527f322e3833352c32302e3335382c342e31372c342e3134332c352e3035372c382e6101808901527f3831362c392e3634392c31332e39322c31332e373334682e30333763352e37336101a08901527f362c362e3436312c31352e3335372d322e3235332c392e33382d382e34382c306101c08901527f2c302d332e3531352d332e3531352d332e3531352d332e3531352d31312e34396101e08901527f2d31312e3437382d35322e3635362d35322e3636342d36342e3833372d36342e6102008901527f3833376c2e3034392d2e303337632d312e3732352d312e3630362d322e3731396102208901527f2d332e3834372d322e3735312d362e3230346830632d2e3034362d322e3337356102408901527f2c312e3036322d342e3538322c322e3732362d362e32323968306c2e3138352d6102608901527f2e3134386830632e3039392d2e3036322c2e3232322d2e3134382c2e33372d2e6102808901527f323539683063322e30362d312e3336322c332e3935312d322e3632312c362e306102a08901527f34342d332e3834324335372e3736332d332e3437332c39372e37362d322e33346102c08901527f312c3132382e3633372c31382e3333326331362e3637312c392e3934362d32366102e08901527f2e3334342c35342e3831332d33382e3635312c34302e3139392d362e3239392d6103008901527f362e3039362d31382e3036332d31372e3734332d31392e3636382d31382e38316103208901527f312d362e3031362d342e3034372d31332e3036312c342e3737362d372e3735326103408901527f2c392e3735316c36382e3235342c36382e33373163312e3732342c312e3630316103608901527f2c322e3731342c332e38342c322e3733382c362e3139325a222f3e00000000006103808901525f6101805260a06101805260405160a0526113516101805160a051614710565b607560a051527f3c706174682069643d22466c6f6174696e6754657874222066696c6c3d226e6f6102205160a05101527f6e652220643d224d313235203435683735307338302030203830203830763735604060a05101527f307330203830202d3830203830682d373530732d38302030202d3830202d38306102005160a05101527f762d3735307330202d3830203830202d3830222f3e0000000000000000000000608060a051015261193d6014602261140a615ad9565b9360a2604051957f3c72616469616c4772616469656e742069643d2252616469616c476c6f77223e610220518801527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604088015261153f6025603589605e87519561022051890196611480818486018a6146ca565b83017f222073746f702d6f7061636974793d222e36222f3e0000000000000000000000838201528f7f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22908201526114e382518093609384019061022051016146ca565b01017f222073746f702d6f7061636974793d2230222f3e000000000000000000000000838201527f3c2f72616469616c4772616469656e743e00000000000000000000000000000060498201520301600581018a520188614710565b61165685602361154d615ad9565b6040519b8c917f3c6c696e6561724772616469656e742069643d2253616e64546f70222078313d610220518401527f223025222079313d223025223e0000000000000000000000000000000000000060408401527f3c73746f70206f66667365743d223025222073746f702d636f6c6f723d220000604d84015288516115d6818486018a6146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22606e82015261161f82518093608e84019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60268201520301600b1981018b520189614710565b6117e060726023611665615ad9565b6040519c8d917f3c6c696e6561724772616469656e742069643d2253616e64426f74746f6d2220610220518401527f78313d2231303025222079313d2231303025223e00000000000000000000000060408401527f3c73746f70206f66667365743d22313025222073746f702d636f6c6f723d220060548401526116f4815180928486019061022051016146ca565b82016211179f60e91b828201527f3c73746f70206f66667365743d2231303025222073746f702d636f6c6f723d22607682015288519061173882609683018a6146ca565b01016211179f60e91b838201527f3c616e696d617465206174747269627574654e616d653d22783122206475723d60268201527f2236732220726570656174436f756e743d22696e646566696e6974652220766160468201527f6c7565733d223330253b3630253b313230253b3630253b3330253b222f3e00006066820152701e17b634b732b0b923b930b234b2b73a1f60791b60848201520301605281018c52018a614710565b6117e8615ad9565b906040519a8b947f3c6c696e6561724772616469656e742069643d22486f7572676c617373537472610220518701527f6f6b6522206772616469656e745472616e73666f726d3d22726f74617465283960408701527f302922206772616469656e74556e6974733d227573657253706163654f6e5573610200518701527f65223e000000000000000000000000000000000000000000000000000000000060808701527f3c73746f70206f66667365743d22353025222073746f702d636f6c6f723d22006083870152518092858701906146ca565b83016211179f60e91b838201527f3c73746f70206f66667365743d22383025222073746f702d636f6c6f723d220060a58201526119068251809360c484019061022051016146ca565b01016211179f60e91b83820152701e17b634b732b0b923b930b234b2b73a1f60791b60258201520301600b19810187520185614710565b615034565b60e052611956611950614dc5565b85615832565b938415614541575b5060c061010081905260405191906119769083614710565b609082527f3c7061746820643d224d2035302c3336302061203330302c333030203020312c610220518301527f31203630302c302061203330302c333030203020312c31202d3630302c30222060408301527f66696c6c3d2223666666222066696c6c2d6f7061636974793d222e3032222073610200518301527f74726f6b653d2275726c2823486f7572676c6173735374726f6b65292220737460808301527f726f6b652d77696474683d2234222f3e00000000000000000000000000000000610180518301526102c060405160c052611a538160c051614710565b61029860c051527f3c7061746820643d226d3536362c3136312e323031762d35332e39323463302d6102205160c05101527f31392e3338322d32322e3531332d33372e3536332d36332e3339382d35312e31604060c05101527f39382d34302e3735362d31332e3539322d39342e3934362d32312e3037392d316102005160c05101527f35322e3538372d32312e303739732d3131312e3833382c372e3438372d313532608060c05101527f2e3630322c32312e303739632d34302e3839332c31332e3633362d36332e34316101805160c05101527f332c33312e3831362d36332e3431332c35312e3139387635332e39323463302c6101005160c05101527f31372e3138312c31372e3730342c33332e3432372c35302e3232332c34362e3360e060c05101527f3934763238342e383039632d33322e3531392c31322e39362d35302e3232332c6101205160c05101527f32392e3230362d35302e3232332c34362e3339347635332e39323463302c313961012060c05101527f2e3338322c32322e35322c33372e3536332c36332e3431332c35312e3139382c8260c05101527f34302e3736332c31332e3539322c39342e3935342c32312e3037392c3135322e61016060c05101527f3630322c32312e303739733131312e3833312d372e3438372c3135322e35383761018060c05101527f2d32312e3037396334302e3838362d31332e3633362c36332e3339382d33312e6101a060c05101527f3831362c36332e3339382d35312e313938762d35332e39323463302d31372e316101c060c05101527f39362d31372e3730342d33332e3433352d35302e3232332d34362e34303156326101e060c05101527f30372e3630336333322e3531392d31322e3936372c35302e3232332d32392e3261020060c05101527f30362c35302e3232332d34362e3430315a6d2d3334372e3436322c35372e373961022060c05101527f336c3133302e3935392c3133312e3032372d3133302e3935392c3133312e303161024060c05101527f33563231382e3939345a6d3236322e3932342e303232763236322e3031386c2d61026060c05101527f3133302e3933372d3133312e3030362c3133302e3933372d3133312e3031335a61028060c05101527f222066696c6c3d2223313631383232223e3c2f706174683e00000000000000006102a060c0510152855f1461432c57604051611dce6102205182614710565b5f8152955b156141d957604051611de76101e082614710565b6101b181527f3c7061746820643d226d3438312e34362c3438312e35347638312e3031632d32610220518201527f2e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e332c60408201527f382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d3533610200518201527f2e362c302d3130312e32342d362e33332d3133312e34372d31362e3136762d3860808201527f316c34362e332d34362e3331683137302e33336c34362e32392c34362e33315a610180518201527f222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70617468610100518201527f20643d226d3433352e31372c3433352e323363302c312e31372d2e34362c322e60e08201527f33322d312e33332c332e34342d372e31312c392e30382d34312e39332c31352e610120518201527f39382d38332e38312c31352e3938732d37362e372d362e392d38332e38322d316101208201527f352e3938632d2e38372d312e31322d312e33332d322e32372d312e33332d332e838201527f3434762d2e30346c382e33342d382e33352e30312d2e30316331332e37322d366101608201527f2e35312c34322e39352d31312e30322c37362e382d31312e30327336322e39376101808201527f2c342e34392c37362e37322c31316c382e34322c382e34325a222066696c6c3d6101a08201527f2275726c282353616e64546f7029222f3e0000000000000000000000000000006101c0820152905b604051926120206107e085614710565b6107a7845261022080517f3c672066696c6c3d226e6f6e6522207374726f6b653d2275726c2823486f7572908601527f676c6173735374726f6b652922207374726f6b652d6c696e656361703d22726f60408087019190915261020080517f756e6422207374726f6b652d6d697465726c696d69743d22313022207374726f908801527f6b652d77696474683d2234223e3c7061746820643d226d3536352e3634312c31608088015261018080517f30372e323863302c392e3533372d352e35362c31382e3632392d31352e36373690890152610100517f2c32362e393733682d2e303233632d392e3230342c372e3539362d32322e3139908901527f342c31342e3536322d33382e3139372c32302e3539322d33392e3530342c313460e089015261012080517f2e3933362d39372e3332352c32342e3335352d3136312e3733332c32342e3335908a01527f352d39302e34382c302d3136372e3934382d31382e3538322d3139392e393533908901527f2d34342e393438682d2e303233632d31302e3131352d382e3334342d31352e36948801949094527f37362d31372e3433372d31352e3637362d32362e3937332c302d33392e3733356101608801527f2c39362e3535342d37312e3932312c3231352e3635322d37312e393231733231938701939093527f352e3632392c33322e3138352c3231352e3632392c37312e3932315a222f3e3c6101a08701527f7061746820643d226d3133342e33362c3136312e32303363302c33392e3733356101c0808801919091527f2c39362e3535342c37312e3932312c3231352e3635322c37312e3932317332316101e08801527f352e3632392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c938701939093527f696e652078313d223133342e3336222079313d223136312e323033222078323d828701527f223133342e3336222079323d223130372e3238222f3e3c6c696e652078313d226102408701527f3536352e3634222079313d223136312e323033222078323d223536352e3634226102608701527f2079323d223130372e3238222f3e3c6c696e652078313d223138342e353834226102808701527f2079313d223230362e383233222078323d223138342e353835222079323d22356102a08701527f33372e353739222f3e3c6c696e652078313d223231382e313831222079313d22938601939093527f3231382e313138222078323d223231382e313831222079323d223536322e35336102e08601527f37222f3e3c6c696e652078313d223438312e383138222079313d223231382e316103008601527f3432222078323d223438312e383139222079323d223536322e343238222f3e3c6103208601527f6c696e652078313d223531352e343135222079313d223230372e3335322220786103408601527f323d223531352e343136222079323d223533372e353739222f3e3c70617468206103608601527f643d226d3138342e35382c3533372e353863302c352e34352c342e32372c313061038086015290517f2e36352c31322e30332c31352e3432682e303263352e35312c332e33392c3132908501527f2e37392c362e35352c32312e35352c392e34322c33302e32312c392e392c37386103c08501527f2e30322c31362e32382c3133312e38332c31362e32382c34392e34312c302c396103e08501527f332e37362d352e33382c3132342e30362d31332e39322c322e372d2e37362c356104008501527f2e32392d312e35342c372e37352d322e33352c382e37372d322e38372c31362e6104208501527f30352d362e30342c32312e35362d392e3433683063372e37362d342e37372c316104408501527f322e30342d392e39372c31322e30342d31352e3432222f3e3c7061746820643d6104608501527f226d3138342e3538322c3439322e363536632d33312e3335342c31322e3438356104808501527f2d35302e3232332c32382e35382d35302e3232332c34362e3134322c302c392e6104a08501527f3533362c352e3536342c31382e3632372c31352e3637372c32362e393639682e6104c08501527f30323263382e3530332c372e3030352c32302e3231332c31332e3436332c33346104e08501527f2e3532342c31392e3135392c392e3939392c332e3939312c32312e3236392c376105008501527f2e3630392c33332e3539372c31302e3738382c33362e34352c392e3430372c386105208501527f322e3138312c31352e3030322c3133312e3833352c31352e3030327339352e336105408501527f36332d352e3539352c3133312e3830372d31352e3030326331302e3834372d326105608501527f2e37392c32302e3836372d352e3932362c32392e3932342d392e3334392c312e6105808501527f3234342d2e3436372c322e3437332d2e3934322c332e3637332d312e3432342c6105a08501527f31342e3332362d352e3639362c32362e3033352d31322e3136312c33342e35326105c08501527f342d31392e313733682e3032326331302e3131342d382e3334322c31352e36376105e08501527f372d31372e3433332c31352e3637372d32362e3936392c302d31372e3536322d6106008501527f31382e3836392d33332e3636352d35302e3232332d34362e3135222f3e3c70616106208501527f746820643d226d3133342e33362c3539322e373263302c33392e3733352c39366106408501527f2e3535342c37312e3932312c3231352e3635322c37312e393231733231352e366106608501527f32392d33322e3138362c3231352e3632392d37312e393231222f3e3c6c696e656106808501527f2078313d223133342e3336222079313d223539322e3732222078323d223133346106a08501527f2e3336222079323d223533382e373937222f3e3c6c696e652078313d223536356106c08501527f2e3634222079313d223539322e3732222078323d223536352e3634222079323d6106e08501527f223533382e373937222f3e3c706f6c796c696e6520706f696e74733d223438316107008501527f2e383232203438312e393031203438312e373938203438312e383737203438316107208501527f2e373735203438312e383534203335302e303135203335302e303236203231386107408501527f2e313835203231382e313239222f3e3c706f6c796c696e6520706f696e74733d6107608501527f223231382e313835203438312e393031203231382e323331203438312e3835346107808501527f203335302e303135203335302e303236203438312e383232203231382e3135326107a08501527f222f3e3c2f673e000000000000000000000000000000000000000000000000006107c0850152905181517f3c672069643d22486f7572676c617373223e00000000000000000000000000009082015284519151909788959092916129ef9183916032890191016146ca565b840160c051519060328101826102205160c0510191612a0d926146ca565b016032018082518093610220510191612a25926146ca565b018082518093610220510191612a3a926146ca565b018082518093610220510191612a4f926146ca565b01631e17b39f60e11b815203601b1981018452600401612a6f9084614710565b60405160805261022051608051017f3c646566733e000000000000000000000000000000000000000000000000000090526101e0515160805160260181610220516101e0510191612abf926146ca565b60805101815191826026830191610220510191612adb926146ca565b016026018082518093610220510191612af3926146ca565b0160a051519080826102205160a0510191612b0d926146ca565b0160e051519080826102205160e0510191612b27926146ca565b018082518093610220510191612b3c926146ca565b01610140515190808261022051610140510191612b58926146ca565b017f3c2f646566733e000000000000000000000000000000000000000000000000008152608051900360181981016080515260070160805190612b9a91614710565b6101605160a00151906101605160c00151916101605160400151906101605160600151612bc78583615d58565b916040958651612bd78882614710565b600581526102205181017f2d31303025000000000000000000000000000000000000000000000000000000905287519485916102205183017f3c74657874506174682073746172744f66667365743d220000000000000000009052805190816037850191610220510191612c4a926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612d8e918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612dbf9085614710565b612dc891615d58565b928551612dd58782614710565b60028152610220518101947f3025000000000000000000000000000000000000000000000000000000000000865287519586926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501612e41926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092612f85918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018552600b01612fb69085614710565b612fc08282615dbf565b918651612fcd8882614710565b60048152610220518101937f2d35302500000000000000000000000000000000000000000000000000000000855288519485926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613039926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e000000000000000000610109820152815161022051909261317d918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018452600b016131ae9084614710565b6131b791615dbf565b9085516131c48782614710565b60038152610220518101927f3530250000000000000000000000000000000000000000000000000000000000845287519384926102205184017f3c74657874506174682073746172744f66667365743d22000000000000000000905251908160378501613230926146ca565b7f2220687265663d2223466c6f6174696e6754657874222066696c6c3d222366666037918401918201527f662220666f6e742d66616d696c793d2227436f7572696572204e6577272c417260578201527f69616c2c6d6f6e6f7370616365222066696c6c2d6f7061636974793d222e3822607782015271103337b73a16b9b4bd329e91191b383c111f60711b60978201527f3c616e696d6174652061646469746976653d2273756d2220617474726962757460a98201527f654e616d653d2273746172744f66667365742220626567696e3d22307322206460c98201527f75723d22353073222066726f6d3d2230252220726570656174436f756e743d2260e98201527f696e646566696e6974652220746f3d2231303025222f3e0000000000000000006101098201528151610220519092613374918491610120850191016146ca565b0160370160e981016a1e17ba32bc3a2830ba341f60a91b90520360e90160141981018352600b016133a59083614710565b85519384936102205185017f3c7465787420746578742d72656e646572696e673d226f7074696d697a65537090528785017f656564223e0000000000000000000000000000000000000000000000000000009052805190816045870191610220510191613411926146ca565b840181519182604583019161022051019161342b926146ca565b016045018082518093610220510191613443926146ca565b018082518093610220510191613458926146ca565b01661e17ba32bc3a1f60c91b8152036018198101825260070161347b9082614710565b610140820151916101a08101519060408101519060e001519361349d90615568565b916134a790615568565b906134b190615568565b936134bb90615568565b8551948592610220518401947f3c75736520687265663d2223476c6f77222066696c6c2d6f7061636974793d2286528885017f2e39222f3e0000000000000000000000000000000000000000000000000000009052604585017f3c75736520687265663d2223476c6f772220783d22313030302220793d2231309052606585017f3030222066696c6c2d6f7061636974793d222e39222f3e0000000000000000009052607c85017f3c75736520687265663d22234c6f676f2220783d223137302220793d223137309052609c85017f22207472616e73666f726d3d227363616c65282e3629222f3e3c757365206872905260bc85017f65663d2223486f7572676c6173732220783d223135302220793d223930222074905260dc85017f72616e73666f726d3d22726f746174652831302922207472616e73666f726d2d905260fc85017f6f726967696e3d2235303020353030222f3e0000000000000000000000000000905261010e85017f3c75736520687265663d222350726f67726573732220783d2200000000000000905280519081610127870191610220510191613662926146ca565b840161012781016a11103c9e911b9c9811179f60a91b905261013281017f3c75736520687265663d22235374617475732220783d220000000000000000009052815191826101498301916102205101916136bb926146ca565b0161012701602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d2223416d6f756e742220783d220000000000000000009052815191826044830191610220510191613714926146ca565b01602201602281016a11103c9e911b9c9811179f60a91b9052602d81017f3c75736520687265663d22234475726174696f6e2220783d2200000000000000905281519182604683019161022051019161376c926146ca565b01602201602481016a11103c9e911b9c9811179f60a91b90520360240160141981018452600b0161379d9084614710565b83519283926102205184017f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323090528584017f30302f737667222077696474683d223130303022206865696768743d2231303090526102005184017f30222076696577426f783d2230203020313030302031303030223e000000000090526101a05151607b850181610220516101a0510191613837926146ca565b84016080515190607b810182610220516080510191613855926146ca565b01607b01808251809361022051019161386d926146ca565b0191829151809361387d926146ca565b017f3c2f7376673e0000000000000000000000000000000000000000000000000000815203601919810182526006016138b69082614710565b610380526102e0518151610220517fb25645690000000000000000000000000000000000000000000000000000000090820190815260248035818401528252916001600160a01b03169061390b604482614710565b515a925f93928493fa61391c614793565b610340819052901580156103c0526141d15761022051818051810103126141bc5761022051015180151581036141bc575b15156102a052610260516102e05182517fb971302a00000000000000000000000000000000000000000000000000000000815260248035600483015261022051919283919082906001600160a01b03165afa9081156141c7575f9161417b575b50600360236139be613ad693614b9d565b938161012061024001518780519788947f5b7b2274726169745f74797065223a224173736574222c2276616c7565223a2261022051870152613a0b815180928589019061022051016146ca565b85017f227d2c7b2274726169745f74797065223a2253656e646572222c2276616c75658382015262111d1160e91b61020051820152613a5682518093606384019061022051016146ca565b01017f227d2c7b2274726169745f74797065223a22537461747573222c2276616c75658382015262111d1160e91b6043820152613a9f82518093604684019061022051016146ca565b01017f227d5d0000000000000000000000000000000000000000000000000000000000838201520301601c19810184520182614710565b6103005161026051610320516102405191939291613afc906001600160a01b0316614b9d565b613b07602435615568565b6102a051909190156140ef5761010051875190613b249082614710565b609b81527fe29aa0efb88f205741524e494e473a205472616e7366657272696e6720746865610220518201527f204e4654206d616b657320746865206e6577206f776e65722074686520726563888201527f697069656e74206f66207468652073747265616d2e205468652066756e647320610200518201527f617265206e6f74206175746f6d61746963616c6c792077697468647261776e2060808201527f666f72207468652070726576696f757320726563697069656e742e000000000061018051820152915b8751968794610220518601967f54686973204e465420726570726573656e74732061207061796d656e7420737488528a87017f7265616d20696e2061205361626c696572204c6f636b757020000000000000009052805190610220518101918060598a0190613c5c91856146ca565b7f20636f6e74726163742e20546865206f776e6572206f662074686973204e46546059918a01918201527f2063616e207769746864726177207468652073747265616d656420617373657460798201527f732c207768696368206172652064656e6f6d696e6174656420696e2000000000609982015284516102205186019691613cea8260b583018a6146ca565b01605901605c81017f2e5c6e5c6e2d2053747265616d2049443a200000000000000000000000000000905281519182606e830191610220510191613d2d926146ca565b01605c0190601282016302e3716960e51b905251918260168301613d50926146ca565b01601201600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613d80926146ca565b0160040190600a82016302e3716960e51b9052519182600e8301613da3926146ca565b01600a01600481016901020b2323932b9b99d160b51b905281519182600e830191610220510191613dd3926146ca565b01600401600a81017f5c6e5c6e00000000000000000000000000000000000000000000000000000000905281519182600e830191610220510191613e16926146ca565b01600a0103600401601f1981018452613e2f9084614710565b61030051613e3e602435615568565b855180916102205182019367029b0b13634b2b9160c51b8552805190816028850191610220510191613e6f926146ca565b8201602881017f2023000000000000000000000000000000000000000000000000000000000000905281519182602a830191610220510191613eb0926146ca565b0160280103600201601f1981018252613ec99082614710565b61038051613ed6906156c7565b9286519586956102205187017f7b2261747472696275746573223a000000000000000000000000000000000000905280519081602e890191610220510191613f1d926146ca565b860190602e82017f2c226465736372697074696f6e223a22000000000000000000000000000000009052519182603e8301613f57926146ca565b01602e0190601082017f222c2265787465726e616c5f75726c223a2268747470733a2f2f7361626c69659052603082017f722e636f6d222c226e616d65223a2200000000000000000000000000000000009052519182603f8301613fba926146ca565b01601001602f81017f222c22696d616765223a22646174613a696d6167652f7376672b786d6c3b62619052604f81017f736536342c0000000000000000000000000000000000000000000000000000009052815191826054830191610220510191614024926146ca565b01602f01602581017f227d000000000000000000000000000000000000000000000000000000000000905203602501601d19810182526002016140679082614710565b6102c0819052614076906156c7565b90805180926102205182017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000905280519081603d8401916102205101916140bc926146ca565b810103603d01601f19810183526140d39083614710565b5180916102205182526102205182016140eb916146eb565b0390f35b86516140fc608082614710565b605b81527fe29d95494e464f3a2054686973204e4654206973206e6f6e2d7472616e736665610220518201527f7261626c652e2049742063616e6e6f7420626520736f6c64206f72207472616e888201527f7366657272656420746f20616e6f74686572206163636f756e742e00000000006102005182015291613bed565b9050610220513d61022051116141c0575b6141968183614710565b816102205191810103126141bc57516001600160a01b03811681036141bc5760036139ad565b5f80fd5b503d61418c565b83513d5f823e3d90fd5b50600161394d565b6040516141e861012082614710565b60f881527f3c7061746820643d226d3438312e34362c3530342e3130317635382e34343963610220518201527f2d322e33352e37372d342e38322c312e35312d372e33392c322e32332d33302e60408201527f332c382e35342d37342e36352c31332e39322d3132342e30362c31332e39322d610200518201527f35332e362c302d3130312e32342d362e33332d3133312e34372d31362e31367660808201527f2d35382e343339683236322e39325a222066696c6c3d2275726c282353616e64610180518201527f426f74746f6d29222f3e3c656c6c697073652063783d22333530222063793d22610100518201527f3530342e313031222072783d223133312e343632222072793d2232382e31303860e08201527f222066696c6c3d2275726c282353616e64546f7029222f3e00000000000000006101205182015290612010565b60405161433b6101c082614710565b61019981527f3c706f6c79676f6e20706f696e74733d22333530203335302e30323620343135610220518201527f2e3033203238342e39373820323835203238342e39373820333530203335302e60408201527f303236222066696c6c3d2275726c282353616e64426f74746f6d29222f3e3c70610200518201527f61746820643d226d3431362e3334312c3238312e39373563302c2e3931342d2e60808201527f3335342c312e3830392d312e3033352c322e36382d352e3534322c372e303736610180518201527f2d33322e3636312c31322e34352d36352e32382c31322e34352d33322e363234610100518201527f2c302d35392e3733382d352e3337342d36352e32382d31322e34352d2e36383160e08201527f2d2e3837322d312e3033352d312e3736372d312e3033352d322e36382c302d2e610120518201527f3931342e3335342d312e3830382c312e3033352d322e3637362c352e3534322d6101208201527f372e3037362c33322e3635362d31322e34352c36352e32382d31322e34352c33838201527f322e3631392c302c35392e3733382c352e3337342c36352e32382c31322e34356101608201527f2e3638312e3836372c312e3033352c312e3736322c312e3033352c322e3637366101808201527f5a222066696c6c3d2275726c282353616e64546f7029222f3e000000000000006101a082015295611dd3565b61455591945061454f614e00565b90615832565b925f61195e565b905099610ad6565b9050610a2e565b601b60d09a610721565b634e487b7160e01b5f52604160045260245ffd5b6145ab915060203d6020116145b1575b6145a38183614710565b81019061475a565b5f610519565b503d614599565b6040513d5f823e3d90fd5b6145dc915060203d6020116145b1576145a38183614710565b5f6104ba565b634e487b7160e01b5f52601260045260245ffd5b614618915060203d60201161461e575b6146108183614710565b810190614732565b5f61024e565b503d614606565b506020813d60201161465a575b8161463f60209383614710565b810103126141bc575160058110156141bc576101f5906101eb565b3d9150614632565b61467b915060203d60201161461e576146108183614710565b5f610191565b90506020813d6020116146c2575b8161469c60209383614710565b810103126141bc57516001600160a01b03811681036141bc576001600160a01b0361010f565b3d915061468f565b5f5b8381106146db5750505f910152565b81810151838201526020016146cc565b90602091614704815180928185528580860191016146ca565b601f01601f1916010190565b90601f8019910116810190811067ffffffffffffffff82111761457557604052565b908160209103126141bc57516fffffffffffffffffffffffffffffffff811681036141bc5790565b908160209103126141bc575164ffffffffff811681036141bc5790565b67ffffffffffffffff811161457557601f01601f191660200190565b3d156147bd573d906147a482614777565b916147b26040519384614710565b82523d5f602084013e565b606090565b6020818303126141bc5780519067ffffffffffffffff82116141bc570181601f820112156141bc5780516147f581614777565b926148036040519485614710565b818452602082840101116141bc5761482191602080850191016146ca565b90565b6001600160a01b0316604051906395d89b4160e01b82525f82600481845afa9182156145b8575f92614b79575b5060409161489483516148648582614710565b600a81527f5341422d4c4f434b555000000000000000000000000000000000000000000000602082015282615832565b156148d45750506148a781519182614710565b600e81527f5361626c696572204c6f636b7570000000000000000000000000000000000000602082015290565b61491383516148e38582614710565b600e81527f5341422d4c4f434b55502d4c494e000000000000000000000000000000000000602082015282615832565b8015614b34575b1561495a57505061492d81519182614710565b601581527f5361626c696572204c6f636b7570204c696e6561720000000000000000000000602082015290565b61499983516149698582614710565b600e81527f5341422d4c4f434b55502d44594e000000000000000000000000000000000000602082015282615832565b8015614aef575b156149e05750506149b381519182614710565b601681527f5361626c696572204c6f636b75702044796e616d696300000000000000000000602082015290565b614a1f83516149ef8582614710565b600e81527f5341422d4c4f434b55502d545241000000000000000000000000000000000000602082015282615832565b8015614aaa575b15614a66575050614a3981519182614710565b601781527f5361626c696572204c6f636b7570205472616e63686564000000000000000000602082015290565b614aa69083519384937f16ee429d0000000000000000000000000000000000000000000000000000000085526004850152602484015260448301906146eb565b0390fd5b50614aea8351614aba8582614710565b601181527f5341422d56322d4c4f434b55502d545241000000000000000000000000000000602082015282615832565b614a26565b50614b2f8351614aff8582614710565b601181527f5341422d56322d4c4f434b55502d44594e000000000000000000000000000000602082015282615832565b6149a0565b50614b748351614b448582614710565b601181527f5341422d56322d4c4f434b55502d4c494e000000000000000000000000000000602082015282615832565b61491a565b614b969192503d805f833e614b8e8183614710565b8101906147c2565b905f614851565b6001600160a01b03168060405191614bb6606084614710565b602a8352602083016040368237835115614c855760309053825160011015614c85576078602184015360295b60018111614c235750614bf3575090565b7fe22e27eb000000000000000000000000000000000000000000000000000000005f52600452601460245260445ffd5b90600f81166010811015614c85577f3031323334353637383961626364656600000000000000000000000000000000901a614c5e838661585f565b5360041c908015614c71575f1901614be2565b634e487b7160e01b5f52601160045260245ffd5b634e487b7160e01b5f52603260045260245ffd5b5f809160405160208101906395d89b4160e01b825260048152614cbd602482614710565b51915afa614cc9614793565b90158015614db9575b614d7d5780602080614ce9935183010191016147c2565b601e8151115f14614d305750604051614d03604082614710565b600b81527f4c6f6e672053796d626f6c000000000000000000000000000000000000000000602082015290565b614d3981615870565b15614d415790565b50604051614d50604082614710565b601281527f556e737570706f727465642053796d626f6c0000000000000000000000000000602082015290565b50604051614d8c604082614710565b600581527f4552433230000000000000000000000000000000000000000000000000000000602082015290565b50604081511115614cd2565b60405190614dd4604083614710565b600782527f536574746c6564000000000000000000000000000000000000000000000000006020830152565b60405190614e0f604083614710565b600882527f4465706c657465640000000000000000000000000000000000000000000000006020830152565b6005811015614f275760048103614e555750614821614e00565b60038103614e995750604051614e6c604082614710565b600881527f43616e63656c6564000000000000000000000000000000000000000000000000602082015290565b60018103614edd5750604051614eb0604082614710565b600981527f53747265616d696e670000000000000000000000000000000000000000000000602082015290565b600203614eec57614821614dc5565b604051614efa604082614710565b600781527f50656e64696e6700000000000000000000000000000000000000000000000000602082015290565b634e487b7160e01b5f52602160045260245ffd5b5f809160405160208101907f313ce56700000000000000000000000000000000000000000000000000000000825260048152614f78602482614710565b51915afa614f84614793565b9080614fb3575b15614fae576020818051810103126141bc576020015160ff811681036141bc5790565b505f90565b506020815114614f8b565b60405190614fcd604083614710565b600482527f2667743b000000000000000000000000000000000000000000000000000000006020830152565b60405190615008604083614710565b600482527f266c743b000000000000000000000000000000000000000000000000000000006020830152565b9061505f9493615090602061509f95615082828096816040519c8d8b83829d519485930191016146ca565b8901615073825180938580850191016146ca565b010191828151948592016146ca565b0191828151948592016146ca565b0103601f198101845283614710565b565b908115615376578061536657505b8060018110156151185750506150c3614ff9565b61482160026020604051846150e182965180928580860191016146ca565b81017f2031000000000000000000000000000000000000000000000000000000000000838201520301601d19810184520182614710565b66038d7ea4c680001115615308576040519060a0820182811067ffffffffffffffff821117614575576040526020916040516151548482614710565b5f8152815260409182516151688482614710565b600181527f4b00000000000000000000000000000000000000000000000000000000000000858201528483015282516151a18482614710565b600181527f4d00000000000000000000000000000000000000000000000000000000000000858201528383015282516151da8482614710565b600181527f420000000000000000000000000000000000000000000000000000000000000085820152606083015282516152148482614710565b600181527f54000000000000000000000000000000000000000000000000000000000000008582015260808301525f905f945b6103e88210156152ee5784519461525e8187614710565b600786527f2623383830353b000000000000000000000000000000000000000000000000008287015251945f5b600781106152db575050600160fd1b602786015250600884526152c2906152bc906152b7602887614710565b615568565b91615a13565b916005851015614c85576148219460051b015192615034565b818101830151878201840152820161528b565b9490915060016103e86064600a8504069304910194615247565b50615311614fbe565b614821600860206040518461532f82965180928580860191016146ca565b81017f203939392e393954000000000000000000000000000000000000000000000000838201520301601719810184520182614710565b600a0a9081156145e257046150af565b5050604051615386604082614710565b60018152600360fc1b602082015290565b620151809103048061540157506153ac614ff9565b61482160066020604051846153ca82965180928580860191016146ca565b81017f2031204461790000000000000000000000000000000000000000000000000000838201520301601919810184520182614710565b61270f81116154d8576001810361549457614821615456604051615426604082614710565b600481527f2044617900000000000000000000000000000000000000000000000000000000602082015292615568565b6020604051938261547086945180928580880191016146ca565b8301615484825180938580850191016146ca565b010103601f198101835282614710565b6148216154566040516154a8604082614710565b600581527f2044617973000000000000000000000000000000000000000000000000000000602082015292615568565b506154e1614fbe565b614821600a6020604051846154ff82965180928580860191016146ca565b81017f2039393939204461797300000000000000000000000000000000000000000000838201520301601519810184520182614710565b9061554082614777565b61554d6040519182614710565b828152809261555e601f1991614777565b0190602036910137565b805f917a184f03e93ff9f4daa797ed6e38ed64bf6a1f01000000000000000082101561569f575b806d04ee2d6d415b85acef8100000000600a921015615684575b662386f26fc10000811015615670575b6305f5e10081101561565f575b612710811015615650575b6064811015615642575b1015615637575b600a60216155f260018501615536565b938401015b5f1901917f30313233343536373839616263646566000000000000000000000000000000008282061a835304801561563257600a90916155f7565b505090565b6001909101906155e2565b6064600291049301926155db565b612710600491049301926155d1565b6305f5e100600891049301926155c6565b662386f26fc10000601091049301926155b9565b6d04ee2d6d415b85acef8100000000602091049301926155a9565b50604091507a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000810461558f565b9081511561581c57604051916156de606084614710565b604083527f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208401527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040840152805160028101809111614c7157600390047f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81168103614c71576157749060021b615536565b90602082019080815182019560208701908151925f83525b8881106157ce57505060039394959650525106806001146157bc576002146157b2575090565b603d905f19015390565b50603d90815f19820153600119015390565b600360049199969901986001603f8b5182828260121c16870101518453828282600c1c16870101518385015382828260061c168701015160028501531684010151600382015301949761578c565b905060405161582c602082614710565b5f815290565b9081518151908181149384615849575b5050505090565b602092939450820120920120145f808080615842565b908151811015614c85570160200190565b8051905f5b82811061588457505050600190565b7fff000000000000000000000000000000000000000000000000000000000000006158af828461585f565b5116600160fd1b811490600360fc1b811015806159e9575b7f410000000000000000000000000000000000000000000000000000000000000082101590816159be575b7f61000000000000000000000000000000000000000000000000000000000000008310159283615993575b8415615969575b508315615961575b508215615959575b508115615951575b501561594a57600101615875565b5050505f90565b90505f61593c565b91505f615934565b92505f61592c565b7f2d000000000000000000000000000000000000000000000000000000000000001493505f615924565b7f7a00000000000000000000000000000000000000000000000000000000000000811115935061591d565b7f5a0000000000000000000000000000000000000000000000000000000000000083111591506158f2565b507f39000000000000000000000000000000000000000000000000000000000000008111156158c7565b80615a27575060405161582c602082614710565b600a811015615a8d57615a3990615568565b614821602260405180937f2e300000000000000000000000000000000000000000000000000000000000006020830152615a7c81518092602086860191016146ca565b81010301601f198101835282614710565b615a9690615568565b614821602160405180937f2e000000000000000000000000000000000000000000000000000000000000006020830152615a7c81518092602086860191016146ca565b60405190615ae8604083614710565b601082527f68736c283233302c3231252c31312529000000000000000000000000000000006020830152565b8015615d4857615b22615ad9565b9061271003906127108211614c7157602e6061916050615b4461482195615568565b60576040519788947f3c672066696c6c3d226e6f6e65223e000000000000000000000000000000000060208701527f3c636972636c652063783d22313636222063793d2235302220723d2232322220602f8701527f7374726f6b653d22000000000000000000000000000000000000000000000000604f870152615bd1815180926020868a0191016146ca565b85017f22207374726f6b652d77696474683d223130222f3e0000000000000000000000838201527f3c636972636c652063783d22313636222063793d2235302220706174684c656e606c8201527f6774683d2231303030302220723d22323222207374726f6b653d220000000000608c820152615c5882518093602060a7850191016146ca565b01017f22207374726f6b652d6461736861727261793d22313030303022207374726f6b838201527f652d646173686f66667365743d220000000000000000000000000000000000006070820152615cb9825180936020607e850191016146ca565b01017f22207374726f6b652d6c696e656361703d22726f756e6422207374726f6b652d838201527f77696474683d223522207472616e73666f726d3d22726f74617465282d393029604e8201527f22207472616e73666f726d2d6f726967696e3d22313636203530222f3e000000606e820152631e17b39f60e11b608b82015203016041810184520182614710565b505060405161582c602082614710565b600d61509f9193929360206040519582615d7b88945180928580880191016146ca565b830164010714051160dd1b8382015267029b0b13634b2b9160c51b6025820152615dae8251809385602d850191016146ca565b01010301601f198101845283614710565b600561509f9193929360206040519582615de288945180928580880191016146ca565b830164010714051160dd1b83820152615dae82518093856025850191016146ca565b6004811015614f275780615e4e5750604051615e21604082614710565b600881527f50726f6772657373000000000000000000000000000000000000000000000000602082015290565b60018103615e925750604051615e65604082614710565b600681527f5374617475730000000000000000000000000000000000000000000000000000602082015290565b600203615ed457604051615ea7604082614710565b600681527f416d6f756e740000000000000000000000000000000000000000000000000000602082015290565b604051615ee2604082614710565b600881527f4475726174696f6e000000000000000000000000000000000000000000000000602082015290565b5f908051801561594a5790600d915f925f925b828410615f355750505050600d02900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615f69888561585f565b511614615f7f575b820194600101929190615f22565b859450615f71565b5f908051801561594a57906010915f925f925b828410615fad575050505060041b900390565b90919294603b60f81b7fff00000000000000000000000000000000000000000000000000000000000000615fe1888561585f565b511614615ff7575b820194600101929190615f9a565b859450615fe956fea164736f6c634300081a000a"; uint256 public constant MAX_COUNT = 500; diff --git a/script/Base.s.sol b/script/Base.s.sol index 9e2a23be9..206ff9f85 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -85,37 +85,37 @@ contract BaseScript is Script { // forgefmt: disable-start // Arbitrum chain ID - maxCountMap[42161] = 1160; + maxCountMap[42161] = 1080; // Avalanche chain ID. - maxCountMap[43114] = 520; + maxCountMap[43114] = 490; // Base chain ID. - maxCountMap[8453] = 2170; + maxCountMap[8453] = 2020; // Blast chain ID. - maxCountMap[81457] = 1080; + maxCountMap[81457] = 1010; // BNB chain ID. - maxCountMap[56] = 4820; + maxCountMap[56] = 4430; // Ethereum chain ID. - maxCountMap[1] = 1080; + maxCountMap[1] = 1010; // Gnosis chain ID. - maxCountMap[100] = 600; + maxCountMap[100] = 560; // Optimism chain ID. - maxCountMap[10] = 1080; + maxCountMap[10] = 1010; // Polygon chain ID. - maxCountMap[137] = 1080; + maxCountMap[137] = 1010; // Scroll chain ID. - maxCountMap[534352] = 330; + maxCountMap[534352] = 310; // Sepolia chain ID. - maxCountMap[11155111] = 1080; + maxCountMap[11155111] = 1010; // forgefmt: disable-end } diff --git a/shell/update-counts.sh b/shell/update-counts.sh index 5a54701a1..395bd1ffa 100755 --- a/shell/update-counts.sh +++ b/shell/update-counts.sh @@ -43,7 +43,7 @@ update_counts() { } # Call the function with specific parameters for segments and tranches -update_counts "maxCountMap" "maxCountMap" +update_counts "Segments" "maxCountMap" # Reformat the code with Forge forge fmt $BASE_SCRIPT diff --git a/test/Base.t.sol b/test/Base.t.sol index 172a1902c..747e54f69 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -4,13 +4,9 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; -import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; -import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; -import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; +import { SablierLockup } from "src/core/SablierLockup.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleInstant } from "src/periphery/interfaces/ISablierMerkleInstant.sol"; @@ -45,9 +41,7 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi ISablierBatchLockup internal batchLockup; ERC20Mock internal dai; Defaults internal defaults; - ISablierLockupDynamic internal lockupDynamic; - ISablierLockupLinear internal lockupLinear; - ISablierLockupTranched internal lockupTranched; + ISablierLockup internal lockup; ISablierMerkleFactory internal merkleFactory; ISablierMerkleInstant internal merkleInstant; ISablierMerkleLL internal merkleLL; @@ -107,11 +101,9 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi // Set the variables in Modifiers contract. setVariables(defaults, users); - // Approve `users.operator` to operate over lockups on behalf of the `users.recipient`. + // Approve `users.operator` to operate over lockup on behalf of the `users.recipient`. resetPrank({ msgSender: users.recipient }); - lockupDynamic.setApprovalForAll(users.operator, true); - lockupLinear.setApprovalForAll(users.operator, true); - lockupTranched.setApprovalForAll(users.operator, true); + lockup.setApprovalForAll(users.operator, true); // Set sender as the default caller for the tests. resetPrank({ msgSender: users.sender }); @@ -135,14 +127,10 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi function approveProtocol(address from) internal { resetPrank({ msgSender: from }); dai.approve({ spender: address(batchLockup), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + dai.approve({ spender: address(lockup), value: MAX_UINT256 }); dai.approve({ spender: address(merkleFactory), value: MAX_UINT256 }); usdt.approve({ spender: address(batchLockup), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); - usdt.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + usdt.approve({ spender: address(lockup), value: MAX_UINT256 }); usdt.approve({ spender: address(merkleFactory), value: MAX_UINT256 }); } @@ -165,19 +153,14 @@ abstract contract Base_Test is Assertions, Calculations, DeployOptimized, Modifi if (!isBenchmarkProfile() && !isTestOptimizedProfile()) { batchLockup = new SablierBatchLockup(); nftDescriptor = new LockupNFTDescriptor(); - lockupDynamic = new SablierLockupDynamic(users.admin, nftDescriptor, defaults.MAX_SEGMENT_COUNT()); - lockupLinear = new SablierLockupLinear(users.admin, nftDescriptor); - lockupTranched = new SablierLockupTranched(users.admin, nftDescriptor, defaults.MAX_TRANCHE_COUNT()); + lockup = new SablierLockup(users.admin, nftDescriptor, defaults.MAX_COUNT()); merkleFactory = new SablierMerkleFactory(users.admin); } else { - (nftDescriptor, lockupDynamic, lockupLinear, lockupTranched, batchLockup, merkleFactory) = - deployOptimizedProtocol(users.admin, defaults.MAX_SEGMENT_COUNT(), defaults.MAX_TRANCHE_COUNT()); + (nftDescriptor, lockup, batchLockup, merkleFactory) = + deployOptimizedProtocol(users.admin, defaults.MAX_COUNT()); } - vm.label({ account: address(batchLockup), newLabel: "BatchLockup" }); - vm.label({ account: address(lockupDynamic), newLabel: "LockupDynamic" }); - vm.label({ account: address(lockupLinear), newLabel: "LockupLinear" }); - vm.label({ account: address(lockupTranched), newLabel: "LockupTranched" }); + vm.label({ account: address(lockup), newLabel: "Lockup" }); vm.label({ account: address(merkleFactory), newLabel: "MerkleFactory" }); vm.label({ account: address(nftDescriptor), newLabel: "NFTDescriptor" }); } diff --git a/test/core/fork/LockupDynamic.t.sol b/test/core/fork/LockupDynamic.t.sol index a63cf4397..c018f3d8e 100644 --- a/test/core/fork/LockupDynamic.t.sol +++ b/test/core/fork/LockupDynamic.t.sol @@ -5,11 +5,11 @@ import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Broker, Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; -abstract contract LockupDynamic_Fork_Test is Fork_Test { +abstract contract Lockup_Dynamic_Fork_Test is Fork_Test { /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -23,10 +23,9 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierLockupDynamic} to transfer the holder's assets. + // Approve {SablierLockup} to transfer the holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. - (bool success,) = - address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupDynamic), MAX_UINT256))); + (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256))); success; } @@ -47,21 +46,21 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { struct Vars { // Generic vars address actualNFTOwner; - uint256 actualLockupDynamicBalance; + uint256 actualLockupBalance; uint256 actualRecipientBalance; Lockup.Status actualStatus; uint256[] balances; address expectedNFTOwner; - uint256 expectedLockupDynamicBalance; + uint256 expectedLockupBalance; uint256 expectedRecipientBalance; Lockup.Status expectedStatus; - uint256 initialLockupDynamicBalance; + uint256 initialLockupBalance; uint256 initialRecipientBalance; bool isCancelable; bool isDepleted; bool isSettled; uint256 streamId; - LockupDynamic.Timestamps timestamps; + Lockup.Timestamps timestamps; // Create vars uint256 actualBrokerBalance; uint256 actualHolderBalance; @@ -108,8 +107,8 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { /// - Multiple values for the broker fee, including zero /// - Multiple values for the withdraw amount, including zero /// - The whole gamut of stream statuses - function testForkFuzz_LockupDynamic_CreateWithdrawCancel(Params memory params) external { - checkUsers(params.sender, params.recipient, params.broker.account, address(lockupDynamic)); + function testForkFuzz_CreateWithdrawCancel(Params memory params) external { + checkUsers(params.sender, params.recipient, params.broker.account, address(lockup)); vm.assume(params.segments.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); @@ -134,21 +133,22 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { // Load the pre-create asset balances. vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupDynamic), params.broker.account)); - vars.initialLockupDynamicBalance = vars.balances[0]; + getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account)); + vars.initialLockupBalance = vars.balances[0]; vars.initialBrokerBalance = vars.balances[1]; - vars.streamId = lockupDynamic.nextStreamId(); - vars.timestamps = LockupDynamic.Timestamps({ + vars.streamId = lockup.nextStreamId(); + vars.timestamps = Lockup.Timestamps({ start: params.startTime, + cliff: 0, end: params.segments[params.segments.length - 1].timestamp }); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); - vm.expectEmit({ emitter: address(lockupDynamic) }); - emit ISablierLockupDynamic.CreateLockupDynamicStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupDynamicStream({ streamId: vars.streamId, funder: FORK_ASSET_HOLDER, sender: params.sender, @@ -157,14 +157,14 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { asset: FORK_ASSET, cancelable: true, transferable: true, - segments: params.segments, timestamps: vars.timestamps, - broker: params.broker.account + broker: params.broker.account, + segments: params.segments }); // Create the stream. - lockupDynamic.createWithTimestamps( - LockupDynamic.CreateWithTimestamps({ + lockup.createWithTimestampsLD( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, @@ -172,34 +172,33 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { cancelable: true, transferable: true, startTime: params.startTime, - segments: params.segments, + endTime: vars.timestamps.end, broker: params.broker - }) + }), + 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 or the last segment timestamp can be in the past. - vars.isSettled = - lockupDynamic.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(vars.streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, FORK_ASSET, "asset"); - assertEq(actualStream.endTime, vars.timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.segments, params.segments, "segments"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.startTime, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount"); + 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"); + 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"); + assertEq(lockup.getSegments(vars.streamId), params.segments, "segments"); // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (params.startTime > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { @@ -210,30 +209,26 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupDynamic.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner"); // Load the post-create asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupDynamic), FORK_ASSET_HOLDER, params.broker.account) + address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account) ); - vars.actualLockupDynamicBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualHolderBalance = vars.balances[1]; vars.actualBrokerBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupDynamicBalance = vars.initialLockupDynamicBalance + vars.createAmounts.deposit; - assertEq( - vars.actualLockupDynamicBalance, - vars.expectedLockupDynamicBalance, - "post-create LockupDynamic contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance + vars.createAmounts.deposit; + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-create Lockup contract balance"); // Assert that the holder's balance has been updated. vars.expectedHolderBalance = initialHolderBalance - vars.totalAmount; @@ -253,37 +248,37 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. - vars.withdrawableAmount = lockupDynamic.withdrawableAmountOf(vars.streamId); + vars.withdrawableAmount = lockup.withdrawableAmountOf(vars.streamId); params.withdrawAmount = boundUint128(params.withdrawAmount, 0, vars.withdrawableAmount); // Check if the stream has settled or will get depleted. It is possible for the stream to be just settled // and not depleted because the withdraw amount is fuzzed. vars.isDepleted = params.withdrawAmount == vars.createAmounts.deposit; - vars.isSettled = lockupDynamic.refundableAmountOf(vars.streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0; // Only run the withdraw tests if the withdraw amount is not zero. if (params.withdrawAmount > 0) { // Load the pre-withdraw asset balances. - vars.initialLockupDynamicBalance = vars.actualLockupDynamicBalance; + vars.initialLockupBalance = vars.actualLockupBalance; vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupDynamic) }); - emit ISablierLockup.WithdrawFromLockupStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.recipient, asset: FORK_ASSET, amount: params.withdrawAmount }); - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Make the withdrawal. resetPrank({ msgSender: params.recipient }); - lockupDynamic.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); + lockup.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (vars.isDepleted) { vars.expectedStatus = Lockup.Status.DEPLETED; } else if (vars.isSettled) { @@ -294,23 +289,18 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-withdraw stream status"); // Assert that the withdrawn amount has been updated. - vars.actualWithdrawnAmount = lockupDynamic.getWithdrawnAmount(vars.streamId); + vars.actualWithdrawnAmount = lockup.getWithdrawnAmount(vars.streamId); vars.expectedWithdrawnAmount = params.withdrawAmount; assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount"); // Load the post-withdraw asset balances. - vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupDynamic), params.recipient)); - vars.actualLockupDynamicBalance = vars.balances[0]; + vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient)); + vars.actualLockupBalance = vars.balances[0]; vars.actualRecipientBalance = vars.balances[1]; // Assert that the contract's balance has been updated. - vars.expectedLockupDynamicBalance = vars.initialLockupDynamicBalance - uint256(params.withdrawAmount); - assertEq( - vars.actualLockupDynamicBalance, - vars.expectedLockupDynamicBalance, - "post-withdraw lockupDynamic contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(params.withdrawAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-withdraw lockup contract balance"); // Assert that the Recipient's balance has been updated. vars.expectedRecipientBalance = vars.initialRecipientBalance + uint256(params.withdrawAmount); @@ -325,46 +315,42 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { if (!vars.isDepleted && !vars.isSettled) { // Load the pre-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupDynamic), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.initialLockupDynamicBalance = vars.balances[0]; + vars.initialLockupBalance = vars.balances[0]; vars.initialSenderBalance = vars.balances[1]; vars.initialRecipientBalance = vars.balances[2]; // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupDynamic) }); - vars.senderAmount = lockupDynamic.refundableAmountOf(vars.streamId); - vars.recipientAmount = lockupDynamic.withdrawableAmountOf(vars.streamId); - emit ISablierLockup.CancelLockupStream( + vm.expectEmit({ emitter: address(lockup) }); + vars.senderAmount = lockup.refundableAmountOf(vars.streamId); + vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId); + emit ISablierLockupBase.CancelLockupStream( vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount ); - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Cancel the stream. resetPrank({ msgSender: params.sender }); - lockupDynamic.cancel(vars.streamId); + lockup.cancel(vars.streamId); // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED; assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status"); // Load the post-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupDynamic), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.actualLockupDynamicBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualSenderBalance = vars.balances[1]; vars.actualRecipientBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupDynamicBalance = vars.initialLockupDynamicBalance - uint256(vars.senderAmount); - assertEq( - vars.actualLockupDynamicBalance, - vars.expectedLockupDynamicBalance, - "post-cancel lockupDynamic contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(vars.senderAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-cancel lockup contract balance"); // Assert that the Sender's balance has been updated. vars.expectedSenderBalance = vars.initialSenderBalance + uint256(vars.senderAmount); @@ -376,7 +362,7 @@ abstract contract LockupDynamic_Fork_Test is Fork_Test { } // Assert that the not burned NFT. - vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-cancel NFT owner"); } diff --git a/test/core/fork/LockupLinear.t.sol b/test/core/fork/LockupLinear.t.sol index 95fc53523..016ab2972 100644 --- a/test/core/fork/LockupLinear.t.sol +++ b/test/core/fork/LockupLinear.t.sol @@ -6,11 +6,11 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ud } from "@prb/math/src/UD60x18.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; +import { Broker, Lockup } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; -abstract contract LockupLinear_Fork_Test is Fork_Test { +abstract contract Lockup_Linear_Fork_Test is Fork_Test { /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -24,9 +24,9 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierLockupLinear} to transfer the asset holder's assets. + // Approve {SablierLockup} to transfer the asset holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. - (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupLinear), MAX_UINT256))); + (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256))); success; } @@ -40,13 +40,13 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { uint128 totalAmount; uint128 withdrawAmount; uint40 warpTimestamp; - LockupLinear.Timestamps timestamps; + Lockup.Timestamps timestamps; Broker broker; } struct Vars { // Generic vars - uint256 actualLockupLinearBalance; + uint256 actualLockupBalance; uint256 actualHolderBalance; address actualNFTOwner; uint256 actualRecipientBalance; @@ -54,13 +54,13 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { uint256[] balances; uint40 blockTimestamp; uint40 endTimeLowerBound; - uint256 expectedLockupLinearBalance; + uint256 expectedLockupBalance; uint256 expectedHolderBalance; address expectedNFTOwner; uint256 expectedRecipientBalance; Lockup.Status expectedStatus; bool hasCliff; - uint256 initialLockupLinearBalance; + uint256 initialLockupBalance; uint256 initialRecipientBalance; bool isCancelable; bool isDepleted; @@ -111,8 +111,8 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { /// - Cliff time zero and not zero /// - Multiple values for the broker fee, including zero /// - The whole gamut of stream statuses - function testForkFuzz_LockupLinear_CreateWithdrawCancel(Params memory params) external { - checkUsers(params.sender, params.recipient, params.broker.account, address(lockupLinear)); + function testForkFuzz_CreateWithdrawCancel(Params memory params) external { + checkUsers(params.sender, params.recipient, params.broker.account, address(lockup)); // Bound the parameters. Vars memory vars; @@ -144,21 +144,21 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { // Load the pre-create asset balances. vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupLinear), params.broker.account)); - vars.initialLockupLinearBalance = vars.balances[0]; + getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account)); + vars.initialLockupBalance = vars.balances[0]; vars.initialBrokerBalance = vars.balances[1]; // Calculate the broker fee amount and the deposit amount. vars.createAmounts.brokerFee = ud(params.totalAmount).mul(params.broker.fee).intoUint128(); vars.createAmounts.deposit = params.totalAmount - vars.createAmounts.brokerFee; - vars.streamId = lockupLinear.nextStreamId(); + vars.streamId = lockup.nextStreamId(); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupLinear) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockupLinear.CreateLockupLinearStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ streamId: vars.streamId, funder: FORK_ASSET_HOLDER, sender: params.sender, @@ -172,17 +172,19 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { }); // Create the stream. - lockupLinear.createWithTimestamps( - LockupLinear.CreateWithTimestamps({ + lockup.createWithTimestampsLL( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, asset: FORK_ASSET, cancelable: true, transferable: true, - timestamps: params.timestamps, + startTime: params.timestamps.start, + endTime: params.timestamps.end, broker: params.broker - }) + }), + params.timestamps.cliff ); // Check if the stream is settled. It is possible for a Lockup Linear stream to settle at the time of creation @@ -191,22 +193,21 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(vars.streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, FORK_ASSET, "asset"); - assertEq(actualStream.cliffTime, params.timestamps.cliff, "cliffTime"); - assertEq(actualStream.endTime, params.timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + 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.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"); + 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"); // Assert that the stream's status is correct. - vars.actualStatus = lockupLinear.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (params.timestamps.end <= vars.blockTimestamp) { vars.expectedStatus = Lockup.Status.SETTLED; } else if (params.timestamps.start > vars.blockTimestamp) { @@ -217,26 +218,26 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupLinear.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupLinear.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner"); // Load the post-create asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupLinear), FORK_ASSET_HOLDER, params.broker.account) + address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account) ); - vars.actualLockupLinearBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualHolderBalance = vars.balances[1]; vars.actualBrokerBalance = vars.balances[2]; - // Assert that the LockupLinear contract's balance has been updated. - vars.expectedLockupLinearBalance = vars.initialLockupLinearBalance + vars.createAmounts.deposit; - assertEq(vars.actualLockupLinearBalance, vars.expectedLockupLinearBalance, "post-create LockupLinear balance"); + // Assert that the Lockup contract's balance has been updated. + vars.expectedLockupBalance = vars.initialLockupBalance + vars.createAmounts.deposit; + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-create Lockup balance"); // Assert that the holder's balance has been updated. vars.expectedHolderBalance = initialHolderBalance - params.totalAmount; @@ -259,37 +260,37 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. - vars.withdrawableAmount = lockupLinear.withdrawableAmountOf(vars.streamId); + vars.withdrawableAmount = lockup.withdrawableAmountOf(vars.streamId); params.withdrawAmount = boundUint128(params.withdrawAmount, 0, vars.withdrawableAmount); // Check if the stream has settled or will get depleted. It is possible for the stream to be just settled // and not depleted because the withdraw amount is fuzzed. - vars.isSettled = lockupLinear.refundableAmountOf(vars.streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0; vars.isDepleted = params.withdrawAmount == vars.createAmounts.deposit; // Only run the withdraw tests if the withdraw amount is not zero. if (params.withdrawAmount > 0) { // Load the pre-withdraw asset balances. - vars.initialLockupLinearBalance = vars.actualLockupLinearBalance; + vars.initialLockupBalance = vars.actualLockupBalance; vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockup.WithdrawFromLockupStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.recipient, asset: FORK_ASSET, amount: params.withdrawAmount }); - vm.expectEmit({ emitter: address(lockupLinear) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Make the withdrawal. resetPrank({ msgSender: params.recipient }); - lockupLinear.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); + lockup.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); // Assert that the stream's status is correct. - vars.actualStatus = lockupLinear.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (vars.isDepleted) { vars.expectedStatus = Lockup.Status.DEPLETED; } else if (vars.isSettled) { @@ -300,21 +301,18 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-withdraw stream status"); // Assert that the withdrawn amount has been updated. - vars.actualWithdrawnAmount = lockupLinear.getWithdrawnAmount(vars.streamId); + vars.actualWithdrawnAmount = lockup.getWithdrawnAmount(vars.streamId); vars.expectedWithdrawnAmount = params.withdrawAmount; assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount"); // Load the post-withdraw asset balances. - vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupLinear), params.recipient)); - vars.actualLockupLinearBalance = vars.balances[0]; + vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient)); + vars.actualLockupBalance = vars.balances[0]; vars.actualRecipientBalance = vars.balances[1]; // Assert that the contract's balance has been updated. - vars.expectedLockupLinearBalance = vars.initialLockupLinearBalance - uint256(params.withdrawAmount); - assertEq( - vars.actualLockupLinearBalance, vars.expectedLockupLinearBalance, "post-withdraw LockupLinear balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(params.withdrawAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-withdraw Lockup balance"); // Assert that the Recipient's balance has been updated. vars.expectedRecipientBalance = vars.initialRecipientBalance + uint256(params.withdrawAmount); @@ -329,44 +327,42 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { if (!vars.isDepleted && !vars.isSettled) { // Load the pre-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupLinear), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.initialLockupLinearBalance = vars.balances[0]; + vars.initialLockupBalance = vars.balances[0]; vars.initialSenderBalance = vars.balances[1]; vars.initialRecipientBalance = vars.balances[2]; // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupLinear) }); - vars.senderAmount = lockupLinear.refundableAmountOf(vars.streamId); - vars.recipientAmount = lockupLinear.withdrawableAmountOf(vars.streamId); - emit ISablierLockup.CancelLockupStream( + vm.expectEmit({ emitter: address(lockup) }); + vars.senderAmount = lockup.refundableAmountOf(vars.streamId); + vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId); + emit ISablierLockupBase.CancelLockupStream( vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount ); - vm.expectEmit({ emitter: address(lockupLinear) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Cancel the stream. resetPrank({ msgSender: params.sender }); - lockupLinear.cancel(vars.streamId); + lockup.cancel(vars.streamId); // Assert that the stream's status is correct. - vars.actualStatus = lockupLinear.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED; assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status"); // Load the post-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupLinear), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.actualLockupLinearBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualSenderBalance = vars.balances[1]; vars.actualRecipientBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupLinearBalance = vars.initialLockupLinearBalance - uint256(vars.senderAmount); - assertEq( - vars.actualLockupLinearBalance, vars.expectedLockupLinearBalance, "post-cancel LockupLinear balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(vars.senderAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-cancel Lockup balance"); // Assert that the Sender's balance has been updated. vars.expectedSenderBalance = vars.initialSenderBalance + uint256(vars.senderAmount); @@ -378,7 +374,7 @@ abstract contract LockupLinear_Fork_Test is Fork_Test { } // Assert that the not burned NFT. - vars.actualNFTOwner = lockupLinear.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-cancel NFT owner"); } diff --git a/test/core/fork/LockupTranched.t.sol b/test/core/fork/LockupTranched.t.sol index 77303ba9d..3fc7f3100 100644 --- a/test/core/fork/LockupTranched.t.sol +++ b/test/core/fork/LockupTranched.t.sol @@ -5,11 +5,11 @@ import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Solarray } from "solarray/src/Solarray.sol"; import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { Fork_Test } from "./Fork.t.sol"; -abstract contract LockupTranched_Fork_Test is Fork_Test { +abstract contract Lockup_Tranched_Fork_Test is Fork_Test { /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -23,10 +23,9 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { function setUp() public virtual override { Fork_Test.setUp(); - // Approve {SablierLockupTranched} to transfer the holder's assets. + // Approve {SablierLockup} to transfer the holder's assets. // We use a low-level call to ignore reverts because the asset can have the missing return value bug. - (bool success,) = - address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockupTranched), MAX_UINT256))); + (bool success,) = address(FORK_ASSET).call(abi.encodeCall(IERC20.approve, (address(lockup), MAX_UINT256))); success; } @@ -47,21 +46,21 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { struct Vars { // Generic vars address actualNFTOwner; - uint256 actualLockupTranchedBalance; + uint256 actualLockupBalance; uint256 actualRecipientBalance; Lockup.Status actualStatus; uint256[] balances; address expectedNFTOwner; - uint256 expectedLockupTranchedBalance; + uint256 expectedLockupBalance; uint256 expectedRecipientBalance; Lockup.Status expectedStatus; - uint256 initialLockupTranchedBalance; + uint256 initialLockupBalance; uint256 initialRecipientBalance; bool isCancelable; bool isDepleted; bool isSettled; uint256 streamId; - LockupTranched.Timestamps timestamps; + Lockup.Timestamps timestamps; // Create vars uint256 actualBrokerBalance; uint256 actualHolderBalance; @@ -108,8 +107,8 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { /// - Multiple values for the broker fee, including zero. /// - Multiple values for the withdraw amount, including zero /// - The whole gamut of stream statuses - function testForkFuzz_LockupTranched_CreateWithdrawCancel(Params memory params) external { - checkUsers(params.sender, params.recipient, params.broker.account, address(lockupTranched)); + function testForkFuzz_CreateWithdrawCancel(Params memory params) external { + checkUsers(params.sender, params.recipient, params.broker.account, address(lockup)); vm.assume(params.tranches.length != 0); params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); params.startTime = boundUint40(params.startTime, 1, defaults.START_TIME()); @@ -134,21 +133,22 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { // Load the pre-create asset balances. vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupTranched), params.broker.account)); - vars.initialLockupTranchedBalance = vars.balances[0]; + getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.broker.account)); + vars.initialLockupBalance = vars.balances[0]; vars.initialBrokerBalance = vars.balances[1]; - vars.streamId = lockupTranched.nextStreamId(); - vars.timestamps = LockupTranched.Timestamps({ + vars.streamId = lockup.nextStreamId(); + vars.timestamps = Lockup.Timestamps({ start: params.startTime, + cliff: 0, end: params.tranches[params.tranches.length - 1].timestamp }); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); - vm.expectEmit({ emitter: address(lockupTranched) }); - emit ISablierLockupTranched.CreateLockupTranchedStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupTranchedStream({ streamId: vars.streamId, funder: FORK_ASSET_HOLDER, sender: params.sender, @@ -163,8 +163,8 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { }); // Create the stream. - lockupTranched.createWithTimestamps( - LockupTranched.CreateWithTimestamps({ + lockup.createWithTimestampsLT( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, @@ -172,34 +172,33 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { cancelable: true, transferable: true, startTime: params.startTime, - tranches: params.tranches, + endTime: vars.timestamps.end, broker: params.broker - }) + }), + 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 or the last tranche timestamp can be in the past - vars.isSettled = - lockupTranched.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0 || vars.timestamps.end <= getBlockTimestamp(); vars.isCancelable = vars.isSettled ? false : true; // Assert that the stream has been created. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(vars.streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, FORK_ASSET, "asset"); - assertEq(actualStream.endTime, vars.timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.tranches, params.tranches, "tranches"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.startTime, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + assertEq(lockup.getDepositedAmount(vars.streamId), vars.createAmounts.deposit, "depositedAmount"); + 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"); + 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"); + assertEq(lockup.getTranches(vars.streamId), params.tranches, "tranches"); // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (params.startTime > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { @@ -210,30 +209,26 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-create stream status"); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = vars.streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "post-create nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-create NFT owner"); // Load the post-create asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupTranched), FORK_ASSET_HOLDER, params.broker.account) + address(FORK_ASSET), Solarray.addresses(address(lockup), FORK_ASSET_HOLDER, params.broker.account) ); - vars.actualLockupTranchedBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualHolderBalance = vars.balances[1]; vars.actualBrokerBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance + vars.createAmounts.deposit; - assertEq( - vars.actualLockupTranchedBalance, - vars.expectedLockupTranchedBalance, - "post-create LockupTranched contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance + vars.createAmounts.deposit; + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-create Lockup contract balance"); // Assert that the holder's balance has been updated. vars.expectedHolderBalance = initialHolderBalance - vars.totalAmount; @@ -253,37 +248,37 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { vm.warp({ newTimestamp: params.warpTimestamp }); // Bound the withdraw amount. - vars.withdrawableAmount = lockupTranched.withdrawableAmountOf(vars.streamId); + vars.withdrawableAmount = lockup.withdrawableAmountOf(vars.streamId); params.withdrawAmount = boundUint128(params.withdrawAmount, 0, vars.withdrawableAmount); // Check if the stream has settled or will get depleted. It is possible for the stream to be just settled // and not depleted because the withdraw amount is fuzzed. vars.isDepleted = params.withdrawAmount == vars.createAmounts.deposit; - vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0; // Only run the withdraw tests if the withdraw amount is not zero. if (params.withdrawAmount > 0) { // Load the pre-withdraw asset balances. - vars.initialLockupTranchedBalance = vars.actualLockupTranchedBalance; + vars.initialLockupBalance = vars.actualLockupBalance; vars.initialRecipientBalance = FORK_ASSET.balanceOf(params.recipient); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupTranched) }); - emit ISablierLockup.WithdrawFromLockupStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.recipient, asset: FORK_ASSET, amount: params.withdrawAmount }); - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Make the withdrawal. resetPrank({ msgSender: params.recipient }); - lockupTranched.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); + lockup.withdraw({ streamId: vars.streamId, to: params.recipient, amount: params.withdrawAmount }); // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (vars.isDepleted) { vars.expectedStatus = Lockup.Status.DEPLETED; } else if (vars.isSettled) { @@ -294,23 +289,18 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { assertEq(vars.actualStatus, vars.expectedStatus, "post-withdraw stream status"); // Assert that the withdrawn amount has been updated. - vars.actualWithdrawnAmount = lockupTranched.getWithdrawnAmount(vars.streamId); + vars.actualWithdrawnAmount = lockup.getWithdrawnAmount(vars.streamId); vars.expectedWithdrawnAmount = params.withdrawAmount; assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "post-withdraw withdrawnAmount"); // Load the post-withdraw asset balances. - vars.balances = - getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockupTranched), params.recipient)); - vars.actualLockupTranchedBalance = vars.balances[0]; + vars.balances = getTokenBalances(address(FORK_ASSET), Solarray.addresses(address(lockup), params.recipient)); + vars.actualLockupBalance = vars.balances[0]; vars.actualRecipientBalance = vars.balances[1]; // Assert that the contract's balance has been updated. - vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance - uint256(params.withdrawAmount); - assertEq( - vars.actualLockupTranchedBalance, - vars.expectedLockupTranchedBalance, - "post-withdraw lockupTranched contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(params.withdrawAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-withdraw lockup contract balance"); // Assert that the Recipient's balance has been updated. vars.expectedRecipientBalance = vars.initialRecipientBalance + uint256(params.withdrawAmount); @@ -325,46 +315,42 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { if (!vars.isDepleted && !vars.isSettled) { // Load the pre-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupTranched), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.initialLockupTranchedBalance = vars.balances[0]; + vars.initialLockupBalance = vars.balances[0]; vars.initialSenderBalance = vars.balances[1]; vars.initialRecipientBalance = vars.balances[2]; // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupTranched) }); - vars.senderAmount = lockupTranched.refundableAmountOf(vars.streamId); - vars.recipientAmount = lockupTranched.withdrawableAmountOf(vars.streamId); - emit ISablierLockup.CancelLockupStream( + vm.expectEmit({ emitter: address(lockup) }); + vars.senderAmount = lockup.refundableAmountOf(vars.streamId); + vars.recipientAmount = lockup.withdrawableAmountOf(vars.streamId); + emit ISablierLockupBase.CancelLockupStream( vars.streamId, params.sender, params.recipient, FORK_ASSET, vars.senderAmount, vars.recipientAmount ); - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Cancel the stream. resetPrank({ msgSender: params.sender }); - lockupTranched.cancel(vars.streamId); + lockup.cancel(vars.streamId); // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); vars.expectedStatus = vars.recipientAmount > 0 ? Lockup.Status.CANCELED : Lockup.Status.DEPLETED; assertEq(vars.actualStatus, vars.expectedStatus, "post-cancel stream status"); // Load the post-cancel asset balances. vars.balances = getTokenBalances( - address(FORK_ASSET), Solarray.addresses(address(lockupTranched), params.sender, params.recipient) + address(FORK_ASSET), Solarray.addresses(address(lockup), params.sender, params.recipient) ); - vars.actualLockupTranchedBalance = vars.balances[0]; + vars.actualLockupBalance = vars.balances[0]; vars.actualSenderBalance = vars.balances[1]; vars.actualRecipientBalance = vars.balances[2]; // Assert that the contract's balance has been updated. - vars.expectedLockupTranchedBalance = vars.initialLockupTranchedBalance - uint256(vars.senderAmount); - assertEq( - vars.actualLockupTranchedBalance, - vars.expectedLockupTranchedBalance, - "post-cancel lockupTranched contract balance" - ); + vars.expectedLockupBalance = vars.initialLockupBalance - uint256(vars.senderAmount); + assertEq(vars.actualLockupBalance, vars.expectedLockupBalance, "post-cancel lockup contract balance"); // Assert that the Sender's balance has been updated. vars.expectedSenderBalance = vars.initialSenderBalance + uint256(vars.senderAmount); @@ -376,7 +362,7 @@ abstract contract LockupTranched_Fork_Test is Fork_Test { } // Assert that the not burned NFT. - vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: vars.streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: vars.streamId }); vars.expectedNFTOwner = params.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "post-cancel NFT owner"); } diff --git a/test/core/fork/NFTDescriptor.t.sol b/test/core/fork/NFTDescriptor.t.sol index 1b6ec3df8..ca4370425 100644 --- a/test/core/fork/NFTDescriptor.t.sol +++ b/test/core/fork/NFTDescriptor.t.sol @@ -3,9 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Fork_Test } from "./Fork.t.sol"; @@ -17,6 +15,10 @@ contract NFTDescriptor_Fork_Test is Fork_Test { IERC20 internal constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); address internal constant DAI_HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14; + ISablierLockup internal lockupDynamic; + ISablierLockup internal lockupLinear; + ISablierLockup internal lockupTranched; + /*////////////////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ @@ -29,23 +31,32 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev Loads the Lockup v1.0.0 contracts pre-deployed on Mainnet. modifier loadDeployments_v1_0_0() { - lockupDynamic = ISablierLockupDynamic(0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44); - lockupLinear = ISablierLockupLinear(0xB10daee1FCF62243aE27776D7a92D39dC8740f95); + lockupDynamic = ISablierLockup(0x39EFdC3dbB57B2388CcC4bb40aC4CB1226Bc9E44); + lockupLinear = ISablierLockup(0xB10daee1FCF62243aE27776D7a92D39dC8740f95); _; } /// @dev Loads the Lockup v1.1.2 contracts pre-deployed on Mainnet. modifier loadDeployments_v1_1_2() { - lockupDynamic = ISablierLockupDynamic(0x7CC7e125d83A581ff438608490Cc0f7bDff79127); - lockupLinear = ISablierLockupLinear(0xAFb979d9afAd1aD27C5eFf4E27226E3AB9e5dCC9); + lockupDynamic = ISablierLockup(0x7CC7e125d83A581ff438608490Cc0f7bDff79127); + lockupLinear = ISablierLockup(0xAFb979d9afAd1aD27C5eFf4E27226E3AB9e5dCC9); _; } /// @dev Loads the Lockup v1.2.0 contracts pre-deployed on Mainnet. modifier loadDeployments_v1_2_0() { - lockupDynamic = ISablierLockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); - lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); - lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + lockupDynamic = ISablierLockup(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); + lockupLinear = ISablierLockup(0x3962f6585946823440d274aD7C719B02b49DE51E); + lockupTranched = ISablierLockup(0xf86B359035208e4529686A1825F2D5BeE38c28A8); + _; + } + + /// @dev Loads the Lockup v1.2.0 contracts pre-deployed on Mainnet. + modifier loadDeployments_v1_3_0() { + // TODO: Add the deployment addresses for Lockup v1.3.0. + // Deploy some streams temporarity for the test + resetPrank({ msgSender: users.sender }); + lockup.createWithDurationsLL(defaults.createWithDurations(), defaults.durations()); _; } @@ -64,12 +75,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.0.0. /// /// Checklist: - /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. - /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupDynamic_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { + function testForkFuzz_TokenURI_Lockup_Dynamic_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Dynamic. @@ -90,12 +101,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.1.2. /// /// Checklist: - /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. - /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupDynamic_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { + function testForkFuzz_TokenURI_Lockup_Dynamic_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Dynamic. @@ -116,12 +127,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Dynamic v1.2.0. /// /// Checklist: - /// - It should expect a call to {ISablierLockupDynamic.tokenURI}. - /// - The test would fail if the call to {ISablierLockupDynamic.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupDynamic_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { + function testForkFuzz_TokenURI_Lockup_Dynamic_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { streamId = _bound(streamId, 1, lockupDynamic.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Dynamic. @@ -142,12 +153,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.0.0. /// /// Checklist: - /// - It should expect a call to {ISablierLockupLinear.tokenURI}. - /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupLinear_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { + function testForkFuzz_TokenURI_Lockup_Linear_v1_0_0(uint256 streamId) external loadDeployments_v1_0_0 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Linear. @@ -168,12 +179,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.1.2. /// /// Checklist: - /// - It should expect a call to {ISablierLockupLinear.tokenURI}. - /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupLinear_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { + function testForkFuzz_TokenURI_Lockup_Linear_v1_1_2(uint256 streamId) external loadDeployments_v1_1_2 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Linear. @@ -194,12 +205,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Linear v1.2.0. /// /// Checklist: - /// - It should expect a call to {ISablierLockupLinear.tokenURI}. - /// - The test would fail if the call to {ISablierLockupLinear.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupLinear_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { + function testForkFuzz_TokenURI_Lockup_Linear_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { streamId = _bound(streamId, 1, lockupLinear.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Linear. @@ -220,12 +231,12 @@ contract NFTDescriptor_Fork_Test is Fork_Test { /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup Tranched v1.2.0. /// /// Checklist: - /// - It should expect a call to {ISablierLockupTranched.tokenURI}. - /// - The test would fail if the call to {ISablierLockupTranched.tokenURI} reverts. + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. /// /// Given enough fuzz runs, all the following scenarios will be fuzzed: /// - Multiple values of streamId. - function testForkFuzz_TokenURI_LockupTranched_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { + function testForkFuzz_TokenURI_Lockup_Tranched_v1_2_0(uint256 streamId) external loadDeployments_v1_2_0 { streamId = _bound(streamId, 1, lockupTranched.nextStreamId() - 1); // Set the new NFT descriptor for the previous version of Lockup Tranched. @@ -242,4 +253,30 @@ contract NFTDescriptor_Fork_Test is Fork_Test { // Generate the token URI using the new NFT Descriptor. lockupTranched.tokenURI(streamId); } + + /// @dev The following test checks whether the new NFT descriptor is compatible with Lockup v1.3.0. + /// + /// Checklist: + /// - It should expect a call to {ISablierLockup.tokenURI}. + /// - The test would fail if the call to {ISablierLockup.tokenURI} reverts. + /// + /// Given enough fuzz runs, all the following scenarios will be fuzzed: + /// - Multiple values of streamId. + function testForkFuzz_TokenURI_Lockup_v1_3_0(uint256 streamId) external loadDeployments_v1_3_0 { + streamId = _bound(streamId, 1, lockup.nextStreamId() - 1); + + // Set the new NFT descriptor for the previous version of Lockup. + resetPrank({ msgSender: lockup.admin() }); + lockup.setNFTDescriptor(nftDescriptor); + + // Expects a successful call to the new NFT Descriptor. + vm.expectCall({ + callee: address(nftDescriptor), + data: abi.encodeCall(nftDescriptor.tokenURI, (lockup, streamId)), + count: 1 + }); + + // Generate the token URI using the new NFT Descriptor. + lockup.tokenURI(streamId); + } } diff --git a/test/core/fork/assets/DAI.t.sol b/test/core/fork/assets/DAI.t.sol index 6ef555b06..e96fd5b5b 100644 --- a/test/core/fork/assets/DAI.t.sol +++ b/test/core/fork/assets/DAI.t.sol @@ -3,16 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; -import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; -import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol"; +import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev A typical 18-decimal ERC-20 asset with a normal total supply. IERC20 constant FORK_ASSET = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); address constant FORK_ASSET_HOLDER = 0x66F62574ab04989737228D18C3624f7FC1edAe14; -contract DAI_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract DAI_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract DAI_LockupLinear_Fork_Test is LockupLinear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract DAI_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract DAI_LockupTranched_Fork_Test is LockupTranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract DAI_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } diff --git a/test/core/fork/assets/EURS.t.sol b/test/core/fork/assets/EURS.t.sol index 5abab703e..ea6dc8520 100644 --- a/test/core/fork/assets/EURS.t.sol +++ b/test/core/fork/assets/EURS.t.sol @@ -3,16 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; -import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; -import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol"; +import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with 2 decimals. IERC20 constant FORK_ASSET = IERC20(0xdB25f211AB05b1c97D595516F45794528a807ad8); address constant FORK_ASSET_HOLDER = 0x1bee4F735062CD00841d6997964F187f5f5F5Ac9; -contract EURS_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract EURS_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract EURS_LockupLinear_Fork_Test is LockupLinear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract EURS_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract EURS_LockupTranched_Fork_Test is LockupTranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract EURS_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } diff --git a/test/core/fork/assets/SHIB.t.sol b/test/core/fork/assets/SHIB.t.sol index bf51113dc..0f10927f1 100644 --- a/test/core/fork/assets/SHIB.t.sol +++ b/test/core/fork/assets/SHIB.t.sol @@ -3,16 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; -import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; -import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol"; +import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with a large total supply. IERC20 constant FORK_ASSET = IERC20(0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE); address constant FORK_ASSET_HOLDER = 0x73AF3bcf944a6559933396c1577B257e2054D935; -contract SHIB_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract SHIB_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract SHIB_LockupLinear_Fork_Test is LockupLinear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract SHIB_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract SHIB_LockupTranched_Fork_Test is LockupTranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract SHIB_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } diff --git a/test/core/fork/assets/USDC.t.sol b/test/core/fork/assets/USDC.t.sol index 09c3f5d30..dce918831 100644 --- a/test/core/fork/assets/USDC.t.sol +++ b/test/core/fork/assets/USDC.t.sol @@ -3,16 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; -import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; -import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol"; +import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant FORK_ASSET = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); address constant FORK_ASSET_HOLDER = 0x09528d637deb5857dc059dddE6316D465a8b3b69; -contract USDC_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDC_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract USDC_LockupLinear_Fork_Test is LockupLinear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDC_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract USDC_LockupTranched_Fork_Test is LockupTranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDC_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } diff --git a/test/core/fork/assets/USDT.t.sol b/test/core/fork/assets/USDT.t.sol index da6199324..6bee0e6b1 100644 --- a/test/core/fork/assets/USDT.t.sol +++ b/test/core/fork/assets/USDT.t.sol @@ -3,16 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic_Fork_Test } from "../LockupDynamic.t.sol"; -import { LockupLinear_Fork_Test } from "../LockupLinear.t.sol"; -import { LockupTranched_Fork_Test } from "../LockupTranched.t.sol"; +import { Lockup_Dynamic_Fork_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Linear_Fork_Test } from "../LockupLinear.t.sol"; +import { Lockup_Tranched_Fork_Test } from "../LockupTranched.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant FORK_ASSET = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); address constant FORK_ASSET_HOLDER = 0xee5B5B923fFcE93A870B3104b7CA09c3db80047A; -contract USDT_LockupDynamic_Fork_Test is LockupDynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDT_Lockup_Dynamic_Fork_Test is Lockup_Dynamic_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract USDT_LockupLinear_Fork_Test is LockupLinear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDT_Lockup_Linear_Fork_Test is Lockup_Linear_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } -contract USDT_LockupTranched_Fork_Test is LockupTranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } +contract USDT_Lockup_Tranched_Fork_Test is Lockup_Tranched_Fork_Test(FORK_ASSET, FORK_ASSET_HOLDER) { } diff --git a/test/core/integration/Integration.t.sol b/test/core/integration/Integration.t.sol index dd821fb87..30ee41a56 100644 --- a/test/core/integration/Integration.t.sol +++ b/test/core/integration/Integration.t.sol @@ -1,11 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -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 { Broker } from "src/core/types/DataTypes.sol"; import { Base_Test } from "../../Base.t.sol"; import { @@ -22,17 +18,41 @@ abstract contract Integration_Test is Base_Test { VARIABLES //////////////////////////////////////////////////////////////////////////*/ + // 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; + // A non-cancelable stream ID. + uint256 internal notCancelableStreamId; + // A non-transferable stream ID. uint256 internal notTransferableStreamId; + // A stream ID that does not exist. + uint256 internal nullStreamId = 1729; + // A stream with a recipient contract that implements {ISablierLockupRecipient}. + uint256 internal recipientGoodStreamId; + // A stream with a recipient contract that returns invalid selector bytes on the hook call. + uint256 internal recipientInvalidSelectorStreamId; + // A stream with a reentrant contract as the recipient. + 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; /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev A test contract that is meant to be overridden by the implementing contract, which will be - /// either {SablierLockupDynamic}, {SablierLockupLinear} or {SablierLockupTranched}. - ISablierLockup internal lockup; - RecipientInterfaceIDIncorrect internal recipientInterfaceIDIncorrect; RecipientInterfaceIDMissing internal recipientInterfaceIDMissing; RecipientInvalidSelector internal recipientInvalidSelector; @@ -56,6 +76,10 @@ abstract contract Integration_Test is Base_Test { vm.label({ account: address(recipientInvalidSelector), newLabel: "Recipient Invalid Selector" }); vm.label({ account: address(recipientReentrant), newLabel: "Recipient Reentrant" }); vm.label({ account: address(recipientReverting), newLabel: "Recipient Reverting" }); + + withdrawAmounts.push(defaults.WITHDRAW_AMOUNT()); + withdrawAmounts.push(defaults.DEPOSIT_AMOUNT()); + withdrawAmounts.push(defaults.WITHDRAW_AMOUNT() / 2); } /*////////////////////////////////////////////////////////////////////////// @@ -67,52 +91,4 @@ abstract contract Integration_Test is Base_Test { assertFalse(success, "delegatecall success"); assertEq(returnData, abi.encodeWithSelector(Errors.DelegateCall.selector), "delegatecall return data"); } - - /*////////////////////////////////////////////////////////////////////////// - HELPERS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Creates the default stream. - function createDefaultStream() internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream but make it not cancelable. - function createDefaultStreamNotCancelable() internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the NFT transfer disabled. - function createDefaultStreamNotTransferable() internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided address. - function createDefaultStreamWithAsset(IERC20 asset) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided broker. - function createDefaultStreamWithBroker(Broker memory broker) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided end time. - function createDefaultStreamWithEndTime(uint40 endTime) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided user as the recipient and the sender. - function createDefaultStreamWithIdenticalUsers(address user) internal returns (uint256 streamId) { - return createDefaultStreamWithUsers({ recipient: user, sender: user }); - } - - /// @dev Creates the default stream with the provided recipient. - function createDefaultStreamWithRecipient(address recipient) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided sender. - function createDefaultStreamWithSender(address sender) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided start time. - function createDefaultStreamWithStartTime(uint40 startTime) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided total amount. - function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal virtual returns (uint256 streamId); - - /// @dev Creates the default stream with the provided sender and recipient. - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - virtual - returns (uint256 streamId); } diff --git a/test/core/integration/concrete/lockup-linear/constructor.t.sol b/test/core/integration/concrete/constructor.t.sol similarity index 51% rename from test/core/integration/concrete/lockup-linear/constructor.t.sol rename to test/core/integration/concrete/constructor.t.sol index 6ebbc6295..d016095c7 100644 --- a/test/core/integration/concrete/lockup-linear/constructor.t.sol +++ b/test/core/integration/concrete/constructor.t.sol @@ -4,39 +4,47 @@ pragma solidity >=0.8.22 <0.9.0; import { UD60x18 } from "@prb/math/src/UD60x18.sol"; import { IAdminable } from "src/core/interfaces/IAdminable.sol"; -import { SablierLockupLinear } from "src/core/SablierLockupLinear.sol"; +import { SablierLockup } from "src/core/SablierLockup.sol"; -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; +import { Integration_Test } from "../Integration.t.sol"; -contract Constructor_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { +contract Constructor_Integration_Concrete_Test is Integration_Test { function test_Constructor() external { // Expect the relevant event to be emitted. vm.expectEmit(); emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); // Construct the contract. - SablierLockupLinear constructedLockupLinear = - new SablierLockupLinear({ initialAdmin: users.admin, initialNFTDescriptor: nftDescriptor }); + SablierLockup constructedLockup = new SablierLockup({ + initialAdmin: users.admin, + initialNFTDescriptor: nftDescriptor, + maxCount: defaults.MAX_COUNT() + }); // {SablierLockup.constant} - UD60x18 actualMaxBrokerFee = constructedLockupLinear.MAX_BROKER_FEE(); + UD60x18 actualMaxBrokerFee = constructedLockup.MAX_BROKER_FEE(); UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); // {SablierLockup.constructor} - address actualAdmin = constructedLockupLinear.admin(); + address actualAdmin = constructedLockup.admin(); address expectedAdmin = users.admin; assertEq(actualAdmin, expectedAdmin, "admin"); - uint256 actualStreamId = constructedLockupLinear.nextStreamId(); + uint256 actualStreamId = constructedLockup.nextStreamId(); uint256 expectedStreamId = 1; assertEq(actualStreamId, expectedStreamId, "nextStreamId"); - address actualNFTDescriptor = address(constructedLockupLinear.nftDescriptor()); + address actualNFTDescriptor = address(constructedLockup.nftDescriptor()); address expectedNFTDescriptor = address(nftDescriptor); assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); // {SablierLockup.supportsInterface} - assertTrue(constructedLockupLinear.supportsInterface(0x49064906), "ERC-4906 interface ID"); + assertTrue(constructedLockup.supportsInterface(0x49064906), "ERC-4906 interface ID"); + + // {SablierLockup.constructor} + uint256 actualMaxCount = constructedLockup.MAX_COUNT(); + uint256 expectedMaxCount = defaults.MAX_COUNT(); + assertEq(actualMaxCount, expectedMaxCount, "MAX_COUNT"); } } diff --git a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol b/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol similarity index 85% rename from test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol rename to test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol index 2b50092e5..2e2b71d56 100644 --- a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.t.sol +++ b/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -18,7 +18,7 @@ abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_ProvidedAddressNotContract() external whenCallerAdmin { address eoa = vm.addr({ privateKey: 1 }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_AllowToHookZeroCodeSize.selector, eoa)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_AllowToHookZeroCodeSize.selector, eoa)); lockup.allowToHook(eoa); } @@ -30,7 +30,7 @@ abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test { // Incorrect interface ID. address recipient = address(recipientInterfaceIDIncorrect); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_AllowToHookUnsupportedInterface.selector, recipient) + abi.encodeWithSelector(Errors.SablierLockupBase_AllowToHookUnsupportedInterface.selector, recipient) ); lockup.allowToHook(recipient); @@ -43,7 +43,7 @@ abstract contract AllowToHook_Integration_Concrete_Test is Integration_Test { function test_WhenProvidedAddressReturnsInterfaceId() external whenCallerAdmin whenProvidedAddressContract { // It should emit a {AllowToHook} event. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.AllowToHook(users.admin, address(recipientGood)); + emit ISablierLockupBase.AllowToHook(users.admin, address(recipientGood)); // Allow the provided address to hook. lockup.allowToHook(address(recipientGood)); diff --git a/test/core/integration/concrete/lockup/allow-to-hook/allowToHook.tree b/test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.tree similarity index 100% rename from test/core/integration/concrete/lockup/allow-to-hook/allowToHook.tree rename to test/core/integration/concrete/lockup-base/allow-to-hook/allowToHook.tree diff --git a/test/core/integration/concrete/lockup/batch/batch.t.sol b/test/core/integration/concrete/lockup-base/batch/batch.t.sol similarity index 87% rename from test/core/integration/concrete/lockup/batch/batch.t.sol rename to test/core/integration/concrete/lockup-base/batch/batch.t.sol index 55ec13ca4..7c30ba55b 100644 --- a/test/core/integration/concrete/lockup/batch/batch.t.sol +++ b/test/core/integration/concrete/lockup-base/batch/batch.t.sol @@ -15,13 +15,11 @@ abstract contract Batch_Integration_Concrete_Test is Integration_Test { } function test_RevertWhen_DataInvalid() external whenCallFunctionExists { - uint256 nonExistentStreamId = 1337; - bytes[] memory calls = new bytes[](1); - calls[0] = abi.encodeCall(lockup.getDepositedAmount, (nonExistentStreamId)); + calls[0] = abi.encodeCall(lockup.getDepositedAmount, (nullStreamId)); bytes memory expectedRevertData = abi.encodeWithSelector( - Errors.BatchError.selector, abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nonExistentStreamId) + Errors.BatchError.selector, abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId) ); vm.expectRevert(expectedRevertData); diff --git a/test/core/integration/concrete/lockup/batch/batch.tree b/test/core/integration/concrete/lockup-base/batch/batch.tree similarity index 100% rename from test/core/integration/concrete/lockup/batch/batch.tree rename to test/core/integration/concrete/lockup-base/batch/batch.tree diff --git a/test/core/integration/concrete/lockup/burn/burn.t.sol b/test/core/integration/concrete/lockup-base/burn/burn.t.sol similarity index 86% rename from test/core/integration/concrete/lockup/burn/burn.t.sol rename to test/core/integration/concrete/lockup-base/burn/burn.t.sol index 7d77032e8..ab8ec3ef4 100644 --- a/test/core/integration/concrete/lockup/burn/burn.t.sol +++ b/test/core/integration/concrete/lockup-base/burn/burn.t.sol @@ -3,38 +3,37 @@ 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 { ISablierLockup } from "src/core/interfaces/ISablierLockup.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 { function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockup.burn, defaultStreamId); + bytes memory callData = abi.encodeCall(ISablierLockupBase.burn, defaultStreamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNoDelegateCall { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.burn(nullStreamId); } function test_RevertGiven_PENDINGStatus() external whenNoDelegateCall givenNotNull givenNotDepletedStream { vm.warp({ newTimestamp: getBlockTimestamp() - 1 seconds }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotDepleted.selector, defaultStreamId)); lockup.burn(defaultStreamId); } function test_RevertGiven_STREAMINGStatus() external whenNoDelegateCall givenNotNull givenNotDepletedStream { vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotDepleted.selector, defaultStreamId)); lockup.burn(defaultStreamId); } function test_RevertGiven_SETTLEDStatus() external whenNoDelegateCall givenNotNull givenNotDepletedStream { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotDepleted.selector, defaultStreamId)); lockup.burn(defaultStreamId); } @@ -43,7 +42,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test { resetPrank({ msgSender: users.sender }); lockup.cancel(defaultStreamId); resetPrank({ msgSender: users.recipient }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotDepleted.selector, defaultStreamId)); lockup.burn(defaultStreamId); } @@ -55,7 +54,9 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test { whenCallerNotRecipient { resetPrank({ msgSender: users.eve }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) + ); lockup.burn(defaultStreamId); } @@ -68,7 +69,7 @@ abstract contract Burn_Integration_Concrete_Test is Integration_Test { { resetPrank({ msgSender: users.sender }); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.sender) + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.sender) ); lockup.burn(defaultStreamId); } diff --git a/test/core/integration/concrete/lockup/burn/burn.tree b/test/core/integration/concrete/lockup-base/burn/burn.tree similarity index 100% rename from test/core/integration/concrete/lockup/burn/burn.tree rename to test/core/integration/concrete/lockup-base/burn/burn.tree diff --git a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol b/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol similarity index 56% rename from test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol rename to test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol index eef8148c6..6e6c0ec0b 100644 --- a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.t.sol +++ b/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.t.sol @@ -3,19 +3,22 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { CancelMultiple_Integration_Shared_Test } from "../../../shared/lockup/cancelMultiple.t.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; -abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Integration_Shared_Test { function setUp() public virtual override { - CancelMultiple_Integration_Shared_Test.setUp(); + originalTime = getBlockTimestamp(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockup.cancelMultiple, (testStreamIds)); + bytes memory callData = abi.encodeCall(ISablierLockupBase.cancelMultiple, (cancelMultipleStreamIds)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -27,9 +30,8 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int } function test_RevertGiven_AtleastOneNullStream() external whenNoDelegateCall whenNonZeroArrayLength { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], nullStreamId) }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.cancelMultiple({ streamIds: Solarray.uint256s(cancelMultipleStreamIds[0], nullStreamId) }); } function test_RevertGiven_AtleastOneColdStream() @@ -38,10 +40,9 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int whenNonZeroArrayLength givenNoNullStreams { - uint256 earlyStreamId = createDefaultStreamWithEndTime({ endTime: defaults.CLIFF_TIME() + 1 seconds }); vm.warp({ newTimestamp: defaults.CLIFF_TIME() + 1 seconds }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, earlyStreamId)); - lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], earlyStreamId) }); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, earlyEndtimeStreamId)); + lockup.cancelMultiple({ streamIds: Solarray.uint256s(cancelMultipleStreamIds[0], earlyEndtimeStreamId) }); } function test_RevertWhen_CallerUnauthorizedForAny() @@ -56,9 +57,11 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, testStreamIds[0], users.recipient) + abi.encodeWithSelector( + Errors.SablierLockupBase_Unauthorized.selector, cancelMultipleStreamIds[0], users.recipient + ) ); - lockup.cancelMultiple(testStreamIds); + lockup.cancelMultiple(cancelMultipleStreamIds); } function test_RevertGiven_AtleastOneNonCancelableStream() @@ -67,13 +70,12 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int whenNonZeroArrayLength givenNoNullStreams givenNoColdStreams - whenCallerAuthorizedForAll + whenCallerAuthorizedForAllStreams { - uint256 notCancelableStreamId = createDefaultStreamNotCancelable(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, notCancelableStreamId) + abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotCancelable.selector, notCancelableStreamId) ); - lockup.cancelMultiple({ streamIds: Solarray.uint256s(testStreamIds[0], notCancelableStreamId) }); + lockup.cancelMultiple({ streamIds: Solarray.uint256s(cancelMultipleStreamIds[0], notCancelableStreamId) }); } function test_GivenNoNonCancelableStreams() @@ -82,21 +84,21 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int whenNonZeroArrayLength givenNoNullStreams givenNoColdStreams - whenCallerAuthorizedForAll + whenCallerAuthorizedForAllStreams { // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // It should refund the sender. - uint128 senderAmount0 = lockup.refundableAmountOf(testStreamIds[0]); + uint128 senderAmount0 = lockup.refundableAmountOf(cancelMultipleStreamIds[0]); expectCallToTransfer({ to: users.sender, value: senderAmount0 }); - uint128 senderAmount1 = lockup.refundableAmountOf(testStreamIds[1]); + uint128 senderAmount1 = lockup.refundableAmountOf(cancelMultipleStreamIds[1]); expectCallToTransfer({ to: users.sender, value: senderAmount1 }); // It should emit {CancelLockupStream} events for all streams. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream({ - streamId: testStreamIds[0], + emit ISablierLockupBase.CancelLockupStream({ + streamId: cancelMultipleStreamIds[0], sender: users.sender, recipient: users.recipient, asset: dai, @@ -104,8 +106,8 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 }); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream({ - streamId: testStreamIds[1], + emit ISablierLockupBase.CancelLockupStream({ + streamId: cancelMultipleStreamIds[1], sender: users.sender, recipient: users.recipient, asset: dai, @@ -114,24 +116,24 @@ abstract contract CancelMultiple_Integration_Concrete_Test is CancelMultiple_Int }); // Cancel the streams. - lockup.cancelMultiple(testStreamIds); + lockup.cancelMultiple(cancelMultipleStreamIds); // It should mark the streams as canceled. Lockup.Status expectedStatus = Lockup.Status.CANCELED; - assertEq(lockup.statusOf(testStreamIds[0]), expectedStatus, "status0"); - assertEq(lockup.statusOf(testStreamIds[1]), expectedStatus, "status1"); + assertEq(lockup.statusOf(cancelMultipleStreamIds[0]), expectedStatus, "status0"); + assertEq(lockup.statusOf(cancelMultipleStreamIds[1]), expectedStatus, "status1"); // It should make the streams as non cancelable. - assertFalse(lockup.isCancelable(testStreamIds[0]), "isCancelable0"); - assertFalse(lockup.isCancelable(testStreamIds[1]), "isCancelable1"); + assertFalse(lockup.isCancelable(cancelMultipleStreamIds[0]), "isCancelable0"); + assertFalse(lockup.isCancelable(cancelMultipleStreamIds[1]), "isCancelable1"); // It should update the refunded amounts. - assertEq(lockup.getRefundedAmount(testStreamIds[0]), senderAmount0, "refundedAmount0"); - assertEq(lockup.getRefundedAmount(testStreamIds[1]), senderAmount1, "refundedAmount1"); + assertEq(lockup.getRefundedAmount(cancelMultipleStreamIds[0]), senderAmount0, "refundedAmount0"); + assertEq(lockup.getRefundedAmount(cancelMultipleStreamIds[1]), senderAmount1, "refundedAmount1"); // It should not burn the NFT for all streams. address expectedNFTOwner = users.recipient; - assertEq(lockup.getRecipient(testStreamIds[0]), expectedNFTOwner, "NFT owner0"); - assertEq(lockup.getRecipient(testStreamIds[1]), expectedNFTOwner, "NFT owner1"); + assertEq(lockup.getRecipient(cancelMultipleStreamIds[0]), expectedNFTOwner, "NFT owner0"); + assertEq(lockup.getRecipient(cancelMultipleStreamIds[1]), expectedNFTOwner, "NFT owner1"); } } diff --git a/test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree b/test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.tree similarity index 100% rename from test/core/integration/concrete/lockup/cancel-multiple/cancelMultiple.tree rename to test/core/integration/concrete/lockup-base/cancel-multiple/cancelMultiple.tree diff --git a/test/core/integration/concrete/lockup/cancel/cancel.t.sol b/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol similarity index 71% rename from test/core/integration/concrete/lockup/cancel/cancel.t.sol rename to test/core/integration/concrete/lockup-base/cancel/cancel.t.sol index 19794e7e3..c68aaa959 100644 --- a/test/core/integration/concrete/lockup/cancel/cancel.t.sol +++ b/test/core/integration/concrete/lockup-base/cancel/cancel.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -12,34 +12,33 @@ 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(ISablierLockup.cancel, defaultStreamId); + bytes memory callData = abi.encodeCall(ISablierLockupBase.cancel, defaultStreamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNoDelegateCall { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); 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.SablierLockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); 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.SablierLockup_StreamCanceled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamCanceled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } function test_RevertGiven_SETTLEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, defaultStreamId)); lockup.cancel(defaultStreamId); } @@ -54,7 +53,9 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) + ); lockup.cancel(defaultStreamId); } @@ -70,7 +71,7 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.recipient) + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.recipient) ); lockup.cancel(defaultStreamId); } @@ -82,9 +83,10 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { givenWarmStream whenCallerSender { - uint256 streamId = createDefaultStreamNotCancelable(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, streamId)); - lockup.cancel(streamId); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotCancelable.selector, notCancelableStreamId) + ); + lockup.cancel(notCancelableStreamId); } function test_GivenPENDINGStatus() @@ -120,25 +122,23 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { givenCancelableStream givenSTREAMINGStatus { - // Create the stream with a recipient contract that implements {ISablierLockupRecipient}. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // It should not make Sablier run the recipient hook. - uint128 senderAmount = lockup.refundableAmountOf(streamId); - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); + uint128 senderAmount = lockup.refundableAmountOf(recipientGoodStreamId); + uint128 recipientAmount = lockup.withdrawableAmountOf(recipientGoodStreamId); vm.expectCall({ callee: address(recipientGood), data: abi.encodeCall( - ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) + ISablierLockupRecipient.onSablierLockupCancel, + (recipientGoodStreamId, users.sender, senderAmount, recipientAmount) ), count: 0 }); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientGoodStreamId); // It should mark the stream as canceled. - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientGoodStreamId); Lockup.Status expectedStatus = Lockup.Status.CANCELED; assertEq(actualStatus, expectedStatus); } @@ -158,14 +158,11 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientReverting)); resetPrank({ msgSender: users.sender }); - // Create the stream with a reverting contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientReverting)); - // It should revert. vm.expectRevert("You shall not pass"); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientRevertStreamId); } function test_RevertWhen_RecipientReturnsInvalidSelector() @@ -184,16 +181,15 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientInvalidSelector)); resetPrank({ msgSender: users.sender }); - // Create the stream with a recipient contract that returns invalid selector bytes on the hook call. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientInvalidSelector)); - // It should revert. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_InvalidHookSelector.selector, address(recipientInvalidSelector)) + abi.encodeWithSelector( + Errors.SablierLockupBase_InvalidHookSelector.selector, address(recipientInvalidSelector) + ) ); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientInvalidSelectorStreamId); } function test_WhenReentrancy() @@ -213,35 +209,35 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientReentrant)); resetPrank({ msgSender: users.sender }); - // Create the stream with a reentrant contract as the recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientReentrant)); - // It should make Sablier run the recipient hook. - uint128 senderAmount = lockup.refundableAmountOf(streamId); - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); + uint128 senderAmount = lockup.refundableAmountOf(recipientReentrantStreamId); + uint128 recipientAmount = lockup.withdrawableAmountOf(recipientReentrantStreamId); vm.expectCall( address(recipientReentrant), abi.encodeCall( - ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) + ISablierLockupRecipient.onSablierLockupCancel, + (recipientReentrantStreamId, users.sender, senderAmount, recipientAmount) ) ); // It should perform a reentrancy call to the Lockup contract. vm.expectCall( address(lockup), - abi.encodeCall(ISablierLockup.withdraw, (streamId, address(recipientReentrant), recipientAmount)) + abi.encodeCall( + ISablierLockupBase.withdraw, (recipientReentrantStreamId, address(recipientReentrant), recipientAmount) + ) ); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientReentrantStreamId); // It should mark the stream as depleted. The reentrant recipient withdrew all the funds. - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientReentrantStreamId); Lockup.Status expectedStatus = Lockup.Status.DEPLETED; assertEq(actualStatus, expectedStatus); // It should make the withdrawal via the reentrancy. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(recipientReentrantStreamId); assertEq(actualWithdrawnAmount, recipientAmount, "withdrawnAmount"); } @@ -262,49 +258,47 @@ abstract contract Cancel_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientGood)); resetPrank({ msgSender: users.sender }); - // Create the stream. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // It should refund the sender. - uint128 senderAmount = lockup.refundableAmountOf(streamId); + uint128 senderAmount = lockup.refundableAmountOf(recipientGoodStreamId); expectCallToTransfer({ to: users.sender, value: senderAmount }); // It should make Sablier run the recipient hook. - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); + uint128 recipientAmount = lockup.withdrawableAmountOf(recipientGoodStreamId); vm.expectCall( address(recipientGood), abi.encodeCall( - ISablierLockupRecipient.onSablierLockupCancel, (streamId, users.sender, senderAmount, recipientAmount) + ISablierLockupRecipient.onSablierLockupCancel, + (recipientGoodStreamId, users.sender, senderAmount, recipientAmount) ) ); // It should emit {MetadataUpdate} and {CancelLockupStream} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream( - streamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount + emit ISablierLockupBase.CancelLockupStream( + recipientGoodStreamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount ); vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: recipientGoodStreamId }); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientGoodStreamId); // It should mark the stream as canceled. - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientGoodStreamId); Lockup.Status expectedStatus = Lockup.Status.CANCELED; assertEq(actualStatus, expectedStatus); // It should make the stream as non cancelable. - bool isCancelable = lockup.isCancelable(streamId); + bool isCancelable = lockup.isCancelable(recipientGoodStreamId); assertFalse(isCancelable, "isCancelable"); // It should update the refunded amount. - uint128 actualRefundedAmount = lockup.getRefundedAmount(streamId); + uint128 actualRefundedAmount = lockup.getRefundedAmount(recipientGoodStreamId); uint128 expectedRefundedAmount = senderAmount; assertEq(actualRefundedAmount, expectedRefundedAmount, "refundedAmount"); // It should not burn the NFT. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: recipientGoodStreamId }); address expectedNFTOwner = address(recipientGood); assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/concrete/lockup/cancel/cancel.tree b/test/core/integration/concrete/lockup-base/cancel/cancel.tree similarity index 100% rename from test/core/integration/concrete/lockup/cancel/cancel.tree rename to test/core/integration/concrete/lockup-base/cancel/cancel.tree diff --git a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol b/test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol similarity index 72% rename from test/core/integration/concrete/lockup/get-asset/getAsset.t.sol rename to test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol index 582620243..5c8a3dbc0 100644 --- a/test/core/integration/concrete/lockup/get-asset/getAsset.t.sol +++ b/test/core/integration/concrete/lockup-base/get-asset/getAsset.t.sol @@ -8,14 +8,12 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetAsset_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getAsset(nullStreamId); } - function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - IERC20 actualAsset = lockup.getAsset(streamId); + 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/get-asset/getAsset.tree b/test/core/integration/concrete/lockup-base/get-asset/getAsset.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-asset/getAsset.tree rename to test/core/integration/concrete/lockup-base/get-asset/getAsset.tree diff --git a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol b/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol similarity index 78% rename from test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol rename to test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol index ed091abc0..54d3a320e 100644 --- a/test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.t.sol +++ b/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.t.sol @@ -7,14 +7,12 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetDepositedAmount_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getDepositedAmount(nullStreamId); } - function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - uint128 actualDepositedAmount = lockup.getDepositedAmount(streamId); + 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/get-deposited-amount/getDepositedAmount.tree b/test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-deposited-amount/getDepositedAmount.tree rename to test/core/integration/concrete/lockup-base/get-deposited-amount/getDepositedAmount.tree diff --git a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol b/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol similarity index 71% rename from test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol rename to test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol index 475347b27..fd5df5b09 100644 --- a/test/core/integration/concrete/lockup/get-end-time/getEndTime.t.sol +++ b/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.t.sol @@ -7,14 +7,12 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetEndTime_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getEndTime(nullStreamId); } - function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - uint40 actualEndTime = lockup.getEndTime(streamId); + 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/get-end-time/getEndTime.tree b/test/core/integration/concrete/lockup-base/get-end-time/getEndTime.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-end-time/getEndTime.tree rename to test/core/integration/concrete/lockup-base/get-end-time/getEndTime.tree diff --git a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol b/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol similarity index 97% rename from test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol rename to test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol index 736c3f534..f148c0171 100644 --- a/test/core/integration/concrete/lockup/get-recipient/getRecipient.t.sol +++ b/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.t.sol @@ -7,7 +7,6 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetRecipient_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); lockup.getRecipient(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-recipient/getRecipient.tree b/test/core/integration/concrete/lockup-base/get-recipient/getRecipient.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-recipient/getRecipient.tree rename to test/core/integration/concrete/lockup-base/get-recipient/getRecipient.tree diff --git a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol b/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol similarity index 97% rename from test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol rename to test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol index 6692d5b09..75b65781b 100644 --- a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.t.sol +++ b/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetRefundedAmount_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getRefundedAmount(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree b/test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-refunded-amount/getRefundedAmount.tree rename to test/core/integration/concrete/lockup-base/get-refunded-amount/getRefundedAmount.tree diff --git a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol b/test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol similarity index 70% rename from test/core/integration/concrete/lockup/get-sender/getSender.t.sol rename to test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol index 05834d7c8..3cb3abd80 100644 --- a/test/core/integration/concrete/lockup/get-sender/getSender.t.sol +++ b/test/core/integration/concrete/lockup-base/get-sender/getSender.t.sol @@ -7,14 +7,12 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetSender_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getSender(nullStreamId); } - function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - address actualSender = lockup.getSender(streamId); + 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/get-sender/getSender.tree b/test/core/integration/concrete/lockup-base/get-sender/getSender.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-sender/getSender.tree rename to test/core/integration/concrete/lockup-base/get-sender/getSender.tree diff --git a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol b/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol similarity index 80% rename from test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol rename to test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol index 8ea7e1fd4..5d5d0d1aa 100644 --- a/test/core/integration/concrete/lockup/get-start-time/getStartTime.t.sol +++ b/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.t.sol @@ -7,14 +7,12 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetStartTime_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getStartTime(nullStreamId); } function test_GivenNotNull() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getStartTime(nullStreamId); } } diff --git a/test/core/integration/concrete/lockup/get-start-time/getStartTime.tree b/test/core/integration/concrete/lockup-base/get-start-time/getStartTime.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-start-time/getStartTime.tree rename to test/core/integration/concrete/lockup-base/get-start-time/getStartTime.tree diff --git a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol b/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol similarity index 95% rename from test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol rename to test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol index 65a3605e2..4bf94239b 100644 --- a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol +++ b/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract GetWithdrawnAmount_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.getWithdrawnAmount(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree b/test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.tree similarity index 100% rename from test/core/integration/concrete/lockup/get-withdrawn-amount/getWithdrawnAmount.tree rename to test/core/integration/concrete/lockup-base/get-withdrawn-amount/getWithdrawnAmount.tree diff --git a/test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol b/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol similarity index 100% rename from test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.t.sol rename to test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.t.sol diff --git a/test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree b/test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-allowed-to-hook/isAllowedToHook.tree rename to test/core/integration/concrete/lockup-base/is-allowed-to-hook/isAllowedToHook.tree diff --git a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol b/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol similarity index 77% rename from test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol rename to test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol index 0c9024ea1..f2e9e3635 100644 --- a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.t.sol +++ b/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsCancelable_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.isCancelable(nullStreamId); } @@ -23,9 +22,8 @@ abstract contract IsCancelable_Integration_Concrete_Test is Integration_Test { assertTrue(isCancelable, "isCancelable"); } - function test_GivenNonCancelableStream() external givenNotNull givenWarmStream { - uint256 streamId = createDefaultStreamNotCancelable(); - bool isCancelable = lockup.isCancelable(streamId); + function test_GivenNonCancelableStream() external view givenNotNull givenWarmStream { + bool isCancelable = lockup.isCancelable(notCancelableStreamId); assertFalse(isCancelable, "isCancelable"); } } diff --git a/test/core/integration/concrete/lockup/is-cancelable/isCancelable.tree b/test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-cancelable/isCancelable.tree rename to test/core/integration/concrete/lockup-base/is-cancelable/isCancelable.tree diff --git a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol b/test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol similarity index 95% rename from test/core/integration/concrete/lockup/is-cold/isCold.t.sol rename to test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol index da1a1a2bc..54795e743 100644 --- a/test/core/integration/concrete/lockup/is-cold/isCold.t.sol +++ b/test/core/integration/concrete/lockup-base/is-cold/isCold.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsCold_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.isCold(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-cold/isCold.tree b/test/core/integration/concrete/lockup-base/is-cold/isCold.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-cold/isCold.tree rename to test/core/integration/concrete/lockup-base/is-cold/isCold.tree diff --git a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol b/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol similarity index 92% rename from test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol rename to test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol index 3ce146c15..2d4e92115 100644 --- a/test/core/integration/concrete/lockup/is-depleted/isDepleted.t.sol +++ b/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsDepleted_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.isDepleted(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-depleted/isDepleted.tree b/test/core/integration/concrete/lockup-base/is-depleted/isDepleted.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-depleted/isDepleted.tree rename to test/core/integration/concrete/lockup-base/is-depleted/isDepleted.tree diff --git a/test/core/integration/concrete/lockup/is-stream/isStream.t.sol b/test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol similarity index 93% rename from test/core/integration/concrete/lockup/is-stream/isStream.t.sol rename to test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol index 019e6342e..76e129c59 100644 --- a/test/core/integration/concrete/lockup/is-stream/isStream.t.sol +++ b/test/core/integration/concrete/lockup-base/is-stream/isStream.t.sol @@ -5,7 +5,6 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsStream_Integration_Concrete_Test is Integration_Test { function test_GivenNull() external view { - uint256 nullStreamId = 1729; bool isStream = lockup.isStream(nullStreamId); assertFalse(isStream, "isStream"); } diff --git a/test/core/integration/concrete/lockup/is-stream/isStream.tree b/test/core/integration/concrete/lockup-base/is-stream/isStream.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-stream/isStream.tree rename to test/core/integration/concrete/lockup-base/is-stream/isStream.tree diff --git a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol b/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol similarity index 92% rename from test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol rename to test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol index 890f9fbec..02a74019d 100644 --- a/test/core/integration/concrete/lockup/is-transferable/isTransferable.t.sol +++ b/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsTransferable_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.isTransferable(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-transferable/isTransferable.tree b/test/core/integration/concrete/lockup-base/is-transferable/isTransferable.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-transferable/isTransferable.tree rename to test/core/integration/concrete/lockup-base/is-transferable/isTransferable.tree diff --git a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol b/test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol similarity index 95% rename from test/core/integration/concrete/lockup/is-warm/isWarm.t.sol rename to test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol index 989b2c5a8..e88dc484d 100644 --- a/test/core/integration/concrete/lockup/is-warm/isWarm.t.sol +++ b/test/core/integration/concrete/lockup-base/is-warm/isWarm.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract IsWarm_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.isWarm(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/is-warm/isWarm.tree b/test/core/integration/concrete/lockup-base/is-warm/isWarm.tree similarity index 100% rename from test/core/integration/concrete/lockup/is-warm/isWarm.tree rename to test/core/integration/concrete/lockup-base/is-warm/isWarm.tree diff --git a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol b/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol similarity index 95% rename from test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol rename to test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol index 37ab4a643..46a01d520 100644 --- a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.t.sol @@ -7,15 +7,13 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract RefundableAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.refundableAmountOf(nullStreamId); } function test_GivenNonCancelableStream() external givenNotNull { - uint256 streamId = createDefaultStreamNotCancelable(); vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - uint128 actualRefundableAmount = lockup.refundableAmountOf(streamId); + uint128 actualRefundableAmount = lockup.refundableAmountOf(notCancelableStreamId); uint128 expectedRefundableAmount = 0; assertEq(actualRefundableAmount, expectedRefundableAmount, "refundableAmount"); } diff --git a/test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree b/test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.tree similarity index 100% rename from test/core/integration/concrete/lockup/refundable-amount-of/refundableAmountOf.tree rename to test/core/integration/concrete/lockup-base/refundable-amount-of/refundableAmountOf.tree diff --git a/test/core/integration/concrete/lockup/renounce/renounce.t.sol b/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol similarity index 76% rename from test/core/integration/concrete/lockup/renounce/renounce.t.sol rename to test/core/integration/concrete/lockup-base/renounce/renounce.t.sol index 685af48f9..a453a52d9 100644 --- a/test/core/integration/concrete/lockup/renounce/renounce.t.sol +++ b/test/core/integration/concrete/lockup-base/renounce/renounce.t.sol @@ -3,49 +3,52 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.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 Renounce_Integration_Concrete_Test is Integration_Test { + uint256 internal streamId; + function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockup.renounce, defaultStreamId); + bytes memory callData = abi.encodeCall(ISablierLockupBase.renounce, defaultStreamId); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNoDelegateCall { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); 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.SablierLockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); 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.SablierLockup_StreamCanceled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamCanceled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } function test_RevertGiven_SETTLEDStatus() external whenNoDelegateCall givenNotNull givenColdStream { vm.warp({ newTimestamp: defaults.END_TIME() }); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamSettled.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamSettled.selector, defaultStreamId)); lockup.renounce(defaultStreamId); } modifier givenWarmStreamRenounce() { vm.warp({ newTimestamp: defaults.START_TIME() - 1 seconds }); + streamId = defaultStreamId; _; vm.warp({ newTimestamp: defaults.START_TIME() }); + streamId = recipientGoodStreamId; _; } @@ -54,7 +57,9 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { resetPrank({ msgSender: users.eve }); // Run the test. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) + ); lockup.renounce(defaultStreamId); } @@ -65,12 +70,9 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { givenWarmStreamRenounce whenCallerSender { - // Create the not cancelable stream. - uint256 notCancelableStreamId = createDefaultStreamNotCancelable(); - // Run the test. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_StreamNotCancelable.selector, notCancelableStreamId) + abi.encodeWithSelector(Errors.SablierLockupBase_StreamNotCancelable.selector, notCancelableStreamId) ); lockup.renounce(notCancelableStreamId); } @@ -82,12 +84,9 @@ abstract contract Renounce_Integration_Concrete_Test is Integration_Test { givenWarmStreamRenounce whenCallerSender { - // Create the stream with a contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // It should emit {MetadataUpdate} and {RenounceLockupStream} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.RenounceLockupStream(streamId); + emit ISablierLockupBase.RenounceLockupStream(streamId); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); diff --git a/test/core/integration/concrete/lockup/renounce/renounce.tree b/test/core/integration/concrete/lockup-base/renounce/renounce.tree similarity index 100% rename from test/core/integration/concrete/lockup/renounce/renounce.tree rename to test/core/integration/concrete/lockup-base/renounce/renounce.tree diff --git a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol b/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol similarity index 87% rename from test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol rename to test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol index c03772d5d..6d536317d 100644 --- a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.t.sol +++ b/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { LockupNFTDescriptor } from "src/core/LockupNFTDescriptor.sol"; import { Integration_Test } from "./../../../Integration.t.sol"; @@ -21,7 +21,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test function test_WhenProvidedAddressMatchesCurrentNFTDescriptor() external whenCallerAdmin { // It should emit {SetNFTDescriptor} and {BatchMetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.SetNFTDescriptor(users.admin, nftDescriptor, nftDescriptor); + emit ISablierLockupBase.SetNFTDescriptor(users.admin, nftDescriptor, nftDescriptor); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.BatchMetadataUpdate({ _fromTokenId: 1, _toTokenId: lockup.nextStreamId() - 1 }); @@ -29,7 +29,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test lockup.setNFTDescriptor(nftDescriptor); // It should re-set the NFT descriptor. - vm.expectCall(address(nftDescriptor), abi.encodeCall(ILockupNFTDescriptor.tokenURI, (lockup, 1))); + vm.expectCall(address(nftDescriptor), abi.encodeCall(ILockupNFTDescriptor.tokenURI, (lockup, defaultStreamId))); lockup.tokenURI({ tokenId: defaultStreamId }); } @@ -39,7 +39,7 @@ abstract contract SetNFTDescriptor_Integration_Concrete_Test is Integration_Test // It should emit {SetNFTDescriptor} and {BatchMetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.SetNFTDescriptor(users.admin, nftDescriptor, newNFTDescriptor); + emit ISablierLockupBase.SetNFTDescriptor(users.admin, nftDescriptor, newNFTDescriptor); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.BatchMetadataUpdate({ _fromTokenId: 1, _toTokenId: lockup.nextStreamId() - 1 }); diff --git a/test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree b/test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.tree similarity index 100% rename from test/core/integration/concrete/lockup/set-nft-descriptor/setNFTDescriptor.tree rename to test/core/integration/concrete/lockup-base/set-nft-descriptor/setNFTDescriptor.tree diff --git a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol b/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol similarity index 97% rename from test/core/integration/concrete/lockup/status-of/statusOf.t.sol rename to test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol index d25903f34..d1dde1c52 100644 --- a/test/core/integration/concrete/lockup/status-of/statusOf.t.sol +++ b/test/core/integration/concrete/lockup-base/status-of/statusOf.t.sol @@ -8,8 +8,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract StatusOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.statusOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/status-of/statusOf.tree b/test/core/integration/concrete/lockup-base/status-of/statusOf.tree similarity index 100% rename from test/core/integration/concrete/lockup/status-of/statusOf.tree rename to test/core/integration/concrete/lockup-base/status-of/statusOf.tree diff --git a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol b/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol similarity index 97% rename from test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol rename to test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol index b3f59917b..b1d05adcf 100644 --- a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract StreamedAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.streamedAmountOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.tree similarity index 100% rename from test/core/integration/concrete/lockup/streamed-amount-of/streamedAmountOf.tree rename to test/core/integration/concrete/lockup-base/streamed-amount-of/streamedAmountOf.tree diff --git a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol b/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol similarity index 91% rename from test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol rename to test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol index e86f05d8a..c1274144a 100644 --- a/test/core/integration/concrete/lockup/transfer-from/transferFrom.t.sol +++ b/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.t.sol @@ -15,7 +15,9 @@ abstract contract TransferFrom_Integration_Concrete_Test is Integration_Test { } function test_RevertGiven_NonTransferableStream() external { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_NotTransferable.selector, notTransferableStreamId)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_NotTransferable.selector, notTransferableStreamId) + ); lockup.transferFrom({ from: users.recipient, to: users.alice, tokenId: notTransferableStreamId }); } diff --git a/test/core/integration/concrete/lockup/transfer-from/transferFrom.tree b/test/core/integration/concrete/lockup-base/transfer-from/transferFrom.tree similarity index 100% rename from test/core/integration/concrete/lockup/transfer-from/transferFrom.tree rename to test/core/integration/concrete/lockup-base/transfer-from/transferFrom.tree diff --git a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol b/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol similarity index 92% rename from test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol rename to test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol index 5035dcc60..03bd3a094 100644 --- a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.t.sol +++ b/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract WasCanceled_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.wasCanceled(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/was-canceled/wasCanceled.tree b/test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.tree similarity index 100% rename from test/core/integration/concrete/lockup/was-canceled/wasCanceled.tree rename to test/core/integration/concrete/lockup-base/was-canceled/wasCanceled.tree diff --git a/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol b/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol similarity index 68% rename from test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol rename to test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol index 67d586a1c..061552860 100644 --- a/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.t.sol @@ -18,9 +18,6 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { } function test_GivenRecipientSameAsSender() external { - // Create a stream with identical sender and recipient. - uint256 streamId = createDefaultStreamWithIdenticalUsers(users.sender); - // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); @@ -28,19 +25,17 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { vm.expectCall({ callee: users.sender, data: abi.encodeCall( - ISablierLockupRecipient.onSablierLockupWithdraw, (streamId, users.sender, users.sender, withdrawAmount) + ISablierLockupRecipient.onSablierLockupWithdraw, + (identicalSenderRecipientStreamId, users.sender, users.sender, withdrawAmount) ), count: 0 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: users.sender, amount: withdrawAmount }); + lockup.withdraw({ streamId: identicalSenderRecipientStreamId, to: users.sender, amount: withdrawAmount }); } function test_WhenCallerUnknown() external givenRecipientNotSameAsSender { - // Create the test stream. - uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Make the unknown address the caller in this test. address unknownCaller = address(0xCAFE); resetPrank({ msgSender: unknownCaller }); @@ -53,22 +48,23 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, unknownCaller, address(recipientGood), withdrawAmount) + (differentSenderRecipientStreamId, unknownCaller, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ + streamId: differentSenderRecipientStreamId, + to: address(recipientGood), + amount: withdrawAmount + }); } function test_WhenCallerApprovedThirdParty() external givenRecipientNotSameAsSender { - // Create the test stream. - uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Approve the operator to handle the stream. resetPrank({ msgSender: address(recipientGood) }); - lockup.approve({ to: users.operator, tokenId: streamId }); + lockup.approve({ to: users.operator, tokenId: differentSenderRecipientStreamId }); // Make the operator the caller in this test. resetPrank({ msgSender: users.operator }); @@ -81,19 +77,20 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, users.operator, address(recipientGood), withdrawAmount) + (differentSenderRecipientStreamId, users.operator, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ + streamId: differentSenderRecipientStreamId, + to: address(recipientGood), + amount: withdrawAmount + }); } function test_WhenCallerSender() external givenRecipientNotSameAsSender { - // Create the test stream. - uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Make the Sender the caller in this test. resetPrank({ msgSender: users.sender }); @@ -105,19 +102,20 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, users.sender, address(recipientGood), withdrawAmount) + (differentSenderRecipientStreamId, users.sender, address(recipientGood), withdrawAmount) ), count: 1 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ + streamId: differentSenderRecipientStreamId, + to: address(recipientGood), + amount: withdrawAmount + }); } function test_WhenCallerRecipient() external givenRecipientNotSameAsSender { - // Create the test stream. - uint256 streamId = createDefaultStreamWithUsers({ recipient: address(recipientGood), sender: users.sender }); - // Make the recipient contract the caller in this test. resetPrank({ msgSender: address(recipientGood) }); @@ -129,12 +127,16 @@ abstract contract WithdrawHooks_Integration_Concrete_Test is Integration_Test { callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, address(recipientGood), address(recipientGood), withdrawAmount) + (differentSenderRecipientStreamId, address(recipientGood), address(recipientGood), withdrawAmount) ), count: 0 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ + streamId: differentSenderRecipientStreamId, + to: address(recipientGood), + amount: withdrawAmount + }); } } diff --git a/test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree b/test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdraw-hooks/withdrawHooks.tree rename to test/core/integration/concrete/lockup-base/withdraw-hooks/withdrawHooks.tree diff --git a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol b/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol similarity index 91% rename from test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol rename to test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol index 5b95075e3..ba2a5bd27 100644 --- a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol @@ -5,25 +5,27 @@ import { IERC721Errors } from "@openzeppelin/contracts/interfaces/draft-IERC6093 import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.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 WithdrawMaxAndTransfer_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockup.withdrawMaxAndTransfer, (defaultStreamId, users.alice)); + bytes memory callData = + abi.encodeCall(ISablierLockupBase.withdrawMaxAndTransfer, (defaultStreamId, users.alice)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNoDelegateCall { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.withdrawMaxAndTransfer({ streamId: nullStreamId, newRecipient: users.recipient }); } function test_RevertGiven_NonTransferableStream() external whenCallerRecipient whenNoDelegateCall givenNotNull { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_NotTransferable.selector, notTransferableStreamId)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_NotTransferable.selector, notTransferableStreamId) + ); lockup.withdrawMaxAndTransfer({ streamId: notTransferableStreamId, newRecipient: users.recipient }); } @@ -79,7 +81,9 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integratio resetPrank({ msgSender: users.eve }); // It should revert. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Unauthorized.selector, defaultStreamId, users.eve)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_Unauthorized.selector, defaultStreamId, users.eve) + ); lockup.withdrawMaxAndTransfer({ streamId: defaultStreamId, newRecipient: users.eve }); } @@ -105,7 +109,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integratio // It should emit {Transfer} and {WithdrawFromLockupStream} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, amount: expectedWithdrawnAmount, @@ -148,7 +152,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Concrete_Test is Integratio // It should emit {Transfer}, {WithdrawFromLockupStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, amount: expectedWithdrawnAmount, diff --git a/test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree b/test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree rename to test/core/integration/concrete/lockup-base/withdraw-max-and-transfer/withdrawMaxAndTransfer.tree diff --git a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol b/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol similarity index 94% rename from test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol rename to test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol index f3303ce16..1d010c91f 100644 --- a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../../Integration.t.sol"; @@ -16,7 +16,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test { // It should emit a {WithdrawFromLockupStream} event. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, amount: defaults.DEPOSIT_AMOUNT(), @@ -62,7 +62,7 @@ abstract contract WithdrawMax_Integration_Concrete_Test is Integration_Test { // It should emit a {WithdrawFromLockupStream} event. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, amount: expectedWithdrawnAmount, diff --git a/test/core/integration/concrete/lockup/withdraw-max/withdrawMax.tree b/test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdraw-max/withdrawMax.tree rename to test/core/integration/concrete/lockup-base/withdraw-max/withdrawMax.tree diff --git a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol b/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol similarity index 53% rename from test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol rename to test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol index 5f3b3e004..8b8391228 100644 --- a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.t.sol @@ -2,19 +2,25 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { WithdrawMultiple_Integration_Shared_Test } from "./../../../shared/lockup/withdrawMultiple.t.sol"; +import { Integration_Test } from "../../../Integration.t.sol"; + +abstract contract WithdrawMultiple_Integration_Concrete_Test is Integration_Test { + address internal caller; + + // The original time when the tests started. + uint40 internal originalTime; -abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple_Integration_Shared_Test { function setUp() public virtual override { - WithdrawMultiple_Integration_Shared_Test.setUp(); + originalTime = getBlockTimestamp(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = abi.encodeCall(ISablierLockup.withdrawMultiple, (testStreamIds, testAmounts)); + bytes memory callData = + abi.encodeCall(ISablierLockupBase.withdrawMultiple, (withdrawMultipleStreamIds, withdrawAmounts)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -24,7 +30,7 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple uint128[] memory amounts = new uint128[](1); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_WithdrawArrayCountsNotEqual.selector, streamIds.length, amounts.length + Errors.SablierLockupBase_WithdrawArrayCountsNotEqual.selector, streamIds.length, amounts.length ) ); lockup.withdrawMultiple(streamIds, amounts); @@ -44,17 +50,17 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple whenEqualArraysLength whenNonZeroArrayLength { - uint256 nullStreamId = 1729; - uint256[] memory streamIds = Solarray.uint256s(testStreamIds[0], testStreamIds[1], nullStreamId); + uint256[] memory streamIds = + Solarray.uint256s(withdrawMultipleStreamIds[0], withdrawMultipleStreamIds[1], nullStreamId); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // It should revert. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); // Withdraw from multiple streams. - lockup.withdrawMultiple({ streamIds: streamIds, amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: streamIds, amounts: withdrawAmounts }); } function test_RevertGiven_AtleastOneDEPLETEDStream() @@ -68,13 +74,15 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple vm.warp({ newTimestamp: defaults.END_TIME() }); // Deplete the first test stream. - lockup.withdrawMax({ streamId: testStreamIds[0], to: users.recipient }); + lockup.withdrawMax({ streamId: withdrawMultipleStreamIds[0], to: users.recipient }); // It should revert. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, testStreamIds[0])); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, withdrawMultipleStreamIds[0]) + ); // Withdraw from multiple streams. - lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: withdrawMultipleStreamIds, amounts: withdrawAmounts }); } function test_RevertWhen_AtleastOneZeroAmount() @@ -92,8 +100,10 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple uint128[] memory amounts = Solarray.uint128s(defaults.WITHDRAW_AMOUNT(), 0, 0); // It should revert. - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawAmountZero.selector, testStreamIds[1])); - lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_WithdrawAmountZero.selector, withdrawMultipleStreamIds[1]) + ); + lockup.withdrawMultiple({ streamIds: withdrawMultipleStreamIds, amounts: amounts }); } function test_RevertWhen_AtleastOneAmountOverdraws() @@ -109,16 +119,19 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Run the test. - uint128 withdrawableAmount = lockup.withdrawableAmountOf(testStreamIds[2]); - uint128[] memory amounts = Solarray.uint128s(testAmounts[0], testAmounts[1], MAX_UINT128); + uint128 withdrawableAmount = lockup.withdrawableAmountOf(withdrawMultipleStreamIds[2]); + uint128[] memory amounts = Solarray.uint128s(withdrawAmounts[0], withdrawAmounts[1], MAX_UINT128); // It should revert. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_Overdraw.selector, testStreamIds[2], MAX_UINT128, withdrawableAmount + Errors.SablierLockupBase_Overdraw.selector, + withdrawMultipleStreamIds[2], + MAX_UINT128, + withdrawableAmount ) ); - lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: amounts }); + lockup.withdrawMultiple({ streamIds: withdrawMultipleStreamIds, amounts: amounts }); } function test_WhenNoAmountsOverdraw() @@ -131,59 +144,59 @@ abstract contract WithdrawMultiple_Integration_Concrete_Test is WithdrawMultiple whenNoZeroAmounts { // Simulate the passage of time. - vm.warp({ newTimestamp: earlyStopTime }); + vm.warp({ newTimestamp: defaults.WARP_26_PERCENT() }); // Cancel the 3rd stream. resetPrank({ msgSender: users.sender }); - lockup.cancel(testStreamIds[2]); + lockup.cancel(withdrawMultipleStreamIds[2]); - // Run the test with the caller provided in {whenCallerAuthorizedAllStreams}. + // Run the test with the caller provided in {whenCallerAuthorizedForAllStreams}. resetPrank({ msgSender: caller }); // It should make the withdrawals. - expectCallToTransfer({ to: users.recipient, value: testAmounts[0] }); - expectCallToTransfer({ to: users.recipient, value: testAmounts[1] }); - expectCallToTransfer({ to: users.recipient, value: testAmounts[2] }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmounts[0] }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmounts[1] }); + expectCallToTransfer({ to: users.recipient, value: withdrawAmounts[2] }); // It should emit multiple {WithdrawFromLockupStream} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ - streamId: testStreamIds[0], + emit ISablierLockupBase.WithdrawFromLockupStream({ + streamId: withdrawMultipleStreamIds[0], to: users.recipient, asset: dai, - amount: testAmounts[0] + amount: withdrawAmounts[0] }); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ - streamId: testStreamIds[1], + emit ISablierLockupBase.WithdrawFromLockupStream({ + streamId: withdrawMultipleStreamIds[1], to: users.recipient, asset: dai, - amount: testAmounts[1] + amount: withdrawAmounts[1] }); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ - streamId: testStreamIds[2], + emit ISablierLockupBase.WithdrawFromLockupStream({ + streamId: withdrawMultipleStreamIds[2], to: users.recipient, asset: dai, - amount: testAmounts[2] + amount: withdrawAmounts[2] }); // Make the withdrawals. - lockup.withdrawMultiple({ streamIds: testStreamIds, amounts: testAmounts }); + lockup.withdrawMultiple({ streamIds: withdrawMultipleStreamIds, amounts: withdrawAmounts }); // It should update the statuses. - assertEq(lockup.statusOf(testStreamIds[0]), Lockup.Status.STREAMING, "status0"); - assertEq(lockup.statusOf(testStreamIds[1]), Lockup.Status.DEPLETED, "status1"); - assertEq(lockup.statusOf(testStreamIds[2]), Lockup.Status.CANCELED, "status2"); + assertEq(lockup.statusOf(withdrawMultipleStreamIds[0]), Lockup.Status.STREAMING, "status0"); + assertEq(lockup.statusOf(withdrawMultipleStreamIds[1]), Lockup.Status.DEPLETED, "status1"); + assertEq(lockup.statusOf(withdrawMultipleStreamIds[2]), Lockup.Status.CANCELED, "status2"); // It should update the withdrawn amounts. - assertEq(lockup.getWithdrawnAmount(testStreamIds[0]), testAmounts[0], "withdrawnAmount0"); - assertEq(lockup.getWithdrawnAmount(testStreamIds[1]), testAmounts[1], "withdrawnAmount1"); - assertEq(lockup.getWithdrawnAmount(testStreamIds[2]), testAmounts[2], "withdrawnAmount2"); + assertEq(lockup.getWithdrawnAmount(withdrawMultipleStreamIds[0]), withdrawAmounts[0], "withdrawnAmount0"); + assertEq(lockup.getWithdrawnAmount(withdrawMultipleStreamIds[1]), withdrawAmounts[1], "withdrawnAmount1"); + assertEq(lockup.getWithdrawnAmount(withdrawMultipleStreamIds[2]), withdrawAmounts[2], "withdrawnAmount2"); // Assert that the stream NFTs have not been burned. - assertEq(lockup.getRecipient(testStreamIds[0]), users.recipient, "NFT owner0"); - assertEq(lockup.getRecipient(testStreamIds[1]), users.recipient, "NFT owner1"); - assertEq(lockup.getRecipient(testStreamIds[2]), users.recipient, "NFT owner2"); + assertEq(lockup.getRecipient(withdrawMultipleStreamIds[0]), users.recipient, "NFT owner0"); + assertEq(lockup.getRecipient(withdrawMultipleStreamIds[1]), users.recipient, "NFT owner1"); + assertEq(lockup.getRecipient(withdrawMultipleStreamIds[2]), users.recipient, "NFT owner2"); } } diff --git a/test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree b/test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdraw-multiple/withdrawMultiple.tree rename to test/core/integration/concrete/lockup-base/withdraw-multiple/withdrawMultiple.tree diff --git a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol b/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol similarity index 85% rename from test/core/integration/concrete/lockup/withdraw/withdraw.t.sol rename to test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol index b6c2740b3..e6ed09f11 100644 --- a/test/core/integration/concrete/lockup/withdraw/withdraw.t.sol +++ b/test/core/integration/concrete/lockup-base/withdraw/withdraw.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; import { Errors } from "src/core/libraries/Errors.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; @@ -16,15 +16,14 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { function test_RevertWhen_DelegateCall() external { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); bytes memory callData = - abi.encodeCall(ISablierLockup.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); + abi.encodeCall(ISablierLockupBase.withdraw, (defaultStreamId, users.recipient, withdrawAmount)); (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertGiven_Null() external whenNoDelegateCall { - uint256 nullStreamId = 1729; uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.withdraw({ streamId: nullStreamId, to: users.recipient, amount: withdrawAmount }); } @@ -33,13 +32,15 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { lockup.withdrawMax({ streamId: defaultStreamId, to: users.recipient }); uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_StreamDepleted.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_StreamDepleted.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: withdrawAmount }); } function test_RevertWhen_WithdrawalAddressZero() external whenNoDelegateCall givenNotNull givenNotDEPLETEDStatus { uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawToZeroAddress.selector, defaultStreamId)); + vm.expectRevert( + abi.encodeWithSelector(Errors.SablierLockupBase_WithdrawToZeroAddress.selector, defaultStreamId) + ); lockup.withdraw({ streamId: defaultStreamId, to: address(0), amount: withdrawAmount }); } @@ -50,7 +51,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { givenNotDEPLETEDStatus whenWithdrawalAddressNotZero { - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_WithdrawAmountZero.selector, defaultStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_WithdrawAmountZero.selector, defaultStreamId)); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: 0 }); } @@ -65,7 +66,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { uint128 withdrawableAmount = 0; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount + Errors.SablierLockupBase_Overdraw.selector, defaultStreamId, MAX_UINT128, withdrawableAmount ) ); lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: MAX_UINT128 }); @@ -120,7 +121,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { // It should revert. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockup_WithdrawalAddressNotRecipient.selector, defaultStreamId, caller, users.alice + Errors.SablierLockupBase_WithdrawalAddressNotRecipient.selector, defaultStreamId, caller, users.alice ) ); lockup.withdraw({ streamId: defaultStreamId, to: users.alice, amount: withdrawAmount }); @@ -146,7 +147,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { // It should emit {WithdrawFromLockupStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.alice, asset: dai, @@ -265,7 +266,7 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { // It should emit {WithdrawFromLockupStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, asset: dai, @@ -306,25 +307,22 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { givenEndTimeInFuture givenNotCanceledStream { - // Create the stream with a recipient contract that implements {ISablierLockupRecipient}. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // It should not make Sablier run the recipient hook. - uint128 withdrawAmount = lockup.withdrawableAmountOf(streamId); + uint128 withdrawAmount = lockup.withdrawableAmountOf(recipientGoodStreamId); vm.expectCall({ callee: address(recipientGood), data: abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, users.sender, address(recipientGood), withdrawAmount) + (recipientGoodStreamId, users.sender, address(recipientGood), withdrawAmount) ), count: 0 }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ streamId: recipientGoodStreamId, to: address(recipientGood), amount: withdrawAmount }); // It should update the withdrawn amount. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(recipientGoodStreamId); uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } @@ -348,15 +346,12 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientReverting)); resetPrank({ msgSender: users.sender }); - // Create the stream with a reverting contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientReverting)); - // Expect a revert. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert("You shall not pass"); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientReverting), amount: withdrawAmount }); + lockup.withdraw({ streamId: recipientRevertStreamId, to: address(recipientReverting), amount: withdrawAmount }); } function test_RevertWhen_HookReturnsInvalidSelector() @@ -379,17 +374,20 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientInvalidSelector)); resetPrank({ msgSender: users.sender }); - // Create the stream with a recipient contract that returns invalid selector bytes on the hook call. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientInvalidSelector)); - // Expect a revert. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockup_InvalidHookSelector.selector, address(recipientInvalidSelector)) + abi.encodeWithSelector( + Errors.SablierLockupBase_InvalidHookSelector.selector, address(recipientInvalidSelector) + ) ); // Cancel the stream. - lockup.withdraw({ streamId: streamId, to: address(recipientInvalidSelector), amount: withdrawAmount }); + lockup.withdraw({ + streamId: recipientInvalidSelectorStreamId, + to: address(recipientInvalidSelector), + amount: withdrawAmount + }); } function test_WhenReentrancy() @@ -413,9 +411,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientReentrant)); resetPrank({ msgSender: users.sender }); - // Create the stream with a reentrant contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientReentrant)); - // Halve the withdraw amount so that the recipient can re-entry and make another withdrawal. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT() / 2; @@ -424,20 +419,20 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { address(recipientReentrant), abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, users.sender, address(recipientReentrant), withdrawAmount) + (recipientReentrantStreamId, users.sender, address(recipientReentrant), withdrawAmount) ) ); // It should make multiple withdrawals. - lockup.withdraw({ streamId: streamId, to: address(recipientReentrant), amount: withdrawAmount }); + lockup.withdraw({ streamId: recipientReentrantStreamId, to: address(recipientReentrant), amount: withdrawAmount }); // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientReentrantStreamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // It should update the withdrawn amounts. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(recipientReentrantStreamId); uint128 expectedWithdrawnAmount = defaults.WITHDRAW_AMOUNT(); assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } @@ -463,9 +458,6 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { lockup.allowToHook(address(recipientGood)); resetPrank({ msgSender: users.sender }); - // Create the stream with a contract as the stream's recipient. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // Set the withdraw amount to the default amount. uint128 withdrawAmount = defaults.WITHDRAW_AMOUNT(); @@ -477,31 +469,31 @@ abstract contract Withdraw_Integration_Concrete_Test is Integration_Test { address(recipientGood), abi.encodeCall( ISablierLockupRecipient.onSablierLockupWithdraw, - (streamId, users.sender, address(recipientGood), withdrawAmount) + (recipientGoodStreamId, users.sender, address(recipientGood), withdrawAmount) ) ); // It should emit {WithdrawFromLockupStream} and {MetadataUpdate} events. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ - streamId: streamId, + emit ISablierLockupBase.WithdrawFromLockupStream({ + streamId: recipientGoodStreamId, to: address(recipientGood), asset: dai, amount: withdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: recipientGoodStreamId }); // Make the withdrawal. - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ streamId: recipientGoodStreamId, to: address(recipientGood), amount: withdrawAmount }); // Assert that the stream's status is still "STREAMING". - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientGoodStreamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // It should update the withdrawn amount. - uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(streamId); + uint128 actualWithdrawnAmount = lockup.getWithdrawnAmount(recipientGoodStreamId); uint128 expectedWithdrawnAmount = withdrawAmount; assertEq(actualWithdrawnAmount, expectedWithdrawnAmount, "withdrawnAmount"); } diff --git a/test/core/integration/concrete/lockup/withdraw/withdraw.tree b/test/core/integration/concrete/lockup-base/withdraw/withdraw.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdraw/withdraw.tree rename to test/core/integration/concrete/lockup-base/withdraw/withdraw.tree diff --git a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol b/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol similarity index 97% rename from test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol rename to test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol index 2a351c3cd..e8ed734f0 100644 --- a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol +++ b/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol @@ -7,8 +7,7 @@ import { Integration_Test } from "../../../Integration.t.sol"; abstract contract WithdrawableAmountOf_Integration_Concrete_Test is Integration_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); lockup.withdrawableAmountOf(nullStreamId); } diff --git a/test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.tree similarity index 100% rename from test/core/integration/concrete/lockup/withdrawable-amount-of/withdrawableAmountOf.tree rename to test/core/integration/concrete/lockup-base/withdrawable-amount-of/withdrawableAmountOf.tree diff --git a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol index e81619a3f..62079c239 100644 --- a/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/LockupDynamic.t.sol @@ -2,339 +2,366 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "./../../Integration.t.sol"; -import { LockupDynamic_Integration_Shared_Test } from "./../../shared/lockup-dynamic/LockupDynamic.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { Cancel_Integration_Concrete_Test } from "./../lockup/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from "./../lockup/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from "./../lockup/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from "./../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup/is-warm/isWarm.t.sol"; -import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup/refundable-amount-of/refundableAmountOf.t.sol"; -import { Renounce_Integration_Concrete_Test } from "./../lockup/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup/withdraw-hooks/withdrawHooks.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/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup/withdraw-multiple/withdrawMultiple.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "./../lockup/withdraw/withdraw.t.sol"; + "./../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_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract AllowToHook_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, AllowToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract Batch_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract Batch_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, Batch_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract Burn_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract Burn_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, Burn_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract Cancel_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract Cancel_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, Cancel_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +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(LockupDynamic_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) + override(Lockup_Dynamic_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); CancelMultiple_Integration_Concrete_Test.setUp(); } } -contract GetAsset_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetAsset_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetAsset_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetDepositedAmount_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetDepositedAmount_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetDepositedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetEndTime_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetEndTime_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetEndTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetRecipient_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetRecipient_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetRecipient_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetRefundedAmount_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetRefundedAmount_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetRefundedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetSender_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetSender_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetSender_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetStartTime_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetStartTime_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetStartTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract GetWithdrawnAmount_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, GetWithdrawnAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsAllowedToHook_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsAllowedToHook_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsAllowedToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsCancelable_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsCancelable_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsCancelable_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsCold_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsCold_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsCold_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsDepleted_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsDepleted_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsDepleted_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsStream_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsStream_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsStream_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsTransferable_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsTransferable_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsTransferable_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract IsWarm_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract IsWarm_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, IsWarm_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract RefundableAmountOf_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract RefundableAmountOf_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, RefundableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract Renounce_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract Renounce_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, Renounce_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract SetNFTDescriptor_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, SetNFTDescriptor_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract StatusOf_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract StatusOf_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, StatusOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract TransferFrom_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract TransferFrom_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test { function setUp() public virtual - override(LockupDynamic_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) + override(Lockup_Dynamic_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); TransferFrom_Integration_Concrete_Test.setUp(); } } -contract WasCanceled_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract WasCanceled_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, WasCanceled_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract Withdraw_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract Withdraw_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, Withdraw_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawHooks_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawHooks_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test { function setUp() public virtual - override(LockupDynamic_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) + override(Lockup_Dynamic_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); WithdrawHooks_Integration_Concrete_Test.setUp(); } } -contract WithdrawMax_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawMax_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawMax_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +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(LockupDynamic_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) + override(Lockup_Dynamic_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); WithdrawMultiple_Integration_Concrete_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol b/test/core/integration/concrete/lockup-dynamic/constructor.t.sol deleted file mode 100644 index 4b966706d..000000000 --- a/test/core/integration/concrete/lockup-dynamic/constructor.t.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { IAdminable } from "src/core/interfaces/IAdminable.sol"; -import { SablierLockupDynamic } from "src/core/SablierLockupDynamic.sol"; - -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; - -contract Constructor_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { - function test_Constructor() external { - // Expect the relevant event to be emitted. - vm.expectEmit(); - emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); - - // Construct the contract. - SablierLockupDynamic constructedLockupDynamic = new SablierLockupDynamic({ - initialAdmin: users.admin, - initialNFTDescriptor: nftDescriptor, - maxSegmentCount: defaults.MAX_SEGMENT_COUNT() - }); - - // {SablierLockup.constant} - UD60x18 actualMaxBrokerFee = constructedLockupDynamic.MAX_BROKER_FEE(); - UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); - assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - - // {SablierLockup.constructor} - address actualAdmin = constructedLockupDynamic.admin(); - address expectedAdmin = users.admin; - assertEq(actualAdmin, expectedAdmin, "admin"); - - uint256 actualStreamId = constructedLockupDynamic.nextStreamId(); - uint256 expectedStreamId = 1; - assertEq(actualStreamId, expectedStreamId, "nextStreamId"); - - address actualNFTDescriptor = address(constructedLockupDynamic.nftDescriptor()); - address expectedNFTDescriptor = address(nftDescriptor); - assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - - // {SablierLockup.supportsInterface} - assertTrue(constructedLockupDynamic.supportsInterface(0x49064906), "ERC-4906 interface ID"); - - // {SablierLockupDynamic.constructor} - uint256 actualMaxSegmentCount = constructedLockupDynamic.MAX_SEGMENT_COUNT(); - uint256 expectedMaxSegmentCount = defaults.MAX_SEGMENT_COUNT(); - assertEq(actualMaxSegmentCount, expectedMaxSegmentCount, "MAX_SEGMENT_COUNT"); - } -} diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol similarity index 67% rename from test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol index 0f560373f..6191ad777 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.t.sol @@ -4,31 +4,32 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +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 { LockupDynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; -contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithDurationsLD_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupDynamic_Integration_Shared_Test.setUp(); - streamId = lockupDynamic.nextStreamId(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupDynamic.createWithDurations, defaults.createWithDurationsLD()); - (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); + bytes memory callData = abi.encodeCall( + ISablierLockup.createWithDurationsLD, (defaults.createWithDurations(), defaults.segmentsWithDurations()) + ); + (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertWhen_SegmentCountExceedsMaxValue() external whenNoDelegateCall { LockupDynamic.SegmentWithDuration[] memory segments = new LockupDynamic.SegmentWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupDynamic_SegmentCountTooHigh.selector, 25_000)); - createDefaultStreamWithDurations(segments); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, 25_000)); + createDefaultStreamWithDurationsLD(segments); } function test_RevertWhen_FirstIndexHasZeroDuration() @@ -37,18 +38,18 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy whenSegmentCountNotExceedMaxValue { uint40 startTime = getBlockTimestamp(); - LockupDynamic.SegmentWithDuration[] memory segments = defaults.createWithDurationsLD().segments; + LockupDynamic.SegmentWithDuration[] memory segments = defaults.segmentsWithDurations(); segments[1].duration = 0; uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, index, startTime + segments[0].duration, startTime + segments[0].duration ) ); - createDefaultStreamWithDurations(segments); + createDefaultStreamWithDurationsLD(segments); } function test_RevertWhen_StartTimeExceedsFirstTimestamp() @@ -64,12 +65,12 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy segments[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, startTime, startTime + segments[0].duration ) ); - createDefaultStreamWithDurations(segments); + createDefaultStreamWithDurationsLD(segments); } } @@ -98,7 +99,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, index, startTime + segments[0].duration, startTime + segments[0].duration + segments[1].duration @@ -106,7 +107,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy ); // Create the stream. - createDefaultStreamWithDurations(segments); + createDefaultStreamWithDurationsLD(segments); } } @@ -121,8 +122,8 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupDynamic.Timestamps memory timestamps = - LockupDynamic.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: blockTimestamp, cliff: 0, end: blockTimestamp + defaults.TOTAL_DURATION() }); // Adjust the segments. LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); @@ -131,16 +132,16 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy segments[1].timestamp = segments[0].timestamp + segmentsWithDurations[1].duration; // It should perform the ERC-20 transfers. - expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: defaults.DEPOSIT_AMOUNT() }); + 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() }); // It should emit {CreateLockupDynamicStream} and {MetadataUpdate} events. - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupDynamic) }); - emit ISablierLockupDynamic.CreateLockupDynamicStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupDynamicStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -155,28 +156,34 @@ contract CreateWithDurations_LockupDynamic_Integration_Concrete_Test is LockupDy }); // Create the stream. - createDefaultStreamWithDurations(); - - // It should create the stream. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); - expectedStream.endTime = timestamps.end; - expectedStream.segments = segments; - expectedStream.startTime = timestamps.start; - assertEq(actualStream, expectedStream); + createDefaultStreamWithDurationsLD(); + + // 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.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getSegments(streamId), segments, "segments"); // Assert that the stream's status is "STREAMING". - Lockup.Status actualStatus = lockupDynamic.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupDynamic.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.tree similarity index 94% rename from test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.tree index 7d5286cc9..44d129842 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurations.tree +++ b/test/core/integration/concrete/lockup-dynamic/create-with-durations/createWithDurationsLD.tree @@ -1,4 +1,4 @@ -CreateWithDurations_LockupDynamic_Integration_Concrete_Test +CreateWithDurationsLD_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol similarity index 74% rename from test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol index 2be5379e7..e0edc60a9 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.t.sol @@ -7,35 +7,36 @@ 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 { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.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 { LockupDynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; -contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithTimestampsLD_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupDynamic_Integration_Shared_Test.setUp(); - streamId = lockupDynamic.nextStreamId(); + Lockup_Dynamic_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, defaults.createWithTimestampsLD()); - (bool success, bytes memory returnData) = address(lockupDynamic).delegatecall(callData); + 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); - createDefaultStreamWithSender(address(0)); + createDefaultStreamWithSenderLD(address(0)); } function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { address recipient = address(0); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipient(recipient); + createDefaultStreamWithRecipientLD(recipient); } function test_RevertWhen_DepositAmountZero() @@ -48,7 +49,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD // is hard coded to 10%. vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); uint128 totalAmount = 0; - createDefaultStreamWithTotalAmount(totalAmount); + createDefaultStreamWithTotalAmountLD(totalAmount); } function test_RevertWhen_StartTimeZero() @@ -59,7 +60,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD whenDepositAmountNotZero { vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithStartTime(0); + createDefaultStreamWithStartTimeLD(0); } function test_RevertWhen_SegmentCountZero() @@ -71,8 +72,8 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD whenStartTimeNotZero { LockupDynamic.Segment[] memory segments; - vm.expectRevert(Errors.SablierLockupDynamic_SegmentCountZero.selector); - createDefaultStreamWithSegments(segments); + vm.expectRevert(Errors.SablierLockup_SegmentCountZero.selector); + createDefaultStreamWithSegmentsLD(segments); } function test_RevertWhen_SegmentCountExceedsMaxValue() @@ -84,10 +85,11 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD whenStartTimeNotZero whenSegmentCountNotZero { - uint256 segmentCount = defaults.MAX_SEGMENT_COUNT() + 1; + uint256 segmentCount = defaults.MAX_COUNT() + 1; LockupDynamic.Segment[] memory segments = new LockupDynamic.Segment[](segmentCount); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupDynamic_SegmentCountTooHigh.selector, segmentCount)); - createDefaultStreamWithSegments(segments); + segments[segmentCount - 1].timestamp = defaults.END_TIME(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, segmentCount)); + createDefaultStreamWithSegmentsLD(segments); } function test_RevertWhen_SegmentAmountsSumOverflows() @@ -104,7 +106,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD segments[0].amount = MAX_UINT128; segments[1].amount = 1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithSegments(segments); + createDefaultStreamWithSegmentsLD(segments); } function test_RevertWhen_StartTimeGreaterThanFirstTimestamp() @@ -125,14 +127,14 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) ); // Create the stream. - createDefaultStreamWithSegments(segments); + createDefaultStreamWithSegmentsLD(segments); } function test_RevertWhen_StartTimeEqualsFirstTimestamp() @@ -153,14 +155,14 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) ); // Create the stream. - createDefaultStreamWithSegments(segments); + createDefaultStreamWithSegmentsLD(segments); } function test_RevertWhen_TimestampsNotStrictlyIncreasing() @@ -179,11 +181,13 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD 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.SablierLockupDynamic_SegmentTimestampsNotOrdered.selector, + Errors.SablierLockup_SegmentTimestampsNotOrdered.selector, index, segments[0].timestamp, segments[1].timestamp @@ -191,7 +195,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD ); // Create the stream. - createDefaultStreamWithSegments(segments); + lockup.createWithTimestampsLD(params, segments); } function test_RevertWhen_DepositAmountNotEqualSegmentAmountsSum() @@ -214,20 +218,22 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; + LockupDynamic.Segment[] memory segments = defaults.segments(); + // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierLockup_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) ); // Create the stream. - lockupDynamic.createWithTimestamps(params); + lockup.createWithTimestampsLD(params, segments); } function test_RevertWhen_BrokerFeeExceedsMaxValue() @@ -248,7 +254,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); + createDefaultStreamWithBrokerLD(Broker({ account: users.broker, fee: brokerFee })); } function test_RevertWhen_AssetNotContract() @@ -272,7 +278,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD // Run the test. vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAsset(IERC20(nonContract)); + createDefaultStreamWithAssetLD(IERC20(nonContract)); } function test_WhenAssetMissesERC20ReturnValue() @@ -291,7 +297,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD whenBrokerFeeNotExceedMaxValue whenAssetContract { - testCreateWithTimestamps(address(usdt)); + _testCreateWithTimestampsLD(address(usdt)); } function test_WhenAssetNotMissERC20ReturnValue() @@ -310,11 +316,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD whenBrokerFeeNotExceedMaxValue whenAssetContract { - testCreateWithTimestamps(address(dai)); + _testCreateWithTimestampsLD(address(dai)); } - /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. - function testCreateWithTimestamps(address asset) internal { + function _testCreateWithTimestampsLD(address asset) private { // Make the Sender the stream's funder. address funder = users.sender; @@ -322,7 +327,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD expectCallToTransferFrom({ asset: IERC20(asset), from: funder, - to: address(lockupDynamic), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); @@ -335,10 +340,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD }); // It should emit {CreateLockupDynamicStream} and {MetadataUpdate} events. - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupDynamic) }); - emit ISablierLockupDynamic.CreateLockupDynamicStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupDynamicStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -353,26 +358,34 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test is LockupD }); // Create the stream. - streamId = createDefaultStreamWithAsset(IERC20(asset)); + streamId = createDefaultStreamWithAssetLD(IERC20(asset)); // It should create the stream. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); - expectedStream.asset = IERC20(asset); - assertEq(actualStream, expectedStream); + 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.getSegments(streamId), defaults.segments(), "segments"); // Assert that the stream's status is "PENDING". - Lockup.Status actualStatus = lockupDynamic.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupDynamic.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree similarity index 98% rename from test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree index 8b4a2bc17..a827ea774 100644 --- a/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-dynamic/create-with-timestamps/createWithTimestampsLD.tree @@ -1,4 +1,4 @@ -CreateWithTimestamps_LockupDynamic_Integration_Concrete_Test +CreateWithTimestampsLD_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call 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 929b0a398..8b872b286 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 @@ -3,18 +3,16 @@ 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 { LockupDynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; -contract GetSegments_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { +contract GetSegments_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupDynamic.getSegments(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getSegments(nullStreamId); } function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - LockupDynamic.Segment[] memory actualSegments = lockupDynamic.getSegments(streamId); + 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 92e6a6b63..6b662caff 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree +++ b/test/core/integration/concrete/lockup-dynamic/get-segments/getSegments.tree @@ -1,4 +1,4 @@ -GetSegments_LockupDynamic_Integration_Concrete_Test +GetSegments_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null diff --git a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol deleted file mode 100644 index 7b7da2991..000000000 --- a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.t.sol +++ /dev/null @@ -1,35 +0,0 @@ -// 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 { LockupDynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; - -contract GetStream_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { - function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupDynamic.getStream(nullStreamId); - } - - function test_GivenSettledStream() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - - // It should return the stream struct. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(defaultStreamId); - LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); - // It should always return stream as non-cancelable. - expectedStream.isCancelable = false; - assertEq(actualStream, expectedStream); - } - - function test_GivenNotSettledStream() external givenNotNull { - uint256 streamId = createDefaultStream(); - - // It should return the stream struct. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); - LockupDynamic.StreamLD memory expectedStream = defaults.lockupDynamicStream(); - assertEq(actualStream, expectedStream); - } -} diff --git a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree b/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree deleted file mode 100644 index 2a410a0ba..000000000 --- a/test/core/integration/concrete/lockup-dynamic/get-stream/getStream.tree +++ /dev/null @@ -1,9 +0,0 @@ -GetStream_LockupDynamic_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given settled stream - │ ├── it should always return stream as non-cancelable - │ └── it should return the stream struct - └── given not settled stream - └── it should return the stream struct diff --git a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol index 70e78ef9a..98bfe1da1 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.t.sol @@ -2,21 +2,19 @@ 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 } from "src/core/types/DataTypes.sol"; -import { LockupDynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../LockupDynamic.t.sol"; -contract GetTimestamps_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { +contract GetTimestamps_Lockup_Dynamic_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupDynamic.getTimestamps(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getTimestamps(nullStreamId); } function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - LockupDynamic.Timestamps memory actualTimestamps = lockupDynamic.getTimestamps(streamId); - LockupDynamic.Timestamps memory expectedTimestamps = defaults.lockupDynamicTimestamps(); + 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 index 2b419073b..245182d2b 100644 --- a/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree +++ b/test/core/integration/concrete/lockup-dynamic/get-timestamps/getTimestamps.tree @@ -1,4 +1,4 @@ -GetTimestamps_LockupDynamic_Integration_Concrete_Test +GetTimestamps_Lockup_Dynamic_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null 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 1e3112329..ff7923c88 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,26 +2,27 @@ pragma solidity >=0.8.22 <0.9.0; import { LockupDynamic } from "src/core/types/DataTypes.sol"; -import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; -import { LockupDynamic_Integration_Shared_Test, Integration_Test } from "./../LockupDynamic.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_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract StreamedAmountOf_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, StreamedAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() }); - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); assertEq(actualStreamedAmount, 0, "streamedAmount"); } function test_GivenEndTimeNotInFuture() external givenSTREAMINGStatus givenStartTimeInPast { vm.warp({ newTimestamp: defaults.END_TIME() + 1 }); - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -39,10 +40,10 @@ contract StreamedAmountOf_LockupDynamic_Integration_Concrete_Test is }); // Create the stream. - uint256 streamId = createDefaultStreamWithSegments(segments); + uint256 streamId = createDefaultStreamWithSegmentsLD(segments); // It should return the correct streamed amount. - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = 4472.13595499957941e18; // (0.2^0.5)*10,000 assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -52,7 +53,7 @@ contract StreamedAmountOf_LockupDynamic_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 750 seconds }); // It should return the correct streamed amount. - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.segments()[0].amount + 2371.708245126284505e18; // ~7,500*0.1^{0.5} assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree index 6694f6f6b..2d31b7ac5 100644 --- a/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree +++ b/test/core/integration/concrete/lockup-dynamic/streamed-amount-of/streamedAmountOf.tree @@ -1,4 +1,4 @@ -StreamedAmountOf_LockupDynamic_Integration_Concrete_Test +StreamedAmountOf_Lockup_Dynamic_Integration_Concrete_Test └── given STREAMING status ├── given start time in present │ └── it should return zero 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 f637d0392..aec623b5c 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 { LockupDynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "../LockupDynamic.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,12 +16,12 @@ import { LockupDynamic_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_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integration_Shared_Test { - address internal constant LOCKUP_DYNAMIC = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; +contract TokenURI_Lockup_Dynamic_Integration_Concrete_Test is Lockup_Dynamic_Integration_Shared_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. modifier skipOnMismatch() { - if (address(lockupDynamic) == LOCKUP_DYNAMIC) { + if (address(lockup) == LOCKUP) { _; } else { console2.log(StdStyle.yellow('Warning: "LockupDynamic.tokenURI" tests skipped due to address mismatch')); @@ -29,9 +29,8 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ } function test_RevertGiven_NFTNotExist() external { - uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); - lockupDynamic.tokenURI({ tokenId: nullStreamId }); + lockup.tokenURI({ tokenId: nullStreamId }); } /// @dev If you need to update the hard-coded token URI: @@ -40,7 +39,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ function test_WhenTokenURIDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory tokenURI = lockupDynamic.tokenURI(defaultStreamId); + string memory tokenURI = lockup.tokenURI(defaultStreamId); tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = @@ -51,7 +50,7 @@ contract TokenURI_LockupDynamic_Integration_Concrete_Test is LockupDynamic_Integ function test_WhenTokenURINotDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory actualTokenURI = lockupDynamic.tokenURI(defaultStreamId); + string memory actualTokenURI = lockup.tokenURI(defaultStreamId); string memory expectedTokenURI = "data:application/json;base64,eyJhdHRyaWJ1dGVzIjpbeyJ0cmFpdF90eXBlIjoiQXNzZXQiLCJ2YWx1ZSI6IkRBSSJ9LHsidHJhaXRfdHlwZSI6IlNlbmRlciIsInZhbHVlIjoiMHg2MzMyZTdiMWRlYjFmMWEwYjc3YjJiYjE4YjE0NDMzMGM3MjkxYmNhIn0seyJ0cmFpdF90eXBlIjoiU3RhdHVzIiwidmFsdWUiOiJTdHJlYW1pbmcifV0sImRlc2NyaXB0aW9uIjoiVGhpcyBORlQgcmVwcmVzZW50cyBhIHBheW1lbnQgc3RyZWFtIGluIGEgU2FibGllciBMb2NrdXAgU2FibGllciBMb2NrdXAgTGluZWFyIGNvbnRyYWN0LiBUaGUgb3duZXIgb2YgdGhpcyBORlQgY2FuIHdpdGhkcmF3IHRoZSBzdHJlYW1lZCBhc3NldHMsIHdoaWNoIGFyZSBkZW5vbWluYXRlZCBpbiBEQUkuXG5cbi0gU3RyZWFtIElEOiAxXG4tIFNhYmxpZXIgTG9ja3VwIExpbmVhciBBZGRyZXNzOiAweDcxYjk4MzdhZTFlMWFjOTk2NzZlNTJhMmJlODJhOTk4OTAwZTgyYzZcbi0gREFJIEFkZHJlc3M6IDB4NTYxNWRlYjc5OGJiM2U0ZGZhMDEzOWRmYTFiM2Q0MzNjYzIzYjcyZlxuXG7imqDvuI8gV0FSTklORzogVHJhbnNmZXJyaW5nIHRoZSBORlQgbWFrZXMgdGhlIG5ldyBvd25lciB0aGUgcmVjaXBpZW50IG9mIHRoZSBzdHJlYW0uIFRoZSBmdW5kcyBhcmUgbm90IGF1dG9tYXRpY2FsbHkgd2l0aGRyYXduIGZvciB0aGUgcHJldmlvdXMgcmVjaXBpZW50LiIsImV4dGVybmFsX3VybCI6Imh0dHBzOi8vc2FibGllci5jb20iLCJuYW1lIjoiU2FibGllciBTYWJsaWVyIExvY2t1cCBMaW5lYXIgIzEiLCJpbWFnZSI6ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QjRiV3h1Y3owaWFIUjBjRG92TDNkM2R5NTNNeTV2Y21jdk1qQXdNQzl6ZG1jaUlIZHBaSFJvUFNJeE1EQXdJaUJvWldsbmFIUTlJakV3TURBaUlIWnBaWGRDYjNnOUlqQWdNQ0F4TURBd0lERXdNREFpUGp4eVpXTjBJSGRwWkhSb1BTSXhNREFsSWlCb1pXbG5hSFE5SWpFd01DVWlJR1pwYkhSbGNqMGlkWEpzS0NOT2IybHpaU2tpTHo0OGNtVmpkQ0I0UFNJM01DSWdlVDBpTnpBaUlIZHBaSFJvUFNJNE5qQWlJR2hsYVdkb2REMGlPRFl3SWlCbWFXeHNQU0lqWm1abUlpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d015SWdjbmc5SWpRMUlpQnllVDBpTkRVaUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMVzl3WVdOcGRIazlJaTR4SWlCemRISnZhMlV0ZDJsa2RHZzlJalFpTHo0OFpHVm1jejQ4WTJseVkyeGxJR2xrUFNKSGJHOTNJaUJ5UFNJMU1EQWlJR1pwYkd3OUluVnliQ2dqVW1Ga2FXRnNSMnh2ZHlraUx6NDhabWxzZEdWeUlHbGtQU0pPYjJselpTSStQR1psUm14dmIyUWdlRDBpTUNJZ2VUMGlNQ0lnZDJsa2RHZzlJakV3TUNVaUlHaGxhV2RvZEQwaU1UQXdKU0lnWm14dmIyUXRZMjlzYjNJOUltaHpiQ2d5TXpBc01qRWxMREV4SlNraUlHWnNiMjlrTFc5d1lXTnBkSGs5SWpFaUlISmxjM1ZzZEQwaVpteHZiMlJHYVd4c0lpOCtQR1psVkhWeVluVnNaVzVqWlNCaVlYTmxSbkpsY1hWbGJtTjVQU0l1TkNJZ2JuVnRUMk4wWVhabGN6MGlNeUlnY21WemRXeDBQU0pPYjJselpTSWdkSGx3WlQwaVpuSmhZM1JoYkU1dmFYTmxJaTgrUEdabFFteGxibVFnYVc0OUlrNXZhWE5sSWlCcGJqSTlJbVpzYjI5a1JtbHNiQ0lnYlc5a1pUMGljMjltZEMxc2FXZG9kQ0l2UGp3dlptbHNkR1Z5UGp4d1lYUm9JR2xrUFNKTWIyZHZJaUJtYVd4c1BTSWpabVptSWlCbWFXeHNMVzl3WVdOcGRIazlJaTR4SWlCa1BTSnRNVE16TGpVMU9Td3hNalF1TURNMFl5MHVNREV6TERJdU5ERXlMVEV1TURVNUxEUXVPRFE0TFRJdU9USXpMRFl1TkRBeUxUSXVOVFU0TERFdU9ERTVMVFV1TVRZNExETXVORE01TFRjdU9EZzRMRFF1T1RrMkxURTBMalEwTERndU1qWXlMVE14TGpBME55d3hNaTQxTmpVdE5EY3VOamMwTERFeUxqVTJPUzA0TGpnMU9DNHdNell0TVRjdU9ETTRMVEV1TWpjeUxUSTJMak15T0MwekxqWTJNeTA1TGpnd05pMHlMamMyTmkweE9TNHdPRGN0Tnk0eE1UTXRNamN1TlRZeUxURXlMamMzT0MweE15NDROREl0T0M0d01qVXNPUzQwTmpndE1qZ3VOakEyTERFMkxqRTFNeTB6TlM0eU5qVm9NR015TGpBek5TMHhMamd6T0N3MExqSTFNaTB6TGpVME5pdzJMalEyTXkwMUxqSXlOR2d3WXpZdU5ESTVMVFV1TmpVMUxERTJMakl4T0MweUxqZ3pOU3d5TUM0ek5UZ3NOQzR4Tnl3MExqRTBNeXcxTGpBMU55dzRMamd4Tml3NUxqWTBPU3d4TXk0NU1pd3hNeTQzTXpSb0xqQXpOMk0xTGpjek5pdzJMalEyTVN3eE5TNHpOVGN0TWk0eU5UTXNPUzR6T0MwNExqUTRMREFzTUMwekxqVXhOUzB6TGpVeE5TMHpMalV4TlMwekxqVXhOUzB4TVM0ME9TMHhNUzQwTnpndE5USXVOalUyTFRVeUxqWTJOQzAyTkM0NE16Y3ROalF1T0RNM2JDNHdORGt0TGpBek4yTXRNUzQzTWpVdE1TNDJNRFl0TWk0M01Ua3RNeTQ0TkRjdE1pNDNOVEV0Tmk0eU1EUm9NR010TGpBME5pMHlMak0zTlN3eExqQTJNaTAwTGpVNE1pd3lMamN5TmkwMkxqSXlPV2d3YkM0eE9EVXRMakUwT0dnd1l5NHdPVGt0TGpBMk1pd3VNakl5TFM0eE5EZ3NMak0zTFM0eU5UbG9NR015TGpBMkxURXVNell5TERNdU9UVXhMVEl1TmpJeExEWXVNRFEwTFRNdU9EUXlRelUzTGpjMk15MHpMalEzTXl3NU55NDNOaTB5TGpNME1Td3hNamd1TmpNM0xERTRMak16TW1NeE5pNDJOekVzT1M0NU5EWXRNall1TXpRMExEVTBMamd4TXkwek9DNDJOVEVzTkRBdU1UazVMVFl1TWprNUxUWXVNRGsyTFRFNExqQTJNeTB4Tnk0M05ETXRNVGt1TmpZNExURTRMamd4TVMwMkxqQXhOaTAwTGpBME55MHhNeTR3TmpFc05DNDNOell0Tnk0M05USXNPUzQzTlRGc05qZ3VNalUwTERZNExqTTNNV014TGpjeU5Dd3hMall3TVN3eUxqY3hOQ3d6TGpnMExESXVOek00TERZdU1Ua3lXaUl2UGp4d1lYUm9JR2xrUFNKR2JHOWhkR2x1WjFSbGVIUWlJR1pwYkd3OUltNXZibVVpSUdROUlrMHhNalVnTkRWb056VXdjemd3SURBZ09EQWdPREIyTnpVd2N6QWdPREFnTFRnd0lEZ3dhQzAzTlRCekxUZ3dJREFnTFRnd0lDMDRNSFl0TnpVd2N6QWdMVGd3SURnd0lDMDRNQ0l2UGp4eVlXUnBZV3hIY21Ga2FXVnVkQ0JwWkQwaVVtRmthV0ZzUjJ4dmR5SStQSE4wYjNBZ2IyWm1jMlYwUFNJd0pTSWdjM1J2Y0MxamIyeHZjajBpYUhOc0tEVXpMRGM1SlN3ME1TVXBJaUJ6ZEc5d0xXOXdZV05wZEhrOUlpNDJJaTgrUEhOMGIzQWdiMlptYzJWMFBTSXhNREFsSWlCemRHOXdMV052Ykc5eVBTSm9jMndvTWpNd0xESXhKU3d4TVNVcElpQnpkRzl3TFc5d1lXTnBkSGs5SWpBaUx6NDhMM0poWkdsaGJFZHlZV1JwWlc1MFBqeHNhVzVsWVhKSGNtRmthV1Z1ZENCcFpEMGlVMkZ1WkZSdmNDSWdlREU5SWpBbElpQjVNVDBpTUNVaVBqeHpkRzl3SUc5bVpuTmxkRDBpTUNVaUlITjBiM0F0WTI5c2IzSTlJbWh6YkNnMU15dzNPU1VzTkRFbEtTSXZQanh6ZEc5d0lHOW1abk5sZEQwaU1UQXdKU0lnYzNSdmNDMWpiMnh2Y2owaWFITnNLREl6TUN3eU1TVXNNVEVsS1NJdlBqd3ZiR2x1WldGeVIzSmhaR2xsYm5RK1BHeHBibVZoY2tkeVlXUnBaVzUwSUdsa1BTSlRZVzVrUW05MGRHOXRJaUI0TVQwaU1UQXdKU0lnZVRFOUlqRXdNQ1VpUGp4emRHOXdJRzltWm5ObGREMGlNVEFsSWlCemRHOXdMV052Ykc5eVBTSm9jMndvTWpNd0xESXhKU3d4TVNVcElpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeE1EQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29OVE1zTnprbExEUXhKU2tpTHo0OFlXNXBiV0YwWlNCaGRIUnlhV0oxZEdWT1lXMWxQU0o0TVNJZ1pIVnlQU0kyY3lJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhaaGJIVmxjejBpTXpBbE96WXdKVHN4TWpBbE96WXdKVHN6TUNVN0lpOCtQQzlzYVc1bFlYSkhjbUZrYVdWdWRENDhiR2x1WldGeVIzSmhaR2xsYm5RZ2FXUTlJa2h2ZFhKbmJHRnpjMU4wY205clpTSWdaM0poWkdsbGJuUlVjbUZ1YzJadmNtMDlJbkp2ZEdGMFpTZzVNQ2tpSUdkeVlXUnBaVzUwVlc1cGRITTlJblZ6WlhKVGNHRmpaVTl1VlhObElqNDhjM1J2Y0NCdlptWnpaWFE5SWpVd0pTSWdjM1J2Y0MxamIyeHZjajBpYUhOc0tEVXpMRGM1SlN3ME1TVXBJaTgrUEhOMGIzQWdiMlptYzJWMFBTSTRNQ1VpSUhOMGIzQXRZMjlzYjNJOUltaHpiQ2d5TXpBc01qRWxMREV4SlNraUx6NDhMMnhwYm1WaGNrZHlZV1JwWlc1MFBqeG5JR2xrUFNKSWIzVnlaMnhoYzNNaVBqeHdZWFJvSUdROUlrMGdOVEFzTXpZd0lHRWdNekF3TERNd01DQXdJREVzTVNBMk1EQXNNQ0JoSURNd01Dd3pNREFnTUNBeExERWdMVFl3TUN3d0lpQm1hV3hzUFNJalptWm1JaUJtYVd4c0xXOXdZV05wZEhrOUlpNHdNaUlnYzNSeWIydGxQU0oxY213b0kwaHZkWEpuYkdGemMxTjBjbTlyWlNraUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeHdZWFJvSUdROUltMDFOallzTVRZeExqSXdNWFl0TlRNdU9USTBZekF0TVRrdU16Z3lMVEl5TGpVeE15MHpOeTQxTmpNdE5qTXVNems0TFRVeExqRTVPQzAwTUM0M05UWXRNVE11TlRreUxUazBMamswTmkweU1TNHdOemt0TVRVeUxqVTROeTB5TVM0d056bHpMVEV4TVM0NE16Z3NOeTQwT0RjdE1UVXlMall3TWl3eU1TNHdOemxqTFRRd0xqZzVNeXd4TXk0Mk16WXROak11TkRFekxETXhMamd4TmkwMk15NDBNVE1zTlRFdU1UazRkalV6TGpreU5HTXdMREUzTGpFNE1Td3hOeTQzTURRc016TXVOREkzTERVd0xqSXlNeXcwTmk0ek9UUjJNamcwTGpnd09XTXRNekl1TlRFNUxERXlMamsyTFRVd0xqSXlNeXd5T1M0eU1EWXROVEF1TWpJekxEUTJMak01TkhZMU15NDVNalJqTUN3eE9TNHpPRElzTWpJdU5USXNNemN1TlRZekxEWXpMalF4TXl3MU1TNHhPVGdzTkRBdU56WXpMREV6TGpVNU1pdzVOQzQ1TlRRc01qRXVNRGM1TERFMU1pNDJNRElzTWpFdU1EYzVjekV4TVM0NE16RXROeTQwT0Rjc01UVXlMalU0TnkweU1TNHdOemxqTkRBdU9EZzJMVEV6TGpZek5pdzJNeTR6T1RndE16RXVPREUyTERZekxqTTVPQzAxTVM0eE9UaDJMVFV6TGpreU5HTXdMVEUzTGpFNU5pMHhOeTQzTURRdE16TXVORE0xTFRVd0xqSXlNeTAwTmk0ME1ERldNakEzTGpZd00yTXpNaTQxTVRrdE1USXVPVFkzTERVd0xqSXlNeTB5T1M0eU1EWXNOVEF1TWpJekxUUTJMalF3TVZwdExUTTBOeTQwTmpJc05UY3VOemt6YkRFek1DNDVOVGtzTVRNeExqQXlOeTB4TXpBdU9UVTVMREV6TVM0d01UTldNakU0TGprNU5GcHRNall5TGpreU5DNHdNakoyTWpZeUxqQXhPR3d0TVRNd0xqa3pOeTB4TXpFdU1EQTJMREV6TUM0NU16Y3RNVE14TGpBeE0xb2lJR1pwYkd3OUlpTXhOakU0TWpJaVBqd3ZjR0YwYUQ0OGNHOXNlV2R2YmlCd2IybHVkSE05SWpNMU1DQXpOVEF1TURJMklEUXhOUzR3TXlBeU9EUXVPVGM0SURJNE5TQXlPRFF1T1RjNElETTFNQ0F6TlRBdU1ESTJJaUJtYVd4c1BTSjFjbXdvSTFOaGJtUkNiM1IwYjIwcElpOCtQSEJoZEdnZ1pEMGliVFF4Tmk0ek5ERXNNamd4TGprM05XTXdMQzQ1TVRRdExqTTFOQ3d4TGpnd09TMHhMakF6TlN3eUxqWTRMVFV1TlRReUxEY3VNRGMyTFRNeUxqWTJNU3d4TWk0ME5TMDJOUzR5T0N3eE1pNDBOUzB6TWk0Mk1qUXNNQzAxT1M0M016Z3ROUzR6TnpRdE5qVXVNamd0TVRJdU5EVXRMalk0TVMwdU9EY3lMVEV1TURNMUxURXVOelkzTFRFdU1ETTFMVEl1Tmpnc01DMHVPVEUwTGpNMU5DMHhMamd3T0N3eExqQXpOUzB5TGpZM05pdzFMalUwTWkwM0xqQTNOaXd6TWk0Mk5UWXRNVEl1TkRVc05qVXVNamd0TVRJdU5EVXNNekl1TmpFNUxEQXNOVGt1TnpNNExEVXVNemMwTERZMUxqSTRMREV5TGpRMUxqWTRNUzQ0Tmpjc01TNHdNelVzTVM0M05qSXNNUzR3TXpVc01pNDJOelphSWlCbWFXeHNQU0oxY213b0kxTmhibVJVYjNBcElpOCtQSEJoZEdnZ1pEMGliVFE0TVM0ME5pdzFNRFF1TVRBeGRqVTRMalEwT1dNdE1pNHpOUzQzTnkwMExqZ3lMREV1TlRFdE55NHpPU3d5TGpJekxUTXdMak1zT0M0MU5DMDNOQzQyTlN3eE15NDVNaTB4TWpRdU1EWXNNVE11T1RJdE5UTXVOaXd3TFRFd01TNHlOQzAyTGpNekxURXpNUzQwTnkweE5pNHhObll0TlRndU5ETTVhREkyTWk0NU1sb2lJR1pwYkd3OUluVnliQ2dqVTJGdVpFSnZkSFJ2YlNraUx6NDhaV3hzYVhCelpTQmplRDBpTXpVd0lpQmplVDBpTlRBMExqRXdNU0lnY25nOUlqRXpNUzQwTmpJaUlISjVQU0l5T0M0eE1EZ2lJR1pwYkd3OUluVnliQ2dqVTJGdVpGUnZjQ2tpTHo0OFp5Qm1hV3hzUFNKdWIyNWxJaUJ6ZEhKdmEyVTlJblZ5YkNnalNHOTFjbWRzWVhOelUzUnliMnRsS1NJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW5KdmRXNWtJaUJ6ZEhKdmEyVXRiV2wwWlhKc2FXMXBkRDBpTVRBaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJK1BIQmhkR2dnWkQwaWJUVTJOUzQyTkRFc01UQTNMakk0WXpBc09TNDFNemN0TlM0MU5pd3hPQzQyTWprdE1UVXVOamMyTERJMkxqazNNMmd0TGpBeU0yTXRPUzR5TURRc055NDFPVFl0TWpJdU1UazBMREUwTGpVMk1pMHpPQzR4T1Rjc01qQXVOVGt5TFRNNUxqVXdOQ3d4TkM0NU16WXRPVGN1TXpJMUxESTBMak0xTlMweE5qRXVOek16TERJMExqTTFOUzA1TUM0ME9Dd3dMVEUyTnk0NU5EZ3RNVGd1TlRneUxURTVPUzQ1TlRNdE5EUXVPVFE0YUMwdU1ESXpZeTB4TUM0eE1UVXRPQzR6TkRRdE1UVXVOamMyTFRFM0xqUXpOeTB4TlM0Mk56WXRNall1T1RjekxEQXRNemt1TnpNMUxEazJMalUxTkMwM01TNDVNakVzTWpFMUxqWTFNaTAzTVM0NU1qRnpNakUxTGpZeU9Td3pNaTR4T0RVc01qRTFMall5T1N3M01TNDVNakZhSWk4K1BIQmhkR2dnWkQwaWJURXpOQzR6Tml3eE5qRXVNakF6WXpBc016a3VOek0xTERrMkxqVTFOQ3czTVM0NU1qRXNNakUxTGpZMU1pdzNNUzQ1TWpGek1qRTFMall5T1Mwek1pNHhPRFlzTWpFMUxqWXlPUzAzTVM0NU1qRWlMejQ4YkdsdVpTQjRNVDBpTVRNMExqTTJJaUI1TVQwaU1UWXhMakl3TXlJZ2VESTlJakV6TkM0ek5pSWdlVEk5SWpFd055NHlPQ0l2UGp4c2FXNWxJSGd4UFNJMU5qVXVOalFpSUhreFBTSXhOakV1TWpBeklpQjRNajBpTlRZMUxqWTBJaUI1TWowaU1UQTNMakk0SWk4K1BHeHBibVVnZURFOUlqRTROQzQxT0RRaUlIa3hQU0l5TURZdU9ESXpJaUI0TWowaU1UZzBMalU0TlNJZ2VUSTlJalV6Tnk0MU56a2lMejQ4YkdsdVpTQjRNVDBpTWpFNExqRTRNU0lnZVRFOUlqSXhPQzR4TVRnaUlIZ3lQU0l5TVRndU1UZ3hJaUI1TWowaU5UWXlMalV6TnlJdlBqeHNhVzVsSUhneFBTSTBPREV1T0RFNElpQjVNVDBpTWpFNExqRTBNaUlnZURJOUlqUTRNUzQ0TVRraUlIa3lQU0kxTmpJdU5ESTRJaTgrUEd4cGJtVWdlREU5SWpVeE5TNDBNVFVpSUhreFBTSXlNRGN1TXpVeUlpQjRNajBpTlRFMUxqUXhOaUlnZVRJOUlqVXpOeTQxTnpraUx6NDhjR0YwYUNCa1BTSnRNVGcwTGpVNExEVXpOeTQxT0dNd0xEVXVORFVzTkM0eU55d3hNQzQyTlN3eE1pNHdNeXd4TlM0ME1tZ3VNREpqTlM0MU1Td3pMak01TERFeUxqYzVMRFl1TlRVc01qRXVOVFVzT1M0ME1pd3pNQzR5TVN3NUxqa3NOemd1TURJc01UWXVNamdzTVRNeExqZ3pMREUyTGpJNExEUTVMalF4TERBc09UTXVOell0TlM0ek9Dd3hNalF1TURZdE1UTXVPVElzTWk0M0xTNDNOaXcxTGpJNUxURXVOVFFzTnk0M05TMHlMak0xTERndU56Y3RNaTQ0Tnl3eE5pNHdOUzAyTGpBMExESXhMalUyTFRrdU5ETm9NR00zTGpjMkxUUXVOemNzTVRJdU1EUXRPUzQ1Tnl3eE1pNHdOQzB4TlM0ME1pSXZQanh3WVhSb0lHUTlJbTB4T0RRdU5UZ3lMRFE1TWk0Mk5UWmpMVE14TGpNMU5Dd3hNaTQwT0RVdE5UQXVNakl6TERJNExqVTRMVFV3TGpJeU15dzBOaTR4TkRJc01DdzVMalV6Tml3MUxqVTJOQ3d4T0M0Mk1qY3NNVFV1TmpjM0xESTJMamsyT1dndU1ESXlZemd1TlRBekxEY3VNREExTERJd0xqSXhNeXd4TXk0ME5qTXNNelF1TlRJMExERTVMakUxT1N3NUxqazVPU3d6TGprNU1Td3lNUzR5Tmprc055NDJNRGtzTXpNdU5UazNMREV3TGpjNE9Dd3pOaTQwTlN3NUxqUXdOeXc0TWk0eE9ERXNNVFV1TURBeUxERXpNUzQ0TXpVc01UVXVNREF5Y3prMUxqTTJNeTAxTGpVNU5Td3hNekV1T0RBM0xURTFMakF3TW1NeE1DNDRORGN0TWk0M09Td3lNQzQ0TmpjdE5TNDVNallzTWprdU9USTBMVGt1TXpRNUxERXVNalEwTFM0ME5qY3NNaTQwTnpNdExqazBNaXd6TGpZM015MHhMalF5TkN3eE5DNHpNall0TlM0Mk9UWXNNall1TURNMUxURXlMakUyTVN3ek5DNDFNalF0TVRrdU1UY3phQzR3TWpKak1UQXVNVEUwTFRndU16UXlMREUxTGpZM055MHhOeTQwTXpNc01UVXVOamMzTFRJMkxqazJPU3d3TFRFM0xqVTJNaTB4T0M0NE5qa3RNek11TmpZMUxUVXdMakl5TXkwME5pNHhOU0l2UGp4d1lYUm9JR1E5SW0weE16UXVNellzTlRreUxqY3lZekFzTXprdU56TTFMRGsyTGpVMU5DdzNNUzQ1TWpFc01qRTFMalkxTWl3M01TNDVNakZ6TWpFMUxqWXlPUzB6TWk0eE9EWXNNakUxTGpZeU9TMDNNUzQ1TWpFaUx6NDhiR2x1WlNCNE1UMGlNVE0wTGpNMklpQjVNVDBpTlRreUxqY3lJaUI0TWowaU1UTTBMak0ySWlCNU1qMGlOVE00TGpjNU55SXZQanhzYVc1bElIZ3hQU0kxTmpVdU5qUWlJSGt4UFNJMU9USXVOeklpSUhneVBTSTFOalV1TmpRaUlIa3lQU0kxTXpndU56azNJaTgrUEhCdmJIbHNhVzVsSUhCdmFXNTBjejBpTkRneExqZ3lNaUEwT0RFdU9UQXhJRFE0TVM0M09UZ2dORGd4TGpnM055QTBPREV1TnpjMUlEUTRNUzQ0TlRRZ016VXdMakF4TlNBek5UQXVNREkySURJeE9DNHhPRFVnTWpFNExqRXlPU0l2UGp4d2IyeDViR2x1WlNCd2IybHVkSE05SWpJeE9DNHhPRFVnTkRneExqa3dNU0F5TVRndU1qTXhJRFE0TVM0NE5UUWdNelV3TGpBeE5TQXpOVEF1TURJMklEUTRNUzQ0TWpJZ01qRTRMakUxTWlJdlBqd3ZaejQ4TDJjK1BHY2dhV1E5SWxCeWIyZHlaWE56SWlCbWFXeHNQU0lqWm1abUlqNDhjbVZqZENCM2FXUjBhRDBpTWpBNElpQm9aV2xuYUhROUlqRXdNQ0lnWm1sc2JDMXZjR0ZqYVhSNVBTSXVNRE1pSUhKNFBTSXhOU0lnY25rOUlqRTFJaUJ6ZEhKdmEyVTlJaU5tWm1ZaUlITjBjbTlyWlMxdmNHRmphWFI1UFNJdU1TSWdjM1J5YjJ0bExYZHBaSFJvUFNJMElpOCtQSFJsZUhRZ2VEMGlNakFpSUhrOUlqTTBJaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1p2Ym5RdGMybDZaVDBpTWpKd2VDSStVSEp2WjNKbGMzTThMM1JsZUhRK1BIUmxlSFFnZUQwaU1qQWlJSGs5SWpjeUlpQm1iMjUwTFdaaGJXbHNlVDBpSjBOdmRYSnBaWElnVG1WM0p5eEJjbWxoYkN4dGIyNXZjM0JoWTJVaUlHWnZiblF0YzJsNlpUMGlNalp3ZUNJK01qVWxQQzkwWlhoMFBqeG5JR1pwYkd3OUltNXZibVVpUGp4amFYSmpiR1VnWTNnOUlqRTJOaUlnWTNrOUlqVXdJaUJ5UFNJeU1pSWdjM1J5YjJ0bFBTSm9jMndvTWpNd0xESXhKU3d4TVNVcElpQnpkSEp2YTJVdGQybGtkR2c5SWpFd0lpOCtQR05wY21Oc1pTQmplRDBpTVRZMklpQmplVDBpTlRBaUlIQmhkR2hNWlc1bmRHZzlJakV3TURBd0lpQnlQU0l5TWlJZ2MzUnliMnRsUFNKb2Myd29OVE1zTnprbExEUXhKU2tpSUhOMGNtOXJaUzFrWVhOb1lYSnlZWGs5SWpFd01EQXdJaUJ6ZEhKdmEyVXRaR0Z6YUc5bVpuTmxkRDBpTnpVd01DSWdjM1J5YjJ0bExXeHBibVZqWVhBOUluSnZkVzVrSWlCemRISnZhMlV0ZDJsa2RHZzlJalVpSUhSeVlXNXpabTl5YlQwaWNtOTBZWFJsS0MwNU1Da2lJSFJ5WVc1elptOXliUzF2Y21sbmFXNDlJakUyTmlBMU1DSXZQand2Wno0OEwyYytQR2NnYVdROUlsTjBZWFIxY3lJZ1ptbHNiRDBpSTJabVppSStQSEpsWTNRZ2QybGtkR2c5SWpFNE5DSWdhR1ZwWjJoMFBTSXhNREFpSUdacGJHd3RiM0JoWTJsMGVUMGlMakF6SWlCeWVEMGlNVFVpSUhKNVBTSXhOU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGIzQmhZMmwwZVQwaUxqRWlJSE4wY205clpTMTNhV1IwYUQwaU5DSXZQangwWlhoMElIZzlJakl3SWlCNVBTSXpOQ0lnWm05dWRDMW1ZVzFwYkhrOUlpZERiM1Z5YVdWeUlFNWxkeWNzUVhKcFlXd3NiVzl1YjNOd1lXTmxJaUJtYjI1MExYTnBlbVU5SWpJeWNIZ2lQbE4wWVhSMWN6d3ZkR1Y0ZEQ0OGRHVjRkQ0I0UFNJeU1DSWdlVDBpTnpJaUlHWnZiblF0Wm1GdGFXeDVQU0luUTI5MWNtbGxjaUJPWlhjbkxFRnlhV0ZzTEcxdmJtOXpjR0ZqWlNJZ1ptOXVkQzF6YVhwbFBTSXlObkI0SWo1VGRISmxZVzFwYm1jOEwzUmxlSFErUEM5blBqeG5JR2xrUFNKQmJXOTFiblFpSUdacGJHdzlJaU5tWm1ZaVBqeHlaV04wSUhkcFpIUm9QU0l4TWpBaUlHaGxhV2RvZEQwaU1UQXdJaUJtYVd4c0xXOXdZV05wZEhrOUlpNHdNeUlnY25nOUlqRTFJaUJ5ZVQwaU1UVWlJSE4wY205clpUMGlJMlptWmlJZ2MzUnliMnRsTFc5d1lXTnBkSGs5SWk0eElpQnpkSEp2YTJVdGQybGtkR2c5SWpRaUx6NDhkR1Y0ZENCNFBTSXlNQ0lnZVQwaU16UWlJR1p2Ym5RdFptRnRhV3g1UFNJblEyOTFjbWxsY2lCT1pYY25MRUZ5YVdGc0xHMXZibTl6Y0dGalpTSWdabTl1ZEMxemFYcGxQU0l5TW5CNElqNUJiVzkxYm5ROEwzUmxlSFErUEhSbGVIUWdlRDBpTWpBaUlIazlJamN5SWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krSmlNNE9EQTFPeUF4TUVzOEwzUmxlSFErUEM5blBqeG5JR2xrUFNKRWRYSmhkR2x2YmlJZ1ptbHNiRDBpSTJabVppSStQSEpsWTNRZ2QybGtkR2c5SWpFMU1pSWdhR1ZwWjJoMFBTSXhNREFpSUdacGJHd3RiM0JoWTJsMGVUMGlMakF6SWlCeWVEMGlNVFVpSUhKNVBTSXhOU0lnYzNSeWIydGxQU0lqWm1abUlpQnpkSEp2YTJVdGIzQmhZMmwwZVQwaUxqRWlJSE4wY205clpTMTNhV1IwYUQwaU5DSXZQangwWlhoMElIZzlJakl3SWlCNVBTSXpOQ0lnWm05dWRDMW1ZVzFwYkhrOUlpZERiM1Z5YVdWeUlFNWxkeWNzUVhKcFlXd3NiVzl1YjNOd1lXTmxJaUJtYjI1MExYTnBlbVU5SWpJeWNIZ2lQa1IxY21GMGFXOXVQQzkwWlhoMFBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJM01pSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakkyY0hnaVBpWnNkRHNnTVNCRVlYazhMM1JsZUhRK1BDOW5Qand2WkdWbWN6NDhkR1Y0ZENCMFpYaDBMWEpsYm1SbGNtbHVaejBpYjNCMGFXMXBlbVZUY0dWbFpDSStQSFJsZUhSUVlYUm9JSE4wWVhKMFQyWm1jMlYwUFNJdE1UQXdKU0lnYUhKbFpqMGlJMFpzYjJGMGFXNW5WR1Y0ZENJZ1ptbHNiRDBpSTJabVppSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1hV3hzTFc5d1lXTnBkSGs5SWk0NElpQm1iMjUwTFhOcGVtVTlJakkyY0hnaVBqeGhibWx0WVhSbElHRmtaR2wwYVhabFBTSnpkVzBpSUdGMGRISnBZblYwWlU1aGJXVTlJbk4wWVhKMFQyWm1jMlYwSWlCaVpXZHBiajBpTUhNaUlHUjFjajBpTlRCeklpQm1jbTl0UFNJd0pTSWdjbVZ3WldGMFEyOTFiblE5SW1sdVpHVm1hVzVwZEdVaUlIUnZQU0l4TURBbElpOCtNSGczTVdJNU9ETTNZV1V4WlRGaFl6azVOamMyWlRVeVlUSmlaVGd5WVRrNU9Ea3dNR1U0TW1NMklPS0FvaUJUWVdKc2FXVnlJRk5oWW14cFpYSWdURzlqYTNWd0lFeHBibVZoY2p3dmRHVjRkRkJoZEdnK1BIUmxlSFJRWVhSb0lITjBZWEowVDJabWMyVjBQU0l3SlNJZ2FISmxaajBpSTBac2IyRjBhVzVuVkdWNGRDSWdabWxzYkQwaUkyWm1aaUlnWm05dWRDMW1ZVzFwYkhrOUlpZERiM1Z5YVdWeUlFNWxkeWNzUVhKcFlXd3NiVzl1YjNOd1lXTmxJaUJtYVd4c0xXOXdZV05wZEhrOUlpNDRJaUJtYjI1MExYTnBlbVU5SWpJMmNIZ2lQanhoYm1sdFlYUmxJR0ZrWkdsMGFYWmxQU0p6ZFcwaUlHRjBkSEpwWW5WMFpVNWhiV1U5SW5OMFlYSjBUMlptYzJWMElpQmlaV2RwYmowaU1ITWlJR1IxY2owaU5UQnpJaUJtY205dFBTSXdKU0lnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJSFJ2UFNJeE1EQWxJaTgrTUhnM01XSTVPRE0zWVdVeFpURmhZems1TmpjMlpUVXlZVEppWlRneVlUazVPRGt3TUdVNE1tTTJJT0tBb2lCVFlXSnNhV1Z5SUZOaFlteHBaWElnVEc5amEzVndJRXhwYm1WaGNqd3ZkR1Y0ZEZCaGRHZytQSFJsZUhSUVlYUm9JSE4wWVhKMFQyWm1jMlYwUFNJdE5UQWxJaUJvY21WbVBTSWpSbXh2WVhScGJtZFVaWGgwSWlCbWFXeHNQU0lqWm1abUlpQm1iMjUwTFdaaGJXbHNlVDBpSjBOdmRYSnBaWElnVG1WM0p5eEJjbWxoYkN4dGIyNXZjM0JoWTJVaUlHWnBiR3d0YjNCaFkybDBlVDBpTGpnaUlHWnZiblF0YzJsNlpUMGlNalp3ZUNJK1BHRnVhVzFoZEdVZ1lXUmthWFJwZG1VOUluTjFiU0lnWVhSMGNtbGlkWFJsVG1GdFpUMGljM1JoY25SUFptWnpaWFFpSUdKbFoybHVQU0l3Y3lJZ1pIVnlQU0kxTUhNaUlHWnliMjA5SWpBbElpQnlaWEJsWVhSRGIzVnVkRDBpYVc1a1pXWnBibWwwWlNJZ2RHODlJakV3TUNVaUx6NHdlRFUyTVRWa1pXSTNPVGhpWWpObE5HUm1ZVEF4TXpsa1ptRXhZak5rTkRNelkyTXlNMkkzTW1ZZzRvQ2lJRVJCU1R3dmRHVjRkRkJoZEdnK1BIUmxlSFJRWVhSb0lITjBZWEowVDJabWMyVjBQU0kxTUNVaUlHaHlaV1k5SWlOR2JHOWhkR2x1WjFSbGVIUWlJR1pwYkd3OUlpTm1abVlpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm1sc2JDMXZjR0ZqYVhSNVBTSXVPQ0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajQ4WVc1cGJXRjBaU0JoWkdScGRHbDJaVDBpYzNWdElpQmhkSFJ5YVdKMWRHVk9ZVzFsUFNKemRHRnlkRTltWm5ObGRDSWdZbVZuYVc0OUlqQnpJaUJrZFhJOUlqVXdjeUlnWm5KdmJUMGlNQ1VpSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUIwYnowaU1UQXdKU0l2UGpCNE5UWXhOV1JsWWpjNU9HSmlNMlUwWkdaaE1ERXpPV1JtWVRGaU0yUTBNek5qWXpJellqY3laaURpZ0tJZ1JFRkpQQzkwWlhoMFVHRjBhRDQ4TDNSbGVIUStQSFZ6WlNCb2NtVm1QU0lqUjJ4dmR5SWdabWxzYkMxdmNHRmphWFI1UFNJdU9TSXZQangxYzJVZ2FISmxaajBpSTBkc2IzY2lJSGc5SWpFd01EQWlJSGs5SWpFd01EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqa2lMejQ4ZFhObElHaHlaV1k5SWlOTWIyZHZJaUI0UFNJeE56QWlJSGs5SWpFM01DSWdkSEpoYm5ObWIzSnRQU0p6WTJGc1pTZ3VOaWtpTHo0OGRYTmxJR2h5WldZOUlpTkliM1Z5WjJ4aGMzTWlJSGc5SWpFMU1DSWdlVDBpT1RBaUlIUnlZVzV6Wm05eWJUMGljbTkwWVhSbEtERXdLU0lnZEhKaGJuTm1iM0p0TFc5eWFXZHBiajBpTlRBd0lEVXdNQ0l2UGp4MWMyVWdhSEpsWmowaUkxQnliMmR5WlhOeklpQjRQU0l4TkRRaUlIazlJamM1TUNJdlBqeDFjMlVnYUhKbFpqMGlJMU4wWVhSMWN5SWdlRDBpTXpZNElpQjVQU0kzT1RBaUx6NDhkWE5sSUdoeVpXWTlJaU5CYlc5MWJuUWlJSGc5SWpVMk9DSWdlVDBpTnprd0lpOCtQSFZ6WlNCb2NtVm1QU0lqUkhWeVlYUnBiMjRpSUhnOUlqY3dOQ0lnZVQwaU56a3dJaTgrUEM5emRtYysifQ"; assertEq(actualTokenURI, expectedTokenURI, "token URI"); diff --git a/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree index adf7bc017..54723cea4 100644 --- a/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree +++ b/test/core/integration/concrete/lockup-dynamic/token-uri/tokenURI.tree @@ -1,4 +1,4 @@ -TokenURI_LockupDynamic_Integration_Concrete_Test +TokenURI_Lockup_Dynamic_Integration_Concrete_Test ├── given NFT not exist │ └── it should revert └── given NFT exists 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 59f57c449..d406d2721 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 @@ -2,20 +2,20 @@ pragma solidity >=0.8.22 <0.9.0; import { WithdrawableAmountOf_Integration_Concrete_Test } from - "./../../lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { LockupDynamic_Integration_Shared_Test, Integration_Test } from "./../LockupDynamic.t.sol"; + "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test, Integration_Test } from "./../LockupDynamic.t.sol"; -contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawableAmountOf_Lockup_Dynamic_Integration_Concrete_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() }); - uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -25,7 +25,7 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Run the test. - uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); // The second term is 7,500*0.5^{0.5} uint128 expectedWithdrawableAmount = defaults.segments()[0].amount + 5303.30085889910643e18; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); @@ -36,10 +36,10 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() + 3750 seconds }); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); // Run the test. - uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); // The second term is 7,500*0.5^{0.5} uint128 expectedWithdrawableAmount = diff --git a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree index 08d80ff3c..ed65b2bfc 100644 --- a/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree +++ b/test/core/integration/concrete/lockup-dynamic/withdrawable-amount-of/withdrawableAmountOf.tree @@ -1,4 +1,4 @@ -WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test +WithdrawableAmountOf_Lockup_Dynamic_Integration_Concrete_Test └── given STREAMING status ├── given start time in present │ └── it should return zero diff --git a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol index e5cfcae77..f2e8003dd 100644 --- a/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/concrete/lockup-linear/LockupLinear.t.sol @@ -2,339 +2,366 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "./../../Integration.t.sol"; -import { LockupLinear_Integration_Shared_Test } from "./../../shared/lockup-linear/LockupLinear.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { Cancel_Integration_Concrete_Test } from "./../lockup/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from "./../lockup/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from "./../lockup/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from "./../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup/is-warm/isWarm.t.sol"; -import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup/refundable-amount-of/refundableAmountOf.t.sol"; -import { Renounce_Integration_Concrete_Test } from "./../lockup/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup/withdraw-hooks/withdrawHooks.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/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup/withdraw-multiple/withdrawMultiple.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "./../lockup/withdraw/withdraw.t.sol"; + "./../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_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract AllowToHook_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, AllowToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Batch_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract Batch_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, Batch_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Burn_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract Burn_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, Burn_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Cancel_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract Cancel_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, Cancel_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +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(LockupLinear_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) + override(Lockup_Linear_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + Lockup_Linear_Integration_Shared_Test.setUp(); CancelMultiple_Integration_Concrete_Test.setUp(); } } -contract GetAsset_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetAsset_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetAsset_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetDepositedAmount_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetDepositedAmount_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetDepositedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetEndTime_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetEndTime_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetEndTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetRecipient_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetRecipient_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetRecipient_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetRefundedAmount_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetRefundedAmount_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetRefundedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetSender_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetSender_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetSender_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetStartTime_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetStartTime_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetStartTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract GetWithdrawnAmount_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, GetWithdrawnAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsAllowedToHook_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsAllowedToHook_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsAllowedToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsCancelable_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsCancelable_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsCancelable_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsCold_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsCold_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsCold_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsDepleted_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsDepleted_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsDepleted_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsStream_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsStream_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsStream_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsTransferable_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsTransferable_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsTransferable_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract IsWarm_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract IsWarm_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, IsWarm_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Renounce_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract Renounce_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, Renounce_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract RefundableAmountOf_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract RefundableAmountOf_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, RefundableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract SetNFTDescriptor_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract SetNFTDescriptor_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, SetNFTDescriptor_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract StatusOf_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract StatusOf_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, StatusOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract TransferFrom_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract TransferFrom_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test { function setUp() public virtual - override(LockupLinear_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) + override(Lockup_Linear_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + Lockup_Linear_Integration_Shared_Test.setUp(); TransferFrom_Integration_Concrete_Test.setUp(); } } -contract WasCanceled_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract WasCanceled_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, WasCanceled_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Withdraw_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract Withdraw_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, Withdraw_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawHooks_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawHooks_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test { function setUp() public virtual - override(LockupLinear_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) + override(Lockup_Linear_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + Lockup_Linear_Integration_Shared_Test.setUp(); WithdrawHooks_Integration_Concrete_Test.setUp(); } } -contract WithdrawMax_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawMax_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawMax_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +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(LockupLinear_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) + override(Lockup_Linear_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + Lockup_Linear_Integration_Shared_Test.setUp(); WithdrawMultiple_Integration_Concrete_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol similarity index 64% rename from test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol index 861426bb9..07b4277b7 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.t.sol @@ -3,24 +3,24 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +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 { LockupLinear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; -contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { +contract CreateWithDurationsLL_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupLinear_Integration_Shared_Test.setUp(); - streamId = lockupLinear.nextStreamId(); + Lockup_Linear_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { bytes memory callData = - abi.encodeCall(ISablierLockupLinear.createWithDurations, defaults.createWithDurationsLL()); - (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); + abi.encodeCall(ISablierLockup.createWithDurationsLL, (defaults.createWithDurations(), defaults.durations())); + (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } @@ -37,13 +37,11 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLin // It should revert. vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime - ) + abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) ); // Create the stream. - createDefaultStreamWithDurations(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); + createDefaultStreamWithDurationsLL(LockupLinear.Durations({ cliff: cliffDuration, total: totalDuration })); } function test_WhenCliffTimeCalculationNotOverflow() external whenNoDelegateCall whenCliffDurationNotZero { @@ -66,11 +64,11 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLin // It should revert. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime) + abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanEndTime.selector, startTime, endTime) ); // Create the stream. - createDefaultStreamWithDurations(durations); + createDefaultStreamWithDurationsLL(durations); } function test_WhenEndTimeCalculationNotOverflow() external whenNoDelegateCall whenCliffDurationZero { @@ -85,7 +83,7 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLin // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupLinear.Timestamps memory timestamps = LockupLinear.Timestamps({ + Lockup.Timestamps memory timestamps = Lockup.Timestamps({ start: blockTimestamp, cliff: blockTimestamp + durations.cliff, end: blockTimestamp + durations.total @@ -94,16 +92,16 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLin if (durations.cliff == 0) timestamps.cliff = 0; // It should perform the ERC-20 transfers. - expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); + 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() }); // It should emit {CreateLockupLinearStream} and {MetadataUpdate} events. - vm.expectEmit({ emitter: address(lockupLinear) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockupLinear.CreateLockupLinearStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -117,28 +115,34 @@ contract CreateWithDurations_LockupLinear_Integration_Concrete_Test is LockupLin }); // Create the stream. - createDefaultStreamWithDurations(durations); + createDefaultStreamWithDurationsLL(durations); // It should create the stream. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.startTime = timestamps.start; - expectedStream.cliffTime = timestamps.cliff; - expectedStream.endTime = timestamps.end; - assertEq(actualStream, expectedStream); + 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.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getCliffTime(streamId), timestamps.cliff, "cliff"); // Assert that the stream's status is "STREAMING". - Lockup.Status actualStatus = lockupLinear.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupLinear.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + 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-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.tree similarity index 94% rename from test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.tree index 8aecc0edc..471e17494 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurations.tree +++ b/test/core/integration/concrete/lockup-linear/create-with-durations/createWithDurationsLL.tree @@ -1,4 +1,4 @@ -CreateWithDurations_LockupLinear_Integration_Concrete_Test +CreateWithDurationsLL_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call diff --git a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol similarity index 62% rename from test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol index 03c21efe4..880c92f7b 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.t.sol @@ -6,35 +6,36 @@ 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 { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; -import { LockupLinear_Integration_Shared_Test } from "./../LockupLinear.t.sol"; +import { Broker, Lockup } from "src/core/types/DataTypes.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "./../LockupLinear.t.sol"; -contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { +contract CreateWithTimestampsLL_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { uint256 internal streamId; function setUp() public override { - LockupLinear_Integration_Shared_Test.setUp(); - streamId = lockupLinear.nextStreamId(); + Lockup_Linear_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupLinear.createWithTimestamps, defaults.createWithTimestampsLL()); - (bool success, bytes memory returnData) = address(lockupLinear).delegatecall(callData); + 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); - createDefaultStreamWithSender(address(0)); + createDefaultStreamWithSenderLL(address(0)); } function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { address recipient = address(0); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipient(recipient); + createDefaultStreamWithRecipientLL(recipient); } function test_RevertWhen_DepositAmountZero() @@ -44,7 +45,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi whenRecipientNotZeroAddress { vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); - createDefaultStreamWithTotalAmount(0); + createDefaultStreamWithTotalAmountLL(0); } function test_RevertWhen_StartTimeZero() @@ -58,7 +59,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi uint40 endTime = defaults.END_TIME(); vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: 0, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: 0, cliff: cliffTime, end: endTime })); } function test_RevertWhen_StartTimeNotLessThanEndTime() @@ -74,9 +75,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi uint40 endTime = defaults.START_TIME(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupLinear_StartTimeNotLessThanEndTime.selector, startTime, endTime) + abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanEndTime.selector, startTime, endTime) ); - createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: 0, end: endTime })); + createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: 0, end: endTime })); } function test_WhenStartTimeLessThanEndTime() @@ -88,23 +89,31 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi whenStartTimeNotZero whenCliffTimeZero { - createDefaultStreamWithTimestamps( - LockupLinear.Timestamps({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) + createDefaultStreamWithTimestampsLL( + Lockup.Timestamps({ start: defaults.START_TIME(), cliff: 0, end: defaults.END_TIME() }) ); - // Assert that the stream has been created. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.cliffTime = 0; - assertEq(actualStream, expectedStream); + // 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 = lockupLinear.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } @@ -122,11 +131,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi uint40 cliffTime = defaults.START_TIME(); uint40 endTime = defaults.END_TIME(); vm.expectRevert( - abi.encodeWithSelector( - Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime - ) + abi.encodeWithSelector(Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, cliffTime) ); - createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } function test_RevertWhen_CliffTimeNotLessThanEndTime() @@ -143,9 +150,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi uint40 cliffTime = defaults.END_TIME(); uint40 endTime = defaults.CLIFF_TIME(); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) + abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); - createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } function test_RevertWhen_BrokerFeeExceedsMaxValue() @@ -163,7 +170,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); + createDefaultStreamWithBrokerLL(Broker({ account: users.broker, fee: brokerFee })); } function test_RevertWhen_AssetNotContract() @@ -180,7 +187,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi { address nonContract = address(8128); vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAsset(IERC20(nonContract)); + createDefaultStreamWithAssetLL(IERC20(nonContract)); } function test_WhenAssetMissesERC20ReturnValue() @@ -196,7 +203,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi whenBrokerFeeNotExceedMaxValue whenAssetContract { - testCreateWithTimestamps(address(usdt)); + _testCreateWithTimestamps(address(usdt)); } function test_WhenAssetNotMissERC20ReturnValue() @@ -212,11 +219,11 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi whenBrokerFeeNotExceedMaxValue whenAssetContract { - testCreateWithTimestamps(address(dai)); + _testCreateWithTimestamps(address(dai)); } /// @dev Shared logic between {test_CreateWithTimestamps_AssetMissingReturnValue} and {test_CreateWithTimestamps}. - function testCreateWithTimestamps(address asset) internal { + function _testCreateWithTimestamps(address asset) private { // Make the Sender the stream's funder. address funder = users.sender; @@ -224,7 +231,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi expectCallToTransferFrom({ asset: IERC20(asset), from: funder, - to: address(lockupLinear), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); @@ -237,10 +244,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi }); // It should emit {MetadataUpdate} and {CreateLockupLinearStream} events. - vm.expectEmit({ emitter: address(lockupLinear) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockupLinear.CreateLockupLinearStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -254,26 +261,34 @@ contract CreateWithTimestamps_LockupLinear_Integration_Concrete_Test is LockupLi }); // Create the stream. - createDefaultStreamWithAsset(IERC20(asset)); + createDefaultStreamWithAssetLL(IERC20(asset)); // It should create the stream. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.asset = IERC20(asset); - assertEq(actualStream, expectedStream); + 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 = lockupLinear.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupLinear.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + 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/createWithTimestamps.tree b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree similarity index 97% rename from test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree index 640b7753a..f1d53bdd8 100644 --- a/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-linear/create-with-timestamps/createWithTimestampsLL.tree @@ -1,4 +1,4 @@ -CreateWithTimestamps_LockupLinear_Integration_Concrete_Test +CreateWithTimestampsLL_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call 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 95f6f963f..0b30aa5df 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 @@ -3,18 +3,16 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; -import { LockupLinear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; -contract GetCliffTime_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { +contract GetCliffTime_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupLinear.getCliffTime(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getCliffTime(nullStreamId); } - function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - uint40 actualCliffTime = lockupLinear.getCliffTime(streamId); + function test_GivenNotNull() external view { + 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 82c02394f..ca19479a2 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 @@ -1,4 +1,4 @@ -GetCliffTime_LockupLinear_Integration_Concrete_Test +GetCliffTime_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null diff --git a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol deleted file mode 100644 index 9bc468e76..000000000 --- a/test/core/integration/concrete/lockup-linear/get-stream/getStream.t.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Errors } from "src/core/libraries/Errors.sol"; -import { LockupLinear } from "src/core/types/DataTypes.sol"; - -import { LockupLinear_Integration_Shared_Test } from "../LockupLinear.t.sol"; - -contract GetStream_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { - function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupLinear.getStream(nullStreamId); - } - - function test_GivenSettledStream() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - - // It should return the stream struct. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(defaultStreamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - // It should always return stream as non-cancelable. - expectedStream.isCancelable = false; - assertEq(actualStream, expectedStream); - } - - function test_GivenNotSettledStream() external givenNotNull { - // It should return the stream struct. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(defaultStreamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - assertEq(actualStream, expectedStream); - } -} diff --git a/test/core/integration/concrete/lockup-linear/get-stream/getStream.tree b/test/core/integration/concrete/lockup-linear/get-stream/getStream.tree deleted file mode 100644 index e2f40df40..000000000 --- a/test/core/integration/concrete/lockup-linear/get-stream/getStream.tree +++ /dev/null @@ -1,9 +0,0 @@ -GetStream_LockupLinear_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given settled stream - │ ├── it should always return stream as non-cancelable - │ └── it should return the stream struct - └── given not settled stream - └── it should return the stream struct diff --git a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol index 3eb8dc124..2996a3690 100644 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.t.sol @@ -2,21 +2,19 @@ pragma solidity >=0.8.22 <0.9.0; import { Errors } from "src/core/libraries/Errors.sol"; -import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupLinear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; -contract GetTimestamps_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { +contract GetTimestamps_Lockup_Linear_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupLinear.getTimestamps(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getTimestamps(nullStreamId); } function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - LockupLinear.Timestamps memory actualTimestamps = lockupLinear.getTimestamps(streamId); - LockupLinear.Timestamps memory expectedTimestamps = defaults.lockupLinearTimestamps(); + 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 index bd723d586..68edb7c04 100644 --- a/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree +++ b/test/core/integration/concrete/lockup-linear/get-timestamps/getTimestamps.tree @@ -1,4 +1,4 @@ -GetTimestamps_LockupLinear_Integration_Concrete_Test +GetTimestamps_Lockup_Linear_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null 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 9a35c7a57..7f81584ed 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,26 +1,26 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "src/core/types/DataTypes.sol"; -import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; -import { LockupLinear_Integration_Shared_Test, Integration_Test } from "./../LockupLinear.t.sol"; +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"; -contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract StreamedAmountOf_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, StreamedAmountOf_Integration_Concrete_Test { - function setUp() public override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } function test_GivenCliffTimeZero() external givenPENDINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); - - LockupLinear.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); + Lockup.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); timestamps.cliff = 0; - uint256 streamId = createDefaultStreamWithTimestamps(timestamps); + uint256 streamId = createDefaultStreamWithTimestampsLL(timestamps); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -28,38 +28,38 @@ contract StreamedAmountOf_LockupLinear_Integration_Concrete_Test is function test_GivenCliffTimeNotZero() external givenPENDINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() - 1 }); - LockupLinear.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); + Lockup.Timestamps memory timestamps = defaults.lockupLinearTimestamps(); timestamps.cliff = defaults.CLIFF_TIME(); - uint256 streamId = createDefaultStreamWithTimestamps(timestamps); + uint256 streamId = createDefaultStreamWithTimestampsLL(timestamps); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_GivenCliffTimeInFuture() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.CLIFF_TIME() - 1 }); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_GivenCliffTimeInPresent() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.CLIFF_TIME() }); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.CLIFF_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_GivenEndTimeNotInFuture() external givenSTREAMINGStatus givenCliffTimeInPast { vm.warp({ newTimestamp: defaults.END_TIME() + 1 }); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } function test_GivenEndTimeInFuture() external givenSTREAMINGStatus givenCliffTimeInPast { - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 2600e18; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree index 5c6c59b98..994e2d043 100644 --- a/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree +++ b/test/core/integration/concrete/lockup-linear/streamed-amount-of/streamedAmountOf.tree @@ -1,4 +1,4 @@ -StreamedAmountOf_LockupLinear_Integration_Concrete_Test +StreamedAmountOf_Lockup_Linear_Integration_Concrete_Test ├── given PENDING status │ ├── given cliff time zero │ │ └── it should return zero 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 9e08b54d9..bab3f3e4e 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 { LockupLinear_Integration_Shared_Test } from "../LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "../LockupLinear.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,12 +16,12 @@ import { LockupLinear_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_LockupLinear_Integration_Concrete_Test is LockupLinear_Integration_Shared_Test { - address internal constant LOCKUP_LINEAR = 0x3381cD18e2Fb4dB236BF0525938AB6E43Db0440f; +contract TokenURI_Lockup_Linear_Integration_Concrete_Test is Lockup_Linear_Integration_Shared_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. modifier skipOnMismatch() { - if (address(lockupLinear) == LOCKUP_LINEAR) { + if (address(lockup) == LOCKUP) { _; } else { console2.log(StdStyle.yellow('Warning: "LockupLinear.tokenURI" tests skipped due to address mismatch')); @@ -29,9 +29,8 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra } function test_RevertGiven_NFTNotExist() external { - uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); - lockupLinear.tokenURI({ tokenId: nullStreamId }); + lockup.tokenURI({ tokenId: nullStreamId }); } /// @dev If you need to update the hard-coded token URI: @@ -40,7 +39,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra function test_WhenTokenURIDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory tokenURI = lockupLinear.tokenURI(defaultStreamId); + string memory tokenURI = lockup.tokenURI(defaultStreamId); tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = @@ -51,7 +50,7 @@ contract TokenURI_LockupLinear_Integration_Concrete_Test is LockupLinear_Integra function test_WhenTokenURINotDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory actualTokenURI = lockupLinear.tokenURI(defaultStreamId); + string memory actualTokenURI = lockup.tokenURI(defaultStreamId); string memory expectedTokenURI = "data:application/json;base64,eyJhdHRyaWJ1dGVzIjpbeyJ0cmFpdF90eXBlIjoiQXNzZXQiLCJ2YWx1ZSI6IkRBSSJ9LHsidHJhaXRfdHlwZSI6IlNlbmRlciIsInZhbHVlIjoiMHg2MzMyZTdiMWRlYjFmMWEwYjc3YjJiYjE4YjE0NDMzMGM3MjkxYmNhIn0seyJ0cmFpdF90eXBlIjoiU3RhdHVzIiwidmFsdWUiOiJTdHJlYW1pbmcifV0sImRlc2NyaXB0aW9uIjoiVGhpcyBORlQgcmVwcmVzZW50cyBhIHBheW1lbnQgc3RyZWFtIGluIGEgU2FibGllciBWMiBMb2NrdXAgTGluZWFyIGNvbnRyYWN0LiBUaGUgb3duZXIgb2YgdGhpcyBORlQgY2FuIHdpdGhkcmF3IHRoZSBzdHJlYW1lZCBhc3NldHMsIHdoaWNoIGFyZSBkZW5vbWluYXRlZCBpbiBEQUkuXG5cbi0gU3RyZWFtIElEOiAxXG4tIExvY2t1cCBMaW5lYXIgQWRkcmVzczogMHgzMzgxY2QxOGUyZmI0ZGIyMzZiZjA1MjU5MzhhYjZlNDNkYjA0NDBmXG4tIERBSSBBZGRyZXNzOiAweDAzYTZhODRjZDc2MmQ5NzA3YTIxNjA1YjU0OGFhYWI4OTE1NjJhYWJcblxu4pqg77iPIFdBUk5JTkc6IFRyYW5zZmVycmluZyB0aGUgTkZUIG1ha2VzIHRoZSBuZXcgb3duZXIgdGhlIHJlY2lwaWVudCBvZiB0aGUgc3RyZWFtLiBUaGUgZnVuZHMgYXJlIG5vdCBhdXRvbWF0aWNhbGx5IHdpdGhkcmF3biBmb3IgdGhlIHByZXZpb3VzIHJlY2lwaWVudC4iLCJleHRlcm5hbF91cmwiOiJodHRwczovL3NhYmxpZXIuY29tIiwibmFtZSI6IlNhYmxpZXIgVjIgTG9ja3VwIExpbmVhciAjMSIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0l4TURBd0lpQm9aV2xuYUhROUlqRXdNREFpSUhacFpYZENiM2c5SWpBZ01DQXhNREF3SURFd01EQWlQanh5WldOMElIZHBaSFJvUFNJeE1EQWxJaUJvWldsbmFIUTlJakV3TUNVaUlHWnBiSFJsY2owaWRYSnNLQ05PYjJselpTa2lMejQ4Y21WamRDQjRQU0kzTUNJZ2VUMGlOekFpSUhkcFpIUm9QU0k0TmpBaUlHaGxhV2RvZEQwaU9EWXdJaUJtYVd4c1BTSWpabVptSWlCbWFXeHNMVzl3WVdOcGRIazlJaTR3TXlJZ2NuZzlJalExSWlCeWVUMGlORFVpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExXOXdZV05wZEhrOUlpNHhJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqUWlMejQ4WkdWbWN6NDhZMmx5WTJ4bElHbGtQU0pIYkc5M0lpQnlQU0kxTURBaUlHWnBiR3c5SW5WeWJDZ2pVbUZrYVdGc1IyeHZkeWtpTHo0OFptbHNkR1Z5SUdsa1BTSk9iMmx6WlNJK1BHWmxSbXh2YjJRZ2VEMGlNQ0lnZVQwaU1DSWdkMmxrZEdnOUlqRXdNQ1VpSUdobGFXZG9kRDBpTVRBd0pTSWdabXh2YjJRdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpSUdac2IyOWtMVzl3WVdOcGRIazlJakVpSUhKbGMzVnNkRDBpWm14dmIyUkdhV3hzSWk4K1BHWmxWSFZ5WW5Wc1pXNWpaU0JpWVhObFJuSmxjWFZsYm1ONVBTSXVOQ0lnYm5WdFQyTjBZWFpsY3owaU15SWdjbVZ6ZFd4MFBTSk9iMmx6WlNJZ2RIbHdaVDBpWm5KaFkzUmhiRTV2YVhObElpOCtQR1psUW14bGJtUWdhVzQ5SWs1dmFYTmxJaUJwYmpJOUltWnNiMjlrUm1sc2JDSWdiVzlrWlQwaWMyOW1kQzFzYVdkb2RDSXZQand2Wm1sc2RHVnlQanh3WVhSb0lHbGtQU0pNYjJkdklpQm1hV3hzUFNJalptWm1JaUJtYVd4c0xXOXdZV05wZEhrOUlpNHhJaUJrUFNKdE1UTXpMalUxT1N3eE1qUXVNRE0wWXkwdU1ERXpMREl1TkRFeUxURXVNRFU1TERRdU9EUTRMVEl1T1RJekxEWXVOREF5TFRJdU5UVTRMREV1T0RFNUxUVXVNVFk0TERNdU5ETTVMVGN1T0RnNExEUXVPVGsyTFRFMExqUTBMRGd1TWpZeUxUTXhMakEwTnl3eE1pNDFOalV0TkRjdU5qYzBMREV5TGpVMk9TMDRMamcxT0M0d016WXRNVGN1T0RNNExURXVNamN5TFRJMkxqTXlPQzB6TGpZMk15MDVMamd3TmkweUxqYzJOaTB4T1M0d09EY3ROeTR4TVRNdE1qY3VOVFl5TFRFeUxqYzNPQzB4TXk0NE5ESXRPQzR3TWpVc09TNDBOamd0TWpndU5qQTJMREUyTGpFMU15MHpOUzR5TmpWb01HTXlMakF6TlMweExqZ3pPQ3cwTGpJMU1pMHpMalUwTml3MkxqUTJNeTAxTGpJeU5HZ3dZell1TkRJNUxUVXVOalUxTERFMkxqSXhPQzB5TGpnek5Td3lNQzR6TlRnc05DNHhOeXcwTGpFME15dzFMakExTnl3NExqZ3hOaXc1TGpZME9Td3hNeTQ1TWl3eE15NDNNelJvTGpBek4yTTFMamN6Tml3MkxqUTJNU3d4TlM0ek5UY3RNaTR5TlRNc09TNHpPQzA0TGpRNExEQXNNQzB6TGpVeE5TMHpMalV4TlMwekxqVXhOUzB6TGpVeE5TMHhNUzQwT1MweE1TNDBOemd0TlRJdU5qVTJMVFV5TGpZMk5DMDJOQzQ0TXpjdE5qUXVPRE0zYkM0d05Ea3RMakF6TjJNdE1TNDNNalV0TVM0Mk1EWXRNaTQzTVRrdE15NDRORGN0TWk0M05URXROaTR5TURSb01HTXRMakEwTmkweUxqTTNOU3d4TGpBMk1pMDBMalU0TWl3eUxqY3lOaTAyTGpJeU9XZ3diQzR4T0RVdExqRTBPR2d3WXk0d09Ua3RMakEyTWl3dU1qSXlMUzR4TkRnc0xqTTNMUzR5TlRsb01HTXlMakEyTFRFdU16WXlMRE11T1RVeExUSXVOakl4TERZdU1EUTBMVE11T0RReVF6VTNMamMyTXkwekxqUTNNeXc1Tnk0M05pMHlMak0wTVN3eE1qZ3VOak0zTERFNExqTXpNbU14Tmk0Mk56RXNPUzQ1TkRZdE1qWXVNelEwTERVMExqZ3hNeTB6T0M0Mk5URXNOREF1TVRrNUxUWXVNams1TFRZdU1EazJMVEU0TGpBMk15MHhOeTQzTkRNdE1Ua3VOalk0TFRFNExqZ3hNUzAyTGpBeE5pMDBMakEwTnkweE15NHdOakVzTkM0M056WXROeTQzTlRJc09TNDNOVEZzTmpndU1qVTBMRFk0TGpNM01XTXhMamN5TkN3eExqWXdNU3d5TGpjeE5Dd3pMamcwTERJdU56TTRMRFl1TVRreVdpSXZQanh3WVhSb0lHbGtQU0pHYkc5aGRHbHVaMVJsZUhRaUlHWnBiR3c5SW01dmJtVWlJR1E5SWsweE1qVWdORFZvTnpVd2N6Z3dJREFnT0RBZ09EQjJOelV3Y3pBZ09EQWdMVGd3SURnd2FDMDNOVEJ6TFRnd0lEQWdMVGd3SUMwNE1IWXROelV3Y3pBZ0xUZ3dJRGd3SUMwNE1DSXZQanh5WVdScFlXeEhjbUZrYVdWdWRDQnBaRDBpVW1Ga2FXRnNSMnh2ZHlJK1BITjBiM0FnYjJabWMyVjBQU0l3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RFNUxESXlKU3cyTXlVcElpQnpkRzl3TFc5d1lXTnBkSGs5SWk0MklpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeE1EQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRHOXdMVzl3WVdOcGRIazlJakFpTHo0OEwzSmhaR2xoYkVkeVlXUnBaVzUwUGp4c2FXNWxZWEpIY21Ga2FXVnVkQ0JwWkQwaVUyRnVaRlJ2Y0NJZ2VERTlJakFsSWlCNU1UMGlNQ1VpUGp4emRHOXdJRzltWm5ObGREMGlNQ1VpSUhOMGIzQXRZMjlzYjNJOUltaHpiQ2d4T1N3eU1pVXNOak1sS1NJdlBqeHpkRzl3SUc5bVpuTmxkRDBpTVRBd0pTSWdjM1J2Y0MxamIyeHZjajBpYUhOc0tESXpNQ3d5TVNVc01URWxLU0l2UGp3dmJHbHVaV0Z5UjNKaFpHbGxiblErUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKVFlXNWtRbTkwZEc5dElpQjRNVDBpTVRBd0pTSWdlVEU5SWpFd01DVWlQanh6ZEc5d0lHOW1abk5sZEQwaU1UQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkRzl3TFdOdmJHOXlQU0pvYzJ3b01Ua3NNaklsTERZekpTa2lMejQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRNU0lnWkhWeVBTSTJjeUlnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJSFpoYkhWbGN6MGlNekFsT3pZd0pUc3hNakFsT3pZd0pUc3pNQ1U3SWk4K1BDOXNhVzVsWVhKSGNtRmthV1Z1ZEQ0OGJHbHVaV0Z5UjNKaFpHbGxiblFnYVdROUlraHZkWEpuYkdGemMxTjBjbTlyWlNJZ1ozSmhaR2xsYm5SVWNtRnVjMlp2Y20wOUluSnZkR0YwWlNnNU1Da2lJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J2Wm1aelpYUTlJalV3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RFNUxESXlKU3cyTXlVcElpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJNE1DVWlJSE4wYjNBdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp4bklHbGtQU0pJYjNWeVoyeGhjM01pUGp4d1lYUm9JR1E5SWswZ05UQXNNell3SUdFZ016QXdMRE13TUNBd0lERXNNU0EyTURBc01DQmhJRE13TUN3ek1EQWdNQ0F4TERFZ0xUWXdNQ3d3SWlCbWFXeHNQU0lqWm1abUlpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d01pSWdjM1J5YjJ0bFBTSjFjbXdvSTBodmRYSm5iR0Z6YzFOMGNtOXJaU2tpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0l2UGp4d1lYUm9JR1E5SW0wMU5qWXNNVFl4TGpJd01YWXROVE11T1RJMFl6QXRNVGt1TXpneUxUSXlMalV4TXkwek55NDFOak10TmpNdU16azRMVFV4TGpFNU9DMDBNQzQzTlRZdE1UTXVOVGt5TFRrMExqazBOaTB5TVM0d056a3RNVFV5TGpVNE55MHlNUzR3TnpsekxURXhNUzQ0TXpnc055NDBPRGN0TVRVeUxqWXdNaXd5TVM0d056bGpMVFF3TGpnNU15d3hNeTQyTXpZdE5qTXVOREV6TERNeExqZ3hOaTAyTXk0ME1UTXNOVEV1TVRrNGRqVXpMamt5TkdNd0xERTNMakU0TVN3eE55NDNNRFFzTXpNdU5ESTNMRFV3TGpJeU15dzBOaTR6T1RSMk1qZzBMamd3T1dNdE16SXVOVEU1TERFeUxqazJMVFV3TGpJeU15d3lPUzR5TURZdE5UQXVNakl6TERRMkxqTTVOSFkxTXk0NU1qUmpNQ3d4T1M0ek9ESXNNakl1TlRJc016Y3VOVFl6TERZekxqUXhNeXcxTVM0eE9UZ3NOREF1TnpZekxERXpMalU1TWl3NU5DNDVOVFFzTWpFdU1EYzVMREUxTWk0Mk1ESXNNakV1TURjNWN6RXhNUzQ0TXpFdE55NDBPRGNzTVRVeUxqVTROeTB5TVM0d056bGpOREF1T0RnMkxURXpMall6Tml3Mk15NHpPVGd0TXpFdU9ERTJMRFl6TGpNNU9DMDFNUzR4T1RoMkxUVXpMamt5TkdNd0xURTNMakU1TmkweE55NDNNRFF0TXpNdU5ETTFMVFV3TGpJeU15MDBOaTQwTURGV01qQTNMall3TTJNek1pNDFNVGt0TVRJdU9UWTNMRFV3TGpJeU15MHlPUzR5TURZc05UQXVNakl6TFRRMkxqUXdNVnB0TFRNME55NDBOaklzTlRjdU56a3piREV6TUM0NU5Ua3NNVE14TGpBeU55MHhNekF1T1RVNUxERXpNUzR3TVROV01qRTRMams1TkZwdE1qWXlMamt5TkM0d01qSjJNall5TGpBeE9Hd3RNVE13TGprek55MHhNekV1TURBMkxERXpNQzQ1TXpjdE1UTXhMakF4TTFvaUlHWnBiR3c5SWlNeE5qRTRNaklpUGp3dmNHRjBhRDQ4Y0c5c2VXZHZiaUJ3YjJsdWRITTlJak0xTUNBek5UQXVNREkySURReE5TNHdNeUF5T0RRdU9UYzRJREk0TlNBeU9EUXVPVGM0SURNMU1DQXpOVEF1TURJMklpQm1hV3hzUFNKMWNtd29JMU5oYm1SQ2IzUjBiMjBwSWk4K1BIQmhkR2dnWkQwaWJUUXhOaTR6TkRFc01qZ3hMamszTldNd0xDNDVNVFF0TGpNMU5Dd3hMamd3T1MweExqQXpOU3d5TGpZNExUVXVOVFF5TERjdU1EYzJMVE15TGpZMk1Td3hNaTQwTlMwMk5TNHlPQ3d4TWk0ME5TMHpNaTQyTWpRc01DMDFPUzQzTXpndE5TNHpOelF0TmpVdU1qZ3RNVEl1TkRVdExqWTRNUzB1T0RjeUxURXVNRE0xTFRFdU56WTNMVEV1TURNMUxUSXVOamdzTUMwdU9URTBMak0xTkMweExqZ3dPQ3d4TGpBek5TMHlMalkzTml3MUxqVTBNaTAzTGpBM05pd3pNaTQyTlRZdE1USXVORFVzTmpVdU1qZ3RNVEl1TkRVc016SXVOakU1TERBc05Ua3VOek00TERVdU16YzBMRFkxTGpJNExERXlMalExTGpZNE1TNDROamNzTVM0d016VXNNUzQzTmpJc01TNHdNelVzTWk0Mk56WmFJaUJtYVd4c1BTSjFjbXdvSTFOaGJtUlViM0FwSWk4K1BIQmhkR2dnWkQwaWJUUTRNUzQwTml3MU1EUXVNVEF4ZGpVNExqUTBPV010TWk0ek5TNDNOeTAwTGpneUxERXVOVEV0Tnk0ek9Td3lMakl6TFRNd0xqTXNPQzQxTkMwM05DNDJOU3d4TXk0NU1pMHhNalF1TURZc01UTXVPVEl0TlRNdU5pd3dMVEV3TVM0eU5DMDJMak16TFRFek1TNDBOeTB4Tmk0eE5uWXROVGd1TkRNNWFESTJNaTQ1TWxvaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkVKdmRIUnZiU2tpTHo0OFpXeHNhWEJ6WlNCamVEMGlNelV3SWlCamVUMGlOVEEwTGpFd01TSWdjbmc5SWpFek1TNDBOaklpSUhKNVBTSXlPQzR4TURnaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkZSdmNDa2lMejQ4WnlCbWFXeHNQU0p1YjI1bElpQnpkSEp2YTJVOUluVnliQ2dqU0c5MWNtZHNZWE56VTNSeWIydGxLU0lnYzNSeWIydGxMV3hwYm1WallYQTlJbkp2ZFc1a0lpQnpkSEp2YTJVdGJXbDBaWEpzYVcxcGREMGlNVEFpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0krUEhCaGRHZ2daRDBpYlRVMk5TNDJOREVzTVRBM0xqSTRZekFzT1M0MU16Y3ROUzQxTml3eE9DNDJNamt0TVRVdU5qYzJMREkyTGprM00yZ3RMakF5TTJNdE9TNHlNRFFzTnk0MU9UWXRNakl1TVRrMExERTBMalUyTWkwek9DNHhPVGNzTWpBdU5Ua3lMVE01TGpVd05Dd3hOQzQ1TXpZdE9UY3VNekkxTERJMExqTTFOUzB4TmpFdU56TXpMREkwTGpNMU5TMDVNQzQwT0N3d0xURTJOeTQ1TkRndE1UZ3VOVGd5TFRFNU9TNDVOVE10TkRRdU9UUTRhQzB1TURJell5MHhNQzR4TVRVdE9DNHpORFF0TVRVdU5qYzJMVEUzTGpRek55MHhOUzQyTnpZdE1qWXVPVGN6TERBdE16a3VOek0xTERrMkxqVTFOQzAzTVM0NU1qRXNNakUxTGpZMU1pMDNNUzQ1TWpGek1qRTFMall5T1N3ek1pNHhPRFVzTWpFMUxqWXlPU3czTVM0NU1qRmFJaTgrUEhCaGRHZ2daRDBpYlRFek5DNHpOaXd4TmpFdU1qQXpZekFzTXprdU56TTFMRGsyTGpVMU5DdzNNUzQ1TWpFc01qRTFMalkxTWl3M01TNDVNakZ6TWpFMUxqWXlPUzB6TWk0eE9EWXNNakUxTGpZeU9TMDNNUzQ1TWpFaUx6NDhiR2x1WlNCNE1UMGlNVE0wTGpNMklpQjVNVDBpTVRZeExqSXdNeUlnZURJOUlqRXpOQzR6TmlJZ2VUSTlJakV3Tnk0eU9DSXZQanhzYVc1bElIZ3hQU0kxTmpVdU5qUWlJSGt4UFNJeE5qRXVNakF6SWlCNE1qMGlOVFkxTGpZMElpQjVNajBpTVRBM0xqSTRJaTgrUEd4cGJtVWdlREU5SWpFNE5DNDFPRFFpSUhreFBTSXlNRFl1T0RJeklpQjRNajBpTVRnMExqVTROU0lnZVRJOUlqVXpOeTQxTnpraUx6NDhiR2x1WlNCNE1UMGlNakU0TGpFNE1TSWdlVEU5SWpJeE9DNHhNVGdpSUhneVBTSXlNVGd1TVRneElpQjVNajBpTlRZeUxqVXpOeUl2UGp4c2FXNWxJSGd4UFNJME9ERXVPREU0SWlCNU1UMGlNakU0TGpFME1pSWdlREk5SWpRNE1TNDRNVGtpSUhreVBTSTFOakl1TkRJNElpOCtQR3hwYm1VZ2VERTlJalV4TlM0ME1UVWlJSGt4UFNJeU1EY3VNelV5SWlCNE1qMGlOVEUxTGpReE5pSWdlVEk5SWpVek55NDFOemtpTHo0OGNHRjBhQ0JrUFNKdE1UZzBMalU0TERVek55NDFPR013TERVdU5EVXNOQzR5Tnl3eE1DNDJOU3d4TWk0d015d3hOUzQwTW1ndU1ESmpOUzQxTVN3ekxqTTVMREV5TGpjNUxEWXVOVFVzTWpFdU5UVXNPUzQwTWl3ek1DNHlNU3c1TGprc056Z3VNRElzTVRZdU1qZ3NNVE14TGpnekxERTJMakk0TERRNUxqUXhMREFzT1RNdU56WXROUzR6T0N3eE1qUXVNRFl0TVRNdU9USXNNaTQzTFM0M05pdzFMakk1TFRFdU5UUXNOeTQzTlMweUxqTTFMRGd1TnpjdE1pNDROeXd4Tmk0d05TMDJMakEwTERJeExqVTJMVGt1TkROb01HTTNMamMyTFRRdU56Y3NNVEl1TURRdE9TNDVOeXd4TWk0d05DMHhOUzQwTWlJdlBqeHdZWFJvSUdROUltMHhPRFF1TlRneUxEUTVNaTQyTlRaakxUTXhMak0xTkN3eE1pNDBPRFV0TlRBdU1qSXpMREk0TGpVNExUVXdMakl5TXl3ME5pNHhORElzTUN3NUxqVXpOaXcxTGpVMk5Dd3hPQzQyTWpjc01UVXVOamMzTERJMkxqazJPV2d1TURJeVl6Z3VOVEF6TERjdU1EQTFMREl3TGpJeE15d3hNeTQwTmpNc016UXVOVEkwTERFNUxqRTFPU3c1TGprNU9Td3pMams1TVN3eU1TNHlOamtzTnk0Mk1Ea3NNek11TlRrM0xERXdMamM0T0N3ek5pNDBOU3c1TGpRd055dzRNaTR4T0RFc01UVXVNREF5TERFek1TNDRNelVzTVRVdU1EQXljemsxTGpNMk15MDFMalU1TlN3eE16RXVPREEzTFRFMUxqQXdNbU14TUM0NE5EY3RNaTQzT1N3eU1DNDROamN0TlM0NU1qWXNNamt1T1RJMExUa3VNelE1TERFdU1qUTBMUzQwTmpjc01pNDBOek10TGprME1pd3pMalkzTXkweExqUXlOQ3d4TkM0ek1qWXROUzQyT1RZc01qWXVNRE0xTFRFeUxqRTJNU3d6TkM0MU1qUXRNVGt1TVRjemFDNHdNakpqTVRBdU1URTBMVGd1TXpReUxERTFMalkzTnkweE55NDBNek1zTVRVdU5qYzNMVEkyTGprMk9Td3dMVEUzTGpVMk1pMHhPQzQ0TmprdE16TXVOalkxTFRVd0xqSXlNeTAwTmk0eE5TSXZQanh3WVhSb0lHUTlJbTB4TXpRdU16WXNOVGt5TGpjeVl6QXNNemt1TnpNMUxEazJMalUxTkN3M01TNDVNakVzTWpFMUxqWTFNaXczTVM0NU1qRnpNakUxTGpZeU9TMHpNaTR4T0RZc01qRTFMall5T1MwM01TNDVNakVpTHo0OGJHbHVaU0I0TVQwaU1UTTBMak0ySWlCNU1UMGlOVGt5TGpjeUlpQjRNajBpTVRNMExqTTJJaUI1TWowaU5UTTRMamM1TnlJdlBqeHNhVzVsSUhneFBTSTFOalV1TmpRaUlIa3hQU0kxT1RJdU56SWlJSGd5UFNJMU5qVXVOalFpSUhreVBTSTFNemd1TnprM0lpOCtQSEJ2Ykhsc2FXNWxJSEJ2YVc1MGN6MGlORGd4TGpneU1pQTBPREV1T1RBeElEUTRNUzQzT1RnZ05EZ3hMamczTnlBME9ERXVOemMxSURRNE1TNDROVFFnTXpVd0xqQXhOU0F6TlRBdU1ESTJJREl4T0M0eE9EVWdNakU0TGpFeU9TSXZQanh3YjJ4NWJHbHVaU0J3YjJsdWRITTlJakl4T0M0eE9EVWdORGd4TGprd01TQXlNVGd1TWpNeElEUTRNUzQ0TlRRZ016VXdMakF4TlNBek5UQXVNREkySURRNE1TNDRNaklnTWpFNExqRTFNaUl2UGp3dlp6NDhMMmMrUEdjZ2FXUTlJbEJ5YjJkeVpYTnpJaUJtYVd4c1BTSWpabVptSWo0OGNtVmpkQ0IzYVdSMGFEMGlNakE0SWlCb1pXbG5hSFE5SWpFd01DSWdabWxzYkMxdmNHRmphWFI1UFNJdU1ETWlJSEo0UFNJeE5TSWdjbms5SWpFMUlpQnpkSEp2YTJVOUlpTm1abVlpSUhOMGNtOXJaUzF2Y0dGamFYUjVQU0l1TVNJZ2MzUnliMnRsTFhkcFpIUm9QU0kwSWk4K1BIUmxlSFFnZUQwaU1qQWlJSGs5SWpNMElpQm1iMjUwTFdaaGJXbHNlVDBpSjBOdmRYSnBaWElnVG1WM0p5eEJjbWxoYkN4dGIyNXZjM0JoWTJVaUlHWnZiblF0YzJsNlpUMGlNakp3ZUNJK1VISnZaM0psYzNNOEwzUmxlSFErUEhSbGVIUWdlRDBpTWpBaUlIazlJamN5SWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krTWpVbFBDOTBaWGgwUGp4bklHWnBiR3c5SW01dmJtVWlQanhqYVhKamJHVWdZM2c5SWpFMk5pSWdZM2s5SWpVd0lpQnlQU0l5TWlJZ2MzUnliMnRsUFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRISnZhMlV0ZDJsa2RHZzlJakV3SWk4K1BHTnBjbU5zWlNCamVEMGlNVFkySWlCamVUMGlOVEFpSUhCaGRHaE1aVzVuZEdnOUlqRXdNREF3SWlCeVBTSXlNaUlnYzNSeWIydGxQU0pvYzJ3b01Ua3NNaklsTERZekpTa2lJSE4wY205clpTMWtZWE5vWVhKeVlYazlJakV3TURBd0lpQnpkSEp2YTJVdFpHRnphRzltWm5ObGREMGlOelV3TUNJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW5KdmRXNWtJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqVWlJSFJ5WVc1elptOXliVDBpY205MFlYUmxLQzA1TUNraUlIUnlZVzV6Wm05eWJTMXZjbWxuYVc0OUlqRTJOaUExTUNJdlBqd3ZaejQ4TDJjK1BHY2dhV1E5SWxOMFlYUjFjeUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakU0TkNJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBsTjBZWFIxY3p3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l5TUNJZ2VUMGlOeklpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajVUZEhKbFlXMXBibWM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pCYlc5MWJuUWlJR1pwYkd3OUlpTm1abVlpUGp4eVpXTjBJSGRwWkhSb1BTSXhNakFpSUdobGFXZG9kRDBpTVRBd0lpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d015SWdjbmc5SWpFMUlpQnllVDBpTVRVaUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMVzl3WVdOcGRIazlJaTR4SWlCemRISnZhMlV0ZDJsa2RHZzlJalFpTHo0OGRHVjRkQ0I0UFNJeU1DSWdlVDBpTXpRaUlHWnZiblF0Wm1GdGFXeDVQU0luUTI5MWNtbGxjaUJPWlhjbkxFRnlhV0ZzTEcxdmJtOXpjR0ZqWlNJZ1ptOXVkQzF6YVhwbFBTSXlNbkI0SWo1QmJXOTFiblE4TDNSbGVIUStQSFJsZUhRZ2VEMGlNakFpSUhrOUlqY3lJaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1p2Ym5RdGMybDZaVDBpTWpad2VDSStKaU00T0RBMU95QXhNRXM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pFZFhKaGRHbHZiaUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakUxTWlJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBrUjFjbUYwYVc5dVBDOTBaWGgwUGp4MFpYaDBJSGc5SWpJd0lpQjVQU0kzTWlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGlac2REc2dNU0JFWVhrOEwzUmxlSFErUEM5blBqd3ZaR1ZtY3o0OGRHVjRkQ0IwWlhoMExYSmxibVJsY21sdVp6MGliM0IwYVcxcGVtVlRjR1ZsWkNJK1BIUmxlSFJRWVhSb0lITjBZWEowVDJabWMyVjBQU0l0TVRBd0pTSWdhSEpsWmowaUkwWnNiMkYwYVc1blZHVjRkQ0lnWm1sc2JEMGlJMlptWmlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ0SWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGp4aGJtbHRZWFJsSUdGa1pHbDBhWFpsUFNKemRXMGlJR0YwZEhKcFluVjBaVTVoYldVOUluTjBZWEowVDJabWMyVjBJaUJpWldkcGJqMGlNSE1pSUdSMWNqMGlOVEJ6SWlCbWNtOXRQU0l3SlNJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhSdlBTSXhNREFsSWk4K01IZ3pNemd4WTJReE9HVXlabUkwWkdJeU16WmlaakExTWpVNU16aGhZalpsTkROa1lqQTBOREJtSU9LQW9pQlRZV0pzYVdWeUlGWXlJRXh2WTJ0MWNDQk1hVzVsWVhJOEwzUmxlSFJRWVhSb1BqeDBaWGgwVUdGMGFDQnpkR0Z5ZEU5bVpuTmxkRDBpTUNVaUlHaHlaV1k5SWlOR2JHOWhkR2x1WjFSbGVIUWlJR1pwYkd3OUlpTm1abVlpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm1sc2JDMXZjR0ZqYVhSNVBTSXVPQ0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajQ4WVc1cGJXRjBaU0JoWkdScGRHbDJaVDBpYzNWdElpQmhkSFJ5YVdKMWRHVk9ZVzFsUFNKemRHRnlkRTltWm5ObGRDSWdZbVZuYVc0OUlqQnpJaUJrZFhJOUlqVXdjeUlnWm5KdmJUMGlNQ1VpSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUIwYnowaU1UQXdKU0l2UGpCNE16TTRNV05rTVRobE1tWmlOR1JpTWpNMlltWXdOVEkxT1RNNFlXSTJaVFF6WkdJd05EUXdaaURpZ0tJZ1UyRmliR2xsY2lCV01pQk1iMk5yZFhBZ1RHbHVaV0Z5UEM5MFpYaDBVR0YwYUQ0OGRHVjRkRkJoZEdnZ2MzUmhjblJQWm1aelpYUTlJaTAxTUNVaUlHaHlaV1k5SWlOR2JHOWhkR2x1WjFSbGVIUWlJR1pwYkd3OUlpTm1abVlpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm1sc2JDMXZjR0ZqYVhSNVBTSXVPQ0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajQ4WVc1cGJXRjBaU0JoWkdScGRHbDJaVDBpYzNWdElpQmhkSFJ5YVdKMWRHVk9ZVzFsUFNKemRHRnlkRTltWm5ObGRDSWdZbVZuYVc0OUlqQnpJaUJrZFhJOUlqVXdjeUlnWm5KdmJUMGlNQ1VpSUhKbGNHVmhkRU52ZFc1MFBTSnBibVJsWm1sdWFYUmxJaUIwYnowaU1UQXdKU0l2UGpCNE1ETmhObUU0TkdOa056WXlaRGszTURkaE1qRTJNRFZpTlRRNFlXRmhZamc1TVRVMk1tRmhZaURpZ0tJZ1JFRkpQQzkwWlhoMFVHRjBhRDQ4ZEdWNGRGQmhkR2dnYzNSaGNuUlBabVp6WlhROUlqVXdKU0lnYUhKbFpqMGlJMFpzYjJGMGFXNW5WR1Y0ZENJZ1ptbHNiRDBpSTJabVppSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1hV3hzTFc5d1lXTnBkSGs5SWk0NElpQm1iMjUwTFhOcGVtVTlJakkyY0hnaVBqeGhibWx0WVhSbElHRmtaR2wwYVhabFBTSnpkVzBpSUdGMGRISnBZblYwWlU1aGJXVTlJbk4wWVhKMFQyWm1jMlYwSWlCaVpXZHBiajBpTUhNaUlHUjFjajBpTlRCeklpQm1jbTl0UFNJd0pTSWdjbVZ3WldGMFEyOTFiblE5SW1sdVpHVm1hVzVwZEdVaUlIUnZQU0l4TURBbElpOCtNSGd3TTJFMllUZzBZMlEzTmpKa09UY3dOMkV5TVRZd05XSTFORGhoWVdGaU9Ea3hOVFl5WVdGaUlPS0FvaUJFUVVrOEwzUmxlSFJRWVhSb1Bqd3ZkR1Y0ZEQ0OGRYTmxJR2h5WldZOUlpTkhiRzkzSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ1SWk4K1BIVnpaU0JvY21WbVBTSWpSMnh2ZHlJZ2VEMGlNVEF3TUNJZ2VUMGlNVEF3TUNJZ1ptbHNiQzF2Y0dGamFYUjVQU0l1T1NJdlBqeDFjMlVnYUhKbFpqMGlJMHh2WjI4aUlIZzlJakUzTUNJZ2VUMGlNVGN3SWlCMGNtRnVjMlp2Y20wOUluTmpZV3hsS0M0MktTSXZQangxYzJVZ2FISmxaajBpSTBodmRYSm5iR0Z6Y3lJZ2VEMGlNVFV3SWlCNVBTSTVNQ0lnZEhKaGJuTm1iM0p0UFNKeWIzUmhkR1VvTVRBcElpQjBjbUZ1YzJadmNtMHRiM0pwWjJsdVBTSTFNREFnTlRBd0lpOCtQSFZ6WlNCb2NtVm1QU0lqVUhKdlozSmxjM01pSUhnOUlqRTBOQ0lnZVQwaU56a3dJaTgrUEhWelpTQm9jbVZtUFNJalUzUmhkSFZ6SWlCNFBTSXpOamdpSUhrOUlqYzVNQ0l2UGp4MWMyVWdhSEpsWmowaUkwRnRiM1Z1ZENJZ2VEMGlOVFk0SWlCNVBTSTNPVEFpTHo0OGRYTmxJR2h5WldZOUlpTkVkWEpoZEdsdmJpSWdlRDBpTnpBMElpQjVQU0kzT1RBaUx6NDhMM04yWno0PSJ9"; assertEq(actualTokenURI, expectedTokenURI, "token URI"); diff --git a/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree index 5c078940d..dcab9a745 100644 --- a/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree +++ b/test/core/integration/concrete/lockup-linear/token-uri/tokenURI.tree @@ -1,4 +1,4 @@ -TokenURI_LockupLinear_Integration_Concrete_Test +TokenURI_Lockup_Linear_Integration_Concrete_Test ├── given NFT not exist │ └── it should revert └── given NFT exists 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 5d4bd2bd9..37c18c611 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 @@ -2,34 +2,34 @@ pragma solidity >=0.8.22 <0.9.0; import { WithdrawableAmountOf_Integration_Concrete_Test } from - "./../../lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { LockupLinear_Integration_Shared_Test, Integration_Test } from "./../LockupLinear.t.sol"; + "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; +import { Lockup_Linear_Integration_Shared_Test, Integration_Test } from "./../LockupLinear.t.sol"; -contract WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawableAmountOf_Lockup_Linear_Integration_Concrete_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } function test_GivenCliffTimeInFuture() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.CLIFF_TIME() - 1 }); - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } function test_GivenNoPreviousWithdrawals() external givenSTREAMINGStatus givenCliffTimeNotInFuture { - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = defaults.WITHDRAW_AMOUNT(); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } function test_GivenPreviousWithdrawal() external givenSTREAMINGStatus givenCliffTimeNotInFuture { - lockupLinear.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.WITHDRAW_AMOUNT() }); - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } diff --git a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree index 2ae1655de..716a4eaf5 100644 --- a/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree +++ b/test/core/integration/concrete/lockup-linear/withdrawable-amount-of/withdrawableAmountOf.tree @@ -1,4 +1,4 @@ -WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test +WithdrawableAmountOf_Lockup_Linear_Integration_Concrete_Test └── given STREAMING status ├── given cliff time in future │ └── it should return zero diff --git a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol index 5e71142de..5c5b4e0b2 100644 --- a/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/concrete/lockup-tranched/LockupTranched.t.sol @@ -2,339 +2,365 @@ pragma solidity >=0.8.22 <0.9.0; import { Integration_Test } from "./../../Integration.t.sol"; -import { LockupTranched_Integration_Shared_Test } from "./../../shared/lockup-tranched/LockupTranched.t.sol"; -import { AllowToHook_Integration_Concrete_Test } from "./../lockup/allow-to-hook/allowToHook.t.sol"; -import { Batch_Integration_Concrete_Test } from "./../lockup/batch/batch.t.sol"; -import { Burn_Integration_Concrete_Test } from "./../lockup/burn/burn.t.sol"; -import { CancelMultiple_Integration_Concrete_Test } from "./../lockup/cancel-multiple/cancelMultiple.t.sol"; -import { Cancel_Integration_Concrete_Test } from "./../lockup/cancel/cancel.t.sol"; -import { GetAsset_Integration_Concrete_Test } from "./../lockup/get-asset/getAsset.t.sol"; -import { GetDepositedAmount_Integration_Concrete_Test } from "./../lockup/get-deposited-amount/getDepositedAmount.t.sol"; -import { GetEndTime_Integration_Concrete_Test } from "./../lockup/get-end-time/getEndTime.t.sol"; -import { GetRecipient_Integration_Concrete_Test } from "./../lockup/get-recipient/getRecipient.t.sol"; -import { GetRefundedAmount_Integration_Concrete_Test } from "./../lockup/get-refunded-amount/getRefundedAmount.t.sol"; -import { GetSender_Integration_Concrete_Test } from "./../lockup/get-sender/getSender.t.sol"; -import { GetStartTime_Integration_Concrete_Test } from "./../lockup/get-start-time/getStartTime.t.sol"; -import { GetWithdrawnAmount_Integration_Concrete_Test } from "./../lockup/get-withdrawn-amount/getWithdrawnAmount.t.sol"; -import { IsAllowedToHook_Integration_Concrete_Test } from "./../lockup/is-allowed-to-hook/isAllowedToHook.t.sol"; -import { IsCancelable_Integration_Concrete_Test } from "./../lockup/is-cancelable/isCancelable.t.sol"; -import { IsCold_Integration_Concrete_Test } from "./../lockup/is-cold/isCold.t.sol"; -import { IsDepleted_Integration_Concrete_Test } from "./../lockup/is-depleted/isDepleted.t.sol"; -import { IsStream_Integration_Concrete_Test } from "./../lockup/is-stream/isStream.t.sol"; -import { IsTransferable_Integration_Concrete_Test } from "./../lockup/is-transferable/isTransferable.t.sol"; -import { IsWarm_Integration_Concrete_Test } from "./../lockup/is-warm/isWarm.t.sol"; -import { RefundableAmountOf_Integration_Concrete_Test } from "./../lockup/refundable-amount-of/refundableAmountOf.t.sol"; -import { Renounce_Integration_Concrete_Test } from "./../lockup/renounce/renounce.t.sol"; -import { SetNFTDescriptor_Integration_Concrete_Test } from "./../lockup/set-nft-descriptor/setNFTDescriptor.t.sol"; -import { StatusOf_Integration_Concrete_Test } from "./../lockup/status-of/statusOf.t.sol"; -import { TransferFrom_Integration_Concrete_Test } from "./../lockup/transfer-from/transferFrom.t.sol"; -import { WasCanceled_Integration_Concrete_Test } from "./../lockup/was-canceled/wasCanceled.t.sol"; -import { WithdrawHooks_Integration_Concrete_Test } from "./../lockup/withdraw-hooks/withdrawHooks.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/withdraw-max-and-transfer/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMax_Integration_Concrete_Test } from "./../lockup/withdraw-max/withdrawMax.t.sol"; -import { WithdrawMultiple_Integration_Concrete_Test } from "./../lockup/withdraw-multiple/withdrawMultiple.t.sol"; -import { Withdraw_Integration_Concrete_Test } from "./../lockup/withdraw/withdraw.t.sol"; - + "./../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_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract AllowToHook_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, AllowToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract Batch_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract Batch_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, Batch_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract Burn_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract Burn_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, Burn_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract Cancel_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract Cancel_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, Cancel_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +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(LockupTranched_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) + override(Lockup_Tranched_Integration_Shared_Test, CancelMultiple_Integration_Concrete_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + Lockup_Tranched_Integration_Shared_Test.setUp(); CancelMultiple_Integration_Concrete_Test.setUp(); } } -contract GetAsset_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetAsset_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetAsset_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetDepositedAmount_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetDepositedAmount_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetDepositedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetEndTime_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetEndTime_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetEndTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetRecipient_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetRecipient_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetRecipient_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetRefundedAmount_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetRefundedAmount_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetRefundedAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetSender_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetSender_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetSender_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetStartTime_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetStartTime_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetStartTime_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetWithdrawnAmount_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract GetWithdrawnAmount_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, GetWithdrawnAmount_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsAllowedToHook_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsAllowedToHook_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsAllowedToHook_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsCancelable_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsCancelable_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsCancelable_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsCold_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsCold_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsCold_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsDepleted_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsDepleted_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsDepleted_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsStream_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsStream_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsStream_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsTransferable_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsTransferable_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsTransferable_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract IsWarm_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract IsWarm_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, IsWarm_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract RefundableAmountOf_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract RefundableAmountOf_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, RefundableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract Renounce_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract Renounce_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, Renounce_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract SetNFTDescriptor_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract SetNFTDescriptor_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, SetNFTDescriptor_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract StatusOf_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract StatusOf_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, StatusOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract TransferFrom_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract TransferFrom_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test { function setUp() public virtual - override(LockupTranched_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) + override(Lockup_Tranched_Integration_Shared_Test, TransferFrom_Integration_Concrete_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + Lockup_Tranched_Integration_Shared_Test.setUp(); TransferFrom_Integration_Concrete_Test.setUp(); } } -contract WasCanceled_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract WasCanceled_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, WasCanceled_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract Withdraw_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract Withdraw_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, Withdraw_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawHooks_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawHooks_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test { function setUp() public virtual - override(LockupTranched_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) + override(Lockup_Tranched_Integration_Shared_Test, WithdrawHooks_Integration_Concrete_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + Lockup_Tranched_Integration_Shared_Test.setUp(); WithdrawHooks_Integration_Concrete_Test.setUp(); } } -contract WithdrawMax_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawMax_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawMax_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +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(LockupTranched_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) + override(Lockup_Tranched_Integration_Shared_Test, WithdrawMultiple_Integration_Concrete_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + Lockup_Tranched_Integration_Shared_Test.setUp(); WithdrawMultiple_Integration_Concrete_Test.setUp(); } } diff --git a/test/core/integration/concrete/lockup-tranched/constructor.t.sol b/test/core/integration/concrete/lockup-tranched/constructor.t.sol deleted file mode 100644 index 25f87935e..000000000 --- a/test/core/integration/concrete/lockup-tranched/constructor.t.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { UD60x18 } from "@prb/math/src/UD60x18.sol"; - -import { IAdminable } from "src/core/interfaces/IAdminable.sol"; -import { SablierLockupTranched } from "src/core/SablierLockupTranched.sol"; - -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; - -contract Constructor_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { - function test_Constructor() external { - // Expect the relevant event to be emitted. - vm.expectEmit(); - emit IAdminable.TransferAdmin({ oldAdmin: address(0), newAdmin: users.admin }); - - // Construct the contract. - SablierLockupTranched constructedLockupTranched = new SablierLockupTranched({ - initialAdmin: users.admin, - initialNFTDescriptor: nftDescriptor, - maxTrancheCount: defaults.MAX_TRANCHE_COUNT() - }); - - // {SablierLockup.constant} - UD60x18 actualMaxBrokerFee = constructedLockupTranched.MAX_BROKER_FEE(); - UD60x18 expectedMaxBrokerFee = UD60x18.wrap(0.1e18); - assertEq(actualMaxBrokerFee, expectedMaxBrokerFee, "MAX_BROKER_FEE"); - - // {SablierLockup.constructor} - address actualAdmin = constructedLockupTranched.admin(); - address expectedAdmin = users.admin; - assertEq(actualAdmin, expectedAdmin, "admin"); - - uint256 actualStreamId = constructedLockupTranched.nextStreamId(); - uint256 expectedStreamId = 1; - assertEq(actualStreamId, expectedStreamId, "nextStreamId"); - - address actualNFTDescriptor = address(constructedLockupTranched.nftDescriptor()); - address expectedNFTDescriptor = address(nftDescriptor); - assertEq(actualNFTDescriptor, expectedNFTDescriptor, "nftDescriptor"); - - // {SablierLockup.supportsInterface} - assertTrue(constructedLockupTranched.supportsInterface(0x49064906), "ERC-4906 interface ID"); - - // {SablierLockupTranched.constructor} - uint256 actualMaxTrancheCount = constructedLockupTranched.MAX_TRANCHE_COUNT(); - uint256 expectedMaxTrancheCount = defaults.MAX_TRANCHE_COUNT(); - assertEq(actualMaxTrancheCount, expectedMaxTrancheCount, "MAX_TRANCHE_COUNT"); - } -} diff --git a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol similarity index 67% rename from test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol rename to test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol index 706fee3a7..bc5742b56 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.t.sol @@ -3,31 +3,32 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.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 { LockupTranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "./../LockupTranched.t.sol"; -contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { +contract CreateWithDurationsLT_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupTranched_Integration_Shared_Test.setUp(); - streamId = lockupTranched.nextStreamId(); + Lockup_Tranched_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupTranched.createWithDurations, defaults.createWithDurationsLT()); - (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); + bytes memory callData = abi.encodeCall( + ISablierLockup.createWithDurationsLT, (defaults.createWithDurations(), defaults.tranchesWithDurations()) + ); + (bool success, bytes memory returnData) = address(lockup).delegatecall(callData); expectRevertDueToDelegateCall(success, returnData); } function test_RevertWhen_TrancheCountExceedsMaxValue() external whenNoDelegateCall { LockupTranched.TrancheWithDuration[] memory tranches = new LockupTranched.TrancheWithDuration[](25_000); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupTranched_TrancheCountTooHigh.selector, 25_000)); - createDefaultStreamWithDurations(tranches); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, 25_000)); + createDefaultStreamWithDurationsLT(tranches); } function test_RevertWhen_FirstIndexHasZeroDuration() @@ -36,18 +37,18 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT whenTrancheCountNotExceedMaxValue { uint40 startTime = getBlockTimestamp(); - LockupTranched.TrancheWithDuration[] memory tranches = defaults.createWithDurationsLT().tranches; + LockupTranched.TrancheWithDuration[] memory tranches = defaults.tranchesWithDurations(); tranches[2].duration = 0; uint256 index = 2; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration + tranches[1].duration, startTime + tranches[0].duration + tranches[1].duration ) ); - createDefaultStreamWithDurations(tranches); + createDefaultStreamWithDurationsLT(tranches); } function test_RevertWhen_StartTimeExceedsFirstTimestamp() @@ -63,12 +64,12 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT tranches[0].duration = MAX_UINT40; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, startTime, startTime + tranches[0].duration ) ); - createDefaultStreamWithDurations(tranches); + createDefaultStreamWithDurationsLT(tranches); } } @@ -93,7 +94,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, index, startTime + tranches[0].duration, startTime + tranches[0].duration + tranches[1].duration @@ -101,7 +102,7 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT ); // Create the stream. - createDefaultStreamWithDurations(tranches); + createDefaultStreamWithDurationsLT(tranches); } } @@ -116,8 +117,8 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT // Declare the timestamps. uint40 blockTimestamp = getBlockTimestamp(); - LockupTranched.Timestamps memory timestamps = - LockupTranched.Timestamps({ start: blockTimestamp, end: blockTimestamp + defaults.TOTAL_DURATION() }); + Lockup.Timestamps memory timestamps = + Lockup.Timestamps({ start: blockTimestamp, cliff: 0, end: blockTimestamp + defaults.TOTAL_DURATION() }); LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); LockupTranched.Tranche[] memory tranches = defaults.tranches(); @@ -126,16 +127,16 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT tranches[2].timestamp = tranches[1].timestamp + tranchesWithDurations[2].duration; // It should perform the ERC-20 transfers. - expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: defaults.DEPOSIT_AMOUNT() }); + 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() }); // It should emit {MetadataUpdate} and {CreateLockupTranchedStream} events. - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupTranched) }); - emit ISablierLockupTranched.CreateLockupTranchedStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupTranchedStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -150,28 +151,34 @@ contract CreateWithDurations_LockupTranched_Integration_Concrete_Test is LockupT }); // Create the stream. - createDefaultStreamWithDurations(); - - // It should create the stream. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); - LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); - expectedStream.endTime = timestamps.end; - expectedStream.startTime = timestamps.start; - expectedStream.tranches = tranches; - assertEq(actualStream, expectedStream); + createDefaultStreamWithDurationsLT(); + + // 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.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getTranches(streamId), tranches, "tranches"); // Assert that the stream's status is "STREAMING". - Lockup.Status actualStatus = lockupTranched.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupTranched.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + 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-durations/createWithDurations.tree b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.tree similarity index 94% rename from test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree rename to test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.tree index 695948e74..375ee923e 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurations.tree +++ b/test/core/integration/concrete/lockup-tranched/create-with-durations/createWithDurationsLT.tree @@ -1,4 +1,4 @@ -CreateWithDurations_LockupTranched_Integration_Concrete_Test +CreateWithDurationsLT_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call diff --git a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol similarity index 76% rename from test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol rename to test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol index 28ad09d78..ad0ec2f15 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.t.sol @@ -7,35 +7,36 @@ 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 { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.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 { LockupTranched_Integration_Shared_Test } from "./../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "./../LockupTranched.t.sol"; -contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { +contract CreateWithTimestampsLT_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupTranched_Integration_Shared_Test.setUp(); - streamId = lockupTranched.nextStreamId(); + Lockup_Tranched_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function test_RevertWhen_DelegateCall() external { - bytes memory callData = - abi.encodeCall(ISablierLockupTranched.createWithTimestamps, defaults.createWithTimestampsLT()); - (bool success, bytes memory returnData) = address(lockupTranched).delegatecall(callData); + 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); - createDefaultStreamWithSender(address(0)); + createDefaultStreamWithSenderLT(address(0)); } function test_RevertWhen_RecipientZeroAddress() external whenNoDelegateCall whenSenderNotZeroAddress { address recipient = address(0); vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721InvalidReceiver.selector, recipient)); - createDefaultStreamWithRecipient(recipient); + createDefaultStreamWithRecipientLT(recipient); } function test_RevertWhen_DepositAmountZero() @@ -48,7 +49,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup // is hard coded to 10%. vm.expectRevert(Errors.SablierLockup_DepositAmountZero.selector); uint128 totalAmount = 0; - createDefaultStreamWithTotalAmount(totalAmount); + createDefaultStreamWithTotalAmountLT(totalAmount); } function test_RevertWhen_StartTimeZero() @@ -59,7 +60,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup whenDepositAmountNotZero { vm.expectRevert(Errors.SablierLockup_StartTimeZero.selector); - createDefaultStreamWithStartTime(0); + createDefaultStreamWithStartTimeLT(0); } function test_RevertWhen_TrancheCountZero() @@ -71,8 +72,8 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup whenStartTimeNotZero { LockupTranched.Tranche[] memory tranches; - vm.expectRevert(Errors.SablierLockupTranched_TrancheCountZero.selector); - createDefaultStreamWithTranches(tranches); + vm.expectRevert(Errors.SablierLockup_TrancheCountZero.selector); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_TrancheCountExceedsMaxValue() @@ -84,10 +85,11 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup whenStartTimeNotZero whenTrancheCountNotZero { - uint256 trancheCount = defaults.MAX_TRANCHE_COUNT() + 1; + uint256 trancheCount = defaults.MAX_COUNT() + 1; LockupTranched.Tranche[] memory tranches = new LockupTranched.Tranche[](trancheCount); - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupTranched_TrancheCountTooHigh.selector, trancheCount)); - createDefaultStreamWithTranches(tranches); + tranches[trancheCount - 1].timestamp = defaults.END_TIME(); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, trancheCount)); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_TrancheAmountsSumOverflows() @@ -104,7 +106,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup tranches[0].amount = MAX_UINT128; tranches[1].amount = 1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_StartTimeGreaterThanFirstTimestamp() @@ -125,14 +127,14 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) ); // Create the stream. - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_StartTimeEqualsFirstTimestamp() @@ -153,14 +155,14 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) ); // Create the stream. - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_TimestampsNotStrictlyIncreasing() @@ -183,7 +185,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup uint256 index = 1; vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_TrancheTimestampsNotOrdered.selector, + Errors.SablierLockup_TrancheTimestampsNotOrdered.selector, index, tranches[0].timestamp, tranches[1].timestamp @@ -191,7 +193,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup ); // Create the stream. - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function test_RevertWhen_DepositAmountNotEqualTrancheAmountsSum() @@ -214,20 +216,22 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup uint128 depositAmount = defaultDepositAmount + 100; // Prepare the params. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLT(); + 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.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + Errors.SablierLockup_DepositAmountNotEqualToTrancheAmountsSum.selector, depositAmount, defaultDepositAmount ) ); // Create the stream. - lockupTranched.createWithTimestamps(params); + lockup.createWithTimestampsLT(params, tranches); } function test_RevertWhen_BrokerFeeExceedsMaxValue() @@ -248,7 +252,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, brokerFee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(Broker({ account: users.broker, fee: brokerFee })); + createDefaultStreamWithBrokerLT(Broker({ account: users.broker, fee: brokerFee })); } function test_RevertWhen_AssetNotContract() @@ -272,7 +276,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup // Run the test. vm.expectRevert(abi.encodeWithSelector(Address.AddressEmptyCode.selector, nonContract)); - createDefaultStreamWithAsset(IERC20(nonContract)); + createDefaultStreamWithAssetLT(IERC20(nonContract)); } function test_WhenAssetMissesERC20ReturnValue() @@ -322,7 +326,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup expectCallToTransferFrom({ asset: IERC20(asset), from: funder, - to: address(lockupTranched), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); @@ -335,10 +339,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup }); // It should emit {CreateLockupTranchedStream} and {MetadataUpdate} events. - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: streamId }); - vm.expectEmit({ emitter: address(lockupTranched) }); - emit ISablierLockupTranched.CreateLockupTranchedStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupTranchedStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -353,26 +357,34 @@ contract CreateWithTimestamps_LockupTranched_Integration_Concrete_Test is Lockup }); // It should create the stream. - streamId = createDefaultStreamWithAsset(IERC20(asset)); + streamId = createDefaultStreamWithAssetLT(IERC20(asset)); - // Assert that the stream has been created. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); - LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); - expectedStream.asset = IERC20(asset); - assertEq(actualStream, expectedStream); + // 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 = lockupTranched.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.PENDING; assertEq(actualStatus, expectedStatus); // It should bump the next stream ID. - uint256 actualNextStreamId = lockupTranched.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // It should mint the NFT. - address actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + 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/createWithTimestamps.tree b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree similarity index 98% rename from test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree rename to test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree index 9f1273285..f6e6393e4 100644 --- a/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestamps.tree +++ b/test/core/integration/concrete/lockup-tranched/create-with-timestamps/createWithTimestampsLT.tree @@ -1,4 +1,4 @@ -CreateWithTimestamps_LockupTranched_Integration_Concrete_Test +CreateWithTimestampsLT_Integration_Concrete_Test ├── when delegate call │ └── it should revert └── when no delegate call diff --git a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol deleted file mode 100644 index c521db549..000000000 --- a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.t.sol +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -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 { LockupTranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; - -contract GetStream_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { - function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupTranched.getStream(nullStreamId); - } - - function test_GivenSettledStream() external givenNotNull { - vm.warp({ newTimestamp: defaults.END_TIME() }); - - // It should return the stream struct. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(defaultStreamId); - LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); - // It should always return stream as non-cancelable. - expectedStream.isCancelable = false; - assertEq(actualStream, expectedStream); - } - - function test_GivenNotSettledStream() external givenNotNull { - uint256 streamId = createDefaultStream(); - // It should return the stream struct. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); - LockupTranched.StreamLT memory expectedStream = defaults.lockupTranchedStream(); - assertEq(actualStream, expectedStream); - } -} diff --git a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree b/test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree deleted file mode 100644 index 74dbb72ca..000000000 --- a/test/core/integration/concrete/lockup-tranched/get-stream/getStream.tree +++ /dev/null @@ -1,9 +0,0 @@ -GetStream_LockupTranched_Integration_Concrete_Test -├── given null -│ └── it should revert -└── given not null - ├── given settled stream - │ ├── it should always return stream as non-cancelable - │ └── it should return the stream struct - └── given not settled stream - └── it should return the stream struct diff --git a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol index eefe31174..f4586cdc7 100644 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol +++ b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.t.sol @@ -2,21 +2,19 @@ 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 } from "src/core/types/DataTypes.sol"; -import { LockupTranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; -contract GetTimestamps_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { +contract GetTimestamps_Lockup_Tranched_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupTranched.getTimestamps(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getTimestamps(nullStreamId); } function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - LockupTranched.Timestamps memory actualTimestamps = lockupTranched.getTimestamps(streamId); - LockupTranched.Timestamps memory expectedTimestamps = defaults.lockupTranchedTimestamps(); + 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 index 894cda8eb..25af809be 100644 --- a/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree +++ b/test/core/integration/concrete/lockup-tranched/get-timestamps/getTimestamps.tree @@ -1,4 +1,4 @@ -GetTimestamps_LockupTranched_Integration_Concrete_Test +GetTimestamps_Lockup_Tranched_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null 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 015f15d67..6233a6c20 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 @@ -4,18 +4,16 @@ 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 { LockupTranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; -contract GetTranches_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { +contract GetTranches_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_Test { function test_RevertGiven_Null() external { - uint256 nullStreamId = 1729; - vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_Null.selector, nullStreamId)); - lockupTranched.getTranches(nullStreamId); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockupBase_Null.selector, nullStreamId)); + lockup.getTranches(nullStreamId); } function test_GivenNotNull() external { - uint256 streamId = createDefaultStream(); - LockupTranched.Tranche[] memory actualTranches = lockupTranched.getTranches(streamId); + 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 8e5ac629e..552166a59 100644 --- a/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree +++ b/test/core/integration/concrete/lockup-tranched/get-tranches/getTranches.tree @@ -1,4 +1,4 @@ -GetTranches_LockupTranched_Integration_Concrete_Test +GetTranches_Integration_Concrete_Test ├── given null │ └── it should revert └── given not null 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 5e50af371..fcff6997c 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 @@ -1,20 +1,21 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { StreamedAmountOf_Integration_Concrete_Test } from "./../../lockup/streamed-amount-of/streamedAmountOf.t.sol"; -import { LockupTranched_Integration_Shared_Test, Integration_Test } from "./../LockupTranched.t.sol"; +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"; -contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract StreamedAmountOf_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, StreamedAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() }); - uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -23,7 +24,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() + 1 seconds }); // It should return the deposited amount. - uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.DEPOSIT_AMOUNT(); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -37,7 +38,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + 1 seconds }); // It should return 0. - uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -51,7 +52,7 @@ contract StreamedAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.END_TIME() - 1 seconds }); // It should return the correct streamed amount. - uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = defaults.tranches()[0].amount + defaults.tranches()[1].amount; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } diff --git a/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree index 3c903d9d5..cae8b9a89 100644 --- a/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree +++ b/test/core/integration/concrete/lockup-tranched/streamed-amount-of/streamedAmountOf.tree @@ -1,4 +1,4 @@ -StreamedAmountOf_LockupTranched_Integration_Concrete_Test +StreamedAmountOf_Lockup_Tranched_Integration_Concrete_Test └── given STREAMING status ├── given start time in present │ └── it should return zero 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 bcfbfabfd..a6704c4d8 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 { LockupTranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "../LockupTranched.t.sol"; /// @dev Requirements for these tests to work: /// - The stream ID must be 1 @@ -16,22 +16,21 @@ import { LockupTranched_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_LockupTranched_Integration_Concrete_Test is LockupTranched_Integration_Shared_Test { - address internal constant LOCKUP_TRANCHED = 0xDB25A7b768311dE128BBDa7B8426c3f9C74f3240; +contract TokenURI_Lockup_Tranched_Integration_Concrete_Test is Lockup_Tranched_Integration_Shared_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. modifier skipOnMismatch() { - if (address(lockupTranched) == LOCKUP_TRANCHED) { + if (address(lockup) == LOCKUP) { _; } else { - console2.log(StdStyle.yellow('Warning: "lockupTranched.tokenURI" tests skipped due to address mismatch')); + console2.log(StdStyle.yellow('Warning: "lockup.tokenURI" tests skipped due to address mismatch')); } } function test_RevertGiven_NFTNotExist() external { - uint256 nullStreamId = 1729; vm.expectRevert(abi.encodeWithSelector(IERC721Errors.ERC721NonexistentToken.selector, nullStreamId)); - lockupTranched.tokenURI({ tokenId: nullStreamId }); + lockup.tokenURI({ tokenId: nullStreamId }); } /// @dev If you need to update the hard-coded token URI: @@ -40,7 +39,7 @@ contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Int function test_WhenTokenURIDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory tokenURI = lockupTranched.tokenURI(defaultStreamId); + string memory tokenURI = lockup.tokenURI(defaultStreamId); tokenURI = vm.replace({ input: tokenURI, from: "data:application/json;base64,", to: "" }); string memory actualDecodedTokenURI = string(Base64.decode(tokenURI)); string memory expectedDecodedTokenURI = @@ -51,7 +50,7 @@ contract TokenURI_LockupTranched_Integration_Concrete_Test is LockupTranched_Int function test_WhenTokenURINotDecoded() external skipOnMismatch givenNFTExists { vm.warp({ newTimestamp: defaults.START_TIME() + defaults.TOTAL_DURATION() / 4 }); - string memory actualTokenURI = lockupTranched.tokenURI(defaultStreamId); + string memory actualTokenURI = lockup.tokenURI(defaultStreamId); string memory expectedTokenURI = "data:application/json;base64,eyJhdHRyaWJ1dGVzIjpbeyJ0cmFpdF90eXBlIjoiQXNzZXQiLCJ2YWx1ZSI6IkRBSSJ9LHsidHJhaXRfdHlwZSI6IlNlbmRlciIsInZhbHVlIjoiMHg2MzMyZTdiMWRlYjFmMWEwYjc3YjJiYjE4YjE0NDMzMGM3MjkxYmNhIn0seyJ0cmFpdF90eXBlIjoiU3RhdHVzIiwidmFsdWUiOiJTdHJlYW1pbmcifV0sImRlc2NyaXB0aW9uIjoiVGhpcyBORlQgcmVwcmVzZW50cyBhIHBheW1lbnQgc3RyZWFtIGluIGEgU2FibGllciBWMiBMb2NrdXAgRHluYW1pYyBjb250cmFjdC4gVGhlIG93bmVyIG9mIHRoaXMgTkZUIGNhbiB3aXRoZHJhdyB0aGUgc3RyZWFtZWQgYXNzZXRzLCB3aGljaCBhcmUgZGVub21pbmF0ZWQgaW4gREFJLlxuXG4tIFN0cmVhbSBJRDogMVxuLSBMb2NrdXAgRHluYW1pYyBBZGRyZXNzOiAweGRiMjVhN2I3NjgzMTFkZTEyOGJiZGE3Yjg0MjZjM2Y5Yzc0ZjMyNDBcbi0gREFJIEFkZHJlc3M6IDB4MDNhNmE4NGNkNzYyZDk3MDdhMjE2MDViNTQ4YWFhYjg5MTU2MmFhYlxuXG7imqDvuI8gV0FSTklORzogVHJhbnNmZXJyaW5nIHRoZSBORlQgbWFrZXMgdGhlIG5ldyBvd25lciB0aGUgcmVjaXBpZW50IG9mIHRoZSBzdHJlYW0uIFRoZSBmdW5kcyBhcmUgbm90IGF1dG9tYXRpY2FsbHkgd2l0aGRyYXduIGZvciB0aGUgcHJldmlvdXMgcmVjaXBpZW50LiIsImV4dGVybmFsX3VybCI6Imh0dHBzOi8vc2FibGllci5jb20iLCJuYW1lIjoiU2FibGllciBWMiBMb2NrdXAgRHluYW1pYyAjMSIsImltYWdlIjoiZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCNGJXeHVjejBpYUhSMGNEb3ZMM2QzZHk1M015NXZjbWN2TWpBd01DOXpkbWNpSUhkcFpIUm9QU0l4TURBd0lpQm9aV2xuYUhROUlqRXdNREFpSUhacFpYZENiM2c5SWpBZ01DQXhNREF3SURFd01EQWlQanh5WldOMElIZHBaSFJvUFNJeE1EQWxJaUJvWldsbmFIUTlJakV3TUNVaUlHWnBiSFJsY2owaWRYSnNLQ05PYjJselpTa2lMejQ4Y21WamRDQjRQU0kzTUNJZ2VUMGlOekFpSUhkcFpIUm9QU0k0TmpBaUlHaGxhV2RvZEQwaU9EWXdJaUJtYVd4c1BTSWpabVptSWlCbWFXeHNMVzl3WVdOcGRIazlJaTR3TXlJZ2NuZzlJalExSWlCeWVUMGlORFVpSUhOMGNtOXJaVDBpSTJabVppSWdjM1J5YjJ0bExXOXdZV05wZEhrOUlpNHhJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqUWlMejQ4WkdWbWN6NDhZMmx5WTJ4bElHbGtQU0pIYkc5M0lpQnlQU0kxTURBaUlHWnBiR3c5SW5WeWJDZ2pVbUZrYVdGc1IyeHZkeWtpTHo0OFptbHNkR1Z5SUdsa1BTSk9iMmx6WlNJK1BHWmxSbXh2YjJRZ2VEMGlNQ0lnZVQwaU1DSWdkMmxrZEdnOUlqRXdNQ1VpSUdobGFXZG9kRDBpTVRBd0pTSWdabXh2YjJRdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpSUdac2IyOWtMVzl3WVdOcGRIazlJakVpSUhKbGMzVnNkRDBpWm14dmIyUkdhV3hzSWk4K1BHWmxWSFZ5WW5Wc1pXNWpaU0JpWVhObFJuSmxjWFZsYm1ONVBTSXVOQ0lnYm5WdFQyTjBZWFpsY3owaU15SWdjbVZ6ZFd4MFBTSk9iMmx6WlNJZ2RIbHdaVDBpWm5KaFkzUmhiRTV2YVhObElpOCtQR1psUW14bGJtUWdhVzQ5SWs1dmFYTmxJaUJwYmpJOUltWnNiMjlrUm1sc2JDSWdiVzlrWlQwaWMyOW1kQzFzYVdkb2RDSXZQand2Wm1sc2RHVnlQanh3WVhSb0lHbGtQU0pNYjJkdklpQm1hV3hzUFNJalptWm1JaUJtYVd4c0xXOXdZV05wZEhrOUlpNHhJaUJrUFNKdE1UTXpMalUxT1N3eE1qUXVNRE0wWXkwdU1ERXpMREl1TkRFeUxURXVNRFU1TERRdU9EUTRMVEl1T1RJekxEWXVOREF5TFRJdU5UVTRMREV1T0RFNUxUVXVNVFk0TERNdU5ETTVMVGN1T0RnNExEUXVPVGsyTFRFMExqUTBMRGd1TWpZeUxUTXhMakEwTnl3eE1pNDFOalV0TkRjdU5qYzBMREV5TGpVMk9TMDRMamcxT0M0d016WXRNVGN1T0RNNExURXVNamN5TFRJMkxqTXlPQzB6TGpZMk15MDVMamd3TmkweUxqYzJOaTB4T1M0d09EY3ROeTR4TVRNdE1qY3VOVFl5TFRFeUxqYzNPQzB4TXk0NE5ESXRPQzR3TWpVc09TNDBOamd0TWpndU5qQTJMREUyTGpFMU15MHpOUzR5TmpWb01HTXlMakF6TlMweExqZ3pPQ3cwTGpJMU1pMHpMalUwTml3MkxqUTJNeTAxTGpJeU5HZ3dZell1TkRJNUxUVXVOalUxTERFMkxqSXhPQzB5TGpnek5Td3lNQzR6TlRnc05DNHhOeXcwTGpFME15dzFMakExTnl3NExqZ3hOaXc1TGpZME9Td3hNeTQ1TWl3eE15NDNNelJvTGpBek4yTTFMamN6Tml3MkxqUTJNU3d4TlM0ek5UY3RNaTR5TlRNc09TNHpPQzA0TGpRNExEQXNNQzB6TGpVeE5TMHpMalV4TlMwekxqVXhOUzB6TGpVeE5TMHhNUzQwT1MweE1TNDBOemd0TlRJdU5qVTJMVFV5TGpZMk5DMDJOQzQ0TXpjdE5qUXVPRE0zYkM0d05Ea3RMakF6TjJNdE1TNDNNalV0TVM0Mk1EWXRNaTQzTVRrdE15NDRORGN0TWk0M05URXROaTR5TURSb01HTXRMakEwTmkweUxqTTNOU3d4TGpBMk1pMDBMalU0TWl3eUxqY3lOaTAyTGpJeU9XZ3diQzR4T0RVdExqRTBPR2d3WXk0d09Ua3RMakEyTWl3dU1qSXlMUzR4TkRnc0xqTTNMUzR5TlRsb01HTXlMakEyTFRFdU16WXlMRE11T1RVeExUSXVOakl4TERZdU1EUTBMVE11T0RReVF6VTNMamMyTXkwekxqUTNNeXc1Tnk0M05pMHlMak0wTVN3eE1qZ3VOak0zTERFNExqTXpNbU14Tmk0Mk56RXNPUzQ1TkRZdE1qWXVNelEwTERVMExqZ3hNeTB6T0M0Mk5URXNOREF1TVRrNUxUWXVNams1TFRZdU1EazJMVEU0TGpBMk15MHhOeTQzTkRNdE1Ua3VOalk0TFRFNExqZ3hNUzAyTGpBeE5pMDBMakEwTnkweE15NHdOakVzTkM0M056WXROeTQzTlRJc09TNDNOVEZzTmpndU1qVTBMRFk0TGpNM01XTXhMamN5TkN3eExqWXdNU3d5TGpjeE5Dd3pMamcwTERJdU56TTRMRFl1TVRreVdpSXZQanh3WVhSb0lHbGtQU0pHYkc5aGRHbHVaMVJsZUhRaUlHWnBiR3c5SW01dmJtVWlJR1E5SWsweE1qVWdORFZvTnpVd2N6Z3dJREFnT0RBZ09EQjJOelV3Y3pBZ09EQWdMVGd3SURnd2FDMDNOVEJ6TFRnd0lEQWdMVGd3SUMwNE1IWXROelV3Y3pBZ0xUZ3dJRGd3SUMwNE1DSXZQanh5WVdScFlXeEhjbUZrYVdWdWRDQnBaRDBpVW1Ga2FXRnNSMnh2ZHlJK1BITjBiM0FnYjJabWMyVjBQU0l3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RZeExEZzRKU3cwTUNVcElpQnpkRzl3TFc5d1lXTnBkSGs5SWk0MklpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJeE1EQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRHOXdMVzl3WVdOcGRIazlJakFpTHo0OEwzSmhaR2xoYkVkeVlXUnBaVzUwUGp4c2FXNWxZWEpIY21Ga2FXVnVkQ0JwWkQwaVUyRnVaRlJ2Y0NJZ2VERTlJakFsSWlCNU1UMGlNQ1VpUGp4emRHOXdJRzltWm5ObGREMGlNQ1VpSUhOMGIzQXRZMjlzYjNJOUltaHpiQ2cyTVN3NE9DVXNOREFsS1NJdlBqeHpkRzl3SUc5bVpuTmxkRDBpTVRBd0pTSWdjM1J2Y0MxamIyeHZjajBpYUhOc0tESXpNQ3d5TVNVc01URWxLU0l2UGp3dmJHbHVaV0Z5UjNKaFpHbGxiblErUEd4cGJtVmhja2R5WVdScFpXNTBJR2xrUFNKVFlXNWtRbTkwZEc5dElpQjRNVDBpTVRBd0pTSWdlVEU5SWpFd01DVWlQanh6ZEc5d0lHOW1abk5sZEQwaU1UQWxJaUJ6ZEc5d0xXTnZiRzl5UFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWk4K1BITjBiM0FnYjJabWMyVjBQU0l4TURBbElpQnpkRzl3TFdOdmJHOXlQU0pvYzJ3b05qRXNPRGdsTERRd0pTa2lMejQ4WVc1cGJXRjBaU0JoZEhSeWFXSjFkR1ZPWVcxbFBTSjRNU0lnWkhWeVBTSTJjeUlnY21Wd1pXRjBRMjkxYm5ROUltbHVaR1ZtYVc1cGRHVWlJSFpoYkhWbGN6MGlNekFsT3pZd0pUc3hNakFsT3pZd0pUc3pNQ1U3SWk4K1BDOXNhVzVsWVhKSGNtRmthV1Z1ZEQ0OGJHbHVaV0Z5UjNKaFpHbGxiblFnYVdROUlraHZkWEpuYkdGemMxTjBjbTlyWlNJZ1ozSmhaR2xsYm5SVWNtRnVjMlp2Y20wOUluSnZkR0YwWlNnNU1Da2lJR2R5WVdScFpXNTBWVzVwZEhNOUluVnpaWEpUY0dGalpVOXVWWE5sSWo0OGMzUnZjQ0J2Wm1aelpYUTlJalV3SlNJZ2MzUnZjQzFqYjJ4dmNqMGlhSE5zS0RZeExEZzRKU3cwTUNVcElpOCtQSE4wYjNBZ2IyWm1jMlYwUFNJNE1DVWlJSE4wYjNBdFkyOXNiM0k5SW1oemJDZ3lNekFzTWpFbExERXhKU2tpTHo0OEwyeHBibVZoY2tkeVlXUnBaVzUwUGp4bklHbGtQU0pJYjNWeVoyeGhjM01pUGp4d1lYUm9JR1E5SWswZ05UQXNNell3SUdFZ016QXdMRE13TUNBd0lERXNNU0EyTURBc01DQmhJRE13TUN3ek1EQWdNQ0F4TERFZ0xUWXdNQ3d3SWlCbWFXeHNQU0lqWm1abUlpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d01pSWdjM1J5YjJ0bFBTSjFjbXdvSTBodmRYSm5iR0Z6YzFOMGNtOXJaU2tpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0l2UGp4d1lYUm9JR1E5SW0wMU5qWXNNVFl4TGpJd01YWXROVE11T1RJMFl6QXRNVGt1TXpneUxUSXlMalV4TXkwek55NDFOak10TmpNdU16azRMVFV4TGpFNU9DMDBNQzQzTlRZdE1UTXVOVGt5TFRrMExqazBOaTB5TVM0d056a3RNVFV5TGpVNE55MHlNUzR3TnpsekxURXhNUzQ0TXpnc055NDBPRGN0TVRVeUxqWXdNaXd5TVM0d056bGpMVFF3TGpnNU15d3hNeTQyTXpZdE5qTXVOREV6TERNeExqZ3hOaTAyTXk0ME1UTXNOVEV1TVRrNGRqVXpMamt5TkdNd0xERTNMakU0TVN3eE55NDNNRFFzTXpNdU5ESTNMRFV3TGpJeU15dzBOaTR6T1RSMk1qZzBMamd3T1dNdE16SXVOVEU1TERFeUxqazJMVFV3TGpJeU15d3lPUzR5TURZdE5UQXVNakl6TERRMkxqTTVOSFkxTXk0NU1qUmpNQ3d4T1M0ek9ESXNNakl1TlRJc016Y3VOVFl6TERZekxqUXhNeXcxTVM0eE9UZ3NOREF1TnpZekxERXpMalU1TWl3NU5DNDVOVFFzTWpFdU1EYzVMREUxTWk0Mk1ESXNNakV1TURjNWN6RXhNUzQ0TXpFdE55NDBPRGNzTVRVeUxqVTROeTB5TVM0d056bGpOREF1T0RnMkxURXpMall6Tml3Mk15NHpPVGd0TXpFdU9ERTJMRFl6TGpNNU9DMDFNUzR4T1RoMkxUVXpMamt5TkdNd0xURTNMakU1TmkweE55NDNNRFF0TXpNdU5ETTFMVFV3TGpJeU15MDBOaTQwTURGV01qQTNMall3TTJNek1pNDFNVGt0TVRJdU9UWTNMRFV3TGpJeU15MHlPUzR5TURZc05UQXVNakl6TFRRMkxqUXdNVnB0TFRNME55NDBOaklzTlRjdU56a3piREV6TUM0NU5Ua3NNVE14TGpBeU55MHhNekF1T1RVNUxERXpNUzR3TVROV01qRTRMams1TkZwdE1qWXlMamt5TkM0d01qSjJNall5TGpBeE9Hd3RNVE13TGprek55MHhNekV1TURBMkxERXpNQzQ1TXpjdE1UTXhMakF4TTFvaUlHWnBiR3c5SWlNeE5qRTRNaklpUGp3dmNHRjBhRDQ4Y0c5c2VXZHZiaUJ3YjJsdWRITTlJak0xTUNBek5UQXVNREkySURReE5TNHdNeUF5T0RRdU9UYzRJREk0TlNBeU9EUXVPVGM0SURNMU1DQXpOVEF1TURJMklpQm1hV3hzUFNKMWNtd29JMU5oYm1SQ2IzUjBiMjBwSWk4K1BIQmhkR2dnWkQwaWJUUXhOaTR6TkRFc01qZ3hMamszTldNd0xDNDVNVFF0TGpNMU5Dd3hMamd3T1MweExqQXpOU3d5TGpZNExUVXVOVFF5TERjdU1EYzJMVE15TGpZMk1Td3hNaTQwTlMwMk5TNHlPQ3d4TWk0ME5TMHpNaTQyTWpRc01DMDFPUzQzTXpndE5TNHpOelF0TmpVdU1qZ3RNVEl1TkRVdExqWTRNUzB1T0RjeUxURXVNRE0xTFRFdU56WTNMVEV1TURNMUxUSXVOamdzTUMwdU9URTBMak0xTkMweExqZ3dPQ3d4TGpBek5TMHlMalkzTml3MUxqVTBNaTAzTGpBM05pd3pNaTQyTlRZdE1USXVORFVzTmpVdU1qZ3RNVEl1TkRVc016SXVOakU1TERBc05Ua3VOek00TERVdU16YzBMRFkxTGpJNExERXlMalExTGpZNE1TNDROamNzTVM0d016VXNNUzQzTmpJc01TNHdNelVzTWk0Mk56WmFJaUJtYVd4c1BTSjFjbXdvSTFOaGJtUlViM0FwSWk4K1BIQmhkR2dnWkQwaWJUUTRNUzQwTml3MU1EUXVNVEF4ZGpVNExqUTBPV010TWk0ek5TNDNOeTAwTGpneUxERXVOVEV0Tnk0ek9Td3lMakl6TFRNd0xqTXNPQzQxTkMwM05DNDJOU3d4TXk0NU1pMHhNalF1TURZc01UTXVPVEl0TlRNdU5pd3dMVEV3TVM0eU5DMDJMak16TFRFek1TNDBOeTB4Tmk0eE5uWXROVGd1TkRNNWFESTJNaTQ1TWxvaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkVKdmRIUnZiU2tpTHo0OFpXeHNhWEJ6WlNCamVEMGlNelV3SWlCamVUMGlOVEEwTGpFd01TSWdjbmc5SWpFek1TNDBOaklpSUhKNVBTSXlPQzR4TURnaUlHWnBiR3c5SW5WeWJDZ2pVMkZ1WkZSdmNDa2lMejQ4WnlCbWFXeHNQU0p1YjI1bElpQnpkSEp2YTJVOUluVnliQ2dqU0c5MWNtZHNZWE56VTNSeWIydGxLU0lnYzNSeWIydGxMV3hwYm1WallYQTlJbkp2ZFc1a0lpQnpkSEp2YTJVdGJXbDBaWEpzYVcxcGREMGlNVEFpSUhOMGNtOXJaUzEzYVdSMGFEMGlOQ0krUEhCaGRHZ2daRDBpYlRVMk5TNDJOREVzTVRBM0xqSTRZekFzT1M0MU16Y3ROUzQxTml3eE9DNDJNamt0TVRVdU5qYzJMREkyTGprM00yZ3RMakF5TTJNdE9TNHlNRFFzTnk0MU9UWXRNakl1TVRrMExERTBMalUyTWkwek9DNHhPVGNzTWpBdU5Ua3lMVE01TGpVd05Dd3hOQzQ1TXpZdE9UY3VNekkxTERJMExqTTFOUzB4TmpFdU56TXpMREkwTGpNMU5TMDVNQzQwT0N3d0xURTJOeTQ1TkRndE1UZ3VOVGd5TFRFNU9TNDVOVE10TkRRdU9UUTRhQzB1TURJell5MHhNQzR4TVRVdE9DNHpORFF0TVRVdU5qYzJMVEUzTGpRek55MHhOUzQyTnpZdE1qWXVPVGN6TERBdE16a3VOek0xTERrMkxqVTFOQzAzTVM0NU1qRXNNakUxTGpZMU1pMDNNUzQ1TWpGek1qRTFMall5T1N3ek1pNHhPRFVzTWpFMUxqWXlPU3czTVM0NU1qRmFJaTgrUEhCaGRHZ2daRDBpYlRFek5DNHpOaXd4TmpFdU1qQXpZekFzTXprdU56TTFMRGsyTGpVMU5DdzNNUzQ1TWpFc01qRTFMalkxTWl3M01TNDVNakZ6TWpFMUxqWXlPUzB6TWk0eE9EWXNNakUxTGpZeU9TMDNNUzQ1TWpFaUx6NDhiR2x1WlNCNE1UMGlNVE0wTGpNMklpQjVNVDBpTVRZeExqSXdNeUlnZURJOUlqRXpOQzR6TmlJZ2VUSTlJakV3Tnk0eU9DSXZQanhzYVc1bElIZ3hQU0kxTmpVdU5qUWlJSGt4UFNJeE5qRXVNakF6SWlCNE1qMGlOVFkxTGpZMElpQjVNajBpTVRBM0xqSTRJaTgrUEd4cGJtVWdlREU5SWpFNE5DNDFPRFFpSUhreFBTSXlNRFl1T0RJeklpQjRNajBpTVRnMExqVTROU0lnZVRJOUlqVXpOeTQxTnpraUx6NDhiR2x1WlNCNE1UMGlNakU0TGpFNE1TSWdlVEU5SWpJeE9DNHhNVGdpSUhneVBTSXlNVGd1TVRneElpQjVNajBpTlRZeUxqVXpOeUl2UGp4c2FXNWxJSGd4UFNJME9ERXVPREU0SWlCNU1UMGlNakU0TGpFME1pSWdlREk5SWpRNE1TNDRNVGtpSUhreVBTSTFOakl1TkRJNElpOCtQR3hwYm1VZ2VERTlJalV4TlM0ME1UVWlJSGt4UFNJeU1EY3VNelV5SWlCNE1qMGlOVEUxTGpReE5pSWdlVEk5SWpVek55NDFOemtpTHo0OGNHRjBhQ0JrUFNKdE1UZzBMalU0TERVek55NDFPR013TERVdU5EVXNOQzR5Tnl3eE1DNDJOU3d4TWk0d015d3hOUzQwTW1ndU1ESmpOUzQxTVN3ekxqTTVMREV5TGpjNUxEWXVOVFVzTWpFdU5UVXNPUzQwTWl3ek1DNHlNU3c1TGprc056Z3VNRElzTVRZdU1qZ3NNVE14TGpnekxERTJMakk0TERRNUxqUXhMREFzT1RNdU56WXROUzR6T0N3eE1qUXVNRFl0TVRNdU9USXNNaTQzTFM0M05pdzFMakk1TFRFdU5UUXNOeTQzTlMweUxqTTFMRGd1TnpjdE1pNDROeXd4Tmk0d05TMDJMakEwTERJeExqVTJMVGt1TkROb01HTTNMamMyTFRRdU56Y3NNVEl1TURRdE9TNDVOeXd4TWk0d05DMHhOUzQwTWlJdlBqeHdZWFJvSUdROUltMHhPRFF1TlRneUxEUTVNaTQyTlRaakxUTXhMak0xTkN3eE1pNDBPRFV0TlRBdU1qSXpMREk0TGpVNExUVXdMakl5TXl3ME5pNHhORElzTUN3NUxqVXpOaXcxTGpVMk5Dd3hPQzQyTWpjc01UVXVOamMzTERJMkxqazJPV2d1TURJeVl6Z3VOVEF6TERjdU1EQTFMREl3TGpJeE15d3hNeTQwTmpNc016UXVOVEkwTERFNUxqRTFPU3c1TGprNU9Td3pMams1TVN3eU1TNHlOamtzTnk0Mk1Ea3NNek11TlRrM0xERXdMamM0T0N3ek5pNDBOU3c1TGpRd055dzRNaTR4T0RFc01UVXVNREF5TERFek1TNDRNelVzTVRVdU1EQXljemsxTGpNMk15MDFMalU1TlN3eE16RXVPREEzTFRFMUxqQXdNbU14TUM0NE5EY3RNaTQzT1N3eU1DNDROamN0TlM0NU1qWXNNamt1T1RJMExUa3VNelE1TERFdU1qUTBMUzQwTmpjc01pNDBOek10TGprME1pd3pMalkzTXkweExqUXlOQ3d4TkM0ek1qWXROUzQyT1RZc01qWXVNRE0xTFRFeUxqRTJNU3d6TkM0MU1qUXRNVGt1TVRjemFDNHdNakpqTVRBdU1URTBMVGd1TXpReUxERTFMalkzTnkweE55NDBNek1zTVRVdU5qYzNMVEkyTGprMk9Td3dMVEUzTGpVMk1pMHhPQzQ0TmprdE16TXVOalkxTFRVd0xqSXlNeTAwTmk0eE5TSXZQanh3WVhSb0lHUTlJbTB4TXpRdU16WXNOVGt5TGpjeVl6QXNNemt1TnpNMUxEazJMalUxTkN3M01TNDVNakVzTWpFMUxqWTFNaXczTVM0NU1qRnpNakUxTGpZeU9TMHpNaTR4T0RZc01qRTFMall5T1MwM01TNDVNakVpTHo0OGJHbHVaU0I0TVQwaU1UTTBMak0ySWlCNU1UMGlOVGt5TGpjeUlpQjRNajBpTVRNMExqTTJJaUI1TWowaU5UTTRMamM1TnlJdlBqeHNhVzVsSUhneFBTSTFOalV1TmpRaUlIa3hQU0kxT1RJdU56SWlJSGd5UFNJMU5qVXVOalFpSUhreVBTSTFNemd1TnprM0lpOCtQSEJ2Ykhsc2FXNWxJSEJ2YVc1MGN6MGlORGd4TGpneU1pQTBPREV1T1RBeElEUTRNUzQzT1RnZ05EZ3hMamczTnlBME9ERXVOemMxSURRNE1TNDROVFFnTXpVd0xqQXhOU0F6TlRBdU1ESTJJREl4T0M0eE9EVWdNakU0TGpFeU9TSXZQanh3YjJ4NWJHbHVaU0J3YjJsdWRITTlJakl4T0M0eE9EVWdORGd4TGprd01TQXlNVGd1TWpNeElEUTRNUzQ0TlRRZ016VXdMakF4TlNBek5UQXVNREkySURRNE1TNDRNaklnTWpFNExqRTFNaUl2UGp3dlp6NDhMMmMrUEdjZ2FXUTlJbEJ5YjJkeVpYTnpJaUJtYVd4c1BTSWpabVptSWo0OGNtVmpkQ0IzYVdSMGFEMGlNakE0SWlCb1pXbG5hSFE5SWpFd01DSWdabWxzYkMxdmNHRmphWFI1UFNJdU1ETWlJSEo0UFNJeE5TSWdjbms5SWpFMUlpQnpkSEp2YTJVOUlpTm1abVlpSUhOMGNtOXJaUzF2Y0dGamFYUjVQU0l1TVNJZ2MzUnliMnRsTFhkcFpIUm9QU0kwSWk4K1BIUmxlSFFnZUQwaU1qQWlJSGs5SWpNMElpQm1iMjUwTFdaaGJXbHNlVDBpSjBOdmRYSnBaWElnVG1WM0p5eEJjbWxoYkN4dGIyNXZjM0JoWTJVaUlHWnZiblF0YzJsNlpUMGlNakp3ZUNJK1VISnZaM0psYzNNOEwzUmxlSFErUEhSbGVIUWdlRDBpTWpBaUlIazlJamN5SWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krTWpVbFBDOTBaWGgwUGp4bklHWnBiR3c5SW01dmJtVWlQanhqYVhKamJHVWdZM2c5SWpFMk5pSWdZM2s5SWpVd0lpQnlQU0l5TWlJZ2MzUnliMnRsUFNKb2Myd29Nak13TERJeEpTd3hNU1VwSWlCemRISnZhMlV0ZDJsa2RHZzlJakV3SWk4K1BHTnBjbU5zWlNCamVEMGlNVFkySWlCamVUMGlOVEFpSUhCaGRHaE1aVzVuZEdnOUlqRXdNREF3SWlCeVBTSXlNaUlnYzNSeWIydGxQU0pvYzJ3b05qRXNPRGdsTERRd0pTa2lJSE4wY205clpTMWtZWE5vWVhKeVlYazlJakV3TURBd0lpQnpkSEp2YTJVdFpHRnphRzltWm5ObGREMGlOelV3TUNJZ2MzUnliMnRsTFd4cGJtVmpZWEE5SW5KdmRXNWtJaUJ6ZEhKdmEyVXRkMmxrZEdnOUlqVWlJSFJ5WVc1elptOXliVDBpY205MFlYUmxLQzA1TUNraUlIUnlZVzV6Wm05eWJTMXZjbWxuYVc0OUlqRTJOaUExTUNJdlBqd3ZaejQ4TDJjK1BHY2dhV1E5SWxOMFlYUjFjeUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakU0TkNJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBsTjBZWFIxY3p3dmRHVjRkRDQ4ZEdWNGRDQjRQU0l5TUNJZ2VUMGlOeklpSUdadmJuUXRabUZ0YVd4NVBTSW5RMjkxY21sbGNpQk9aWGNuTEVGeWFXRnNMRzF2Ym05emNHRmpaU0lnWm05dWRDMXphWHBsUFNJeU5uQjRJajVUZEhKbFlXMXBibWM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pCYlc5MWJuUWlJR1pwYkd3OUlpTm1abVlpUGp4eVpXTjBJSGRwWkhSb1BTSXhNakFpSUdobGFXZG9kRDBpTVRBd0lpQm1hV3hzTFc5d1lXTnBkSGs5SWk0d015SWdjbmc5SWpFMUlpQnllVDBpTVRVaUlITjBjbTlyWlQwaUkyWm1aaUlnYzNSeWIydGxMVzl3WVdOcGRIazlJaTR4SWlCemRISnZhMlV0ZDJsa2RHZzlJalFpTHo0OGRHVjRkQ0I0UFNJeU1DSWdlVDBpTXpRaUlHWnZiblF0Wm1GdGFXeDVQU0luUTI5MWNtbGxjaUJPWlhjbkxFRnlhV0ZzTEcxdmJtOXpjR0ZqWlNJZ1ptOXVkQzF6YVhwbFBTSXlNbkI0SWo1QmJXOTFiblE4TDNSbGVIUStQSFJsZUhRZ2VEMGlNakFpSUhrOUlqY3lJaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1p2Ym5RdGMybDZaVDBpTWpad2VDSStKaU00T0RBMU95QXhNRXM4TDNSbGVIUStQQzluUGp4bklHbGtQU0pFZFhKaGRHbHZiaUlnWm1sc2JEMGlJMlptWmlJK1BISmxZM1FnZDJsa2RHZzlJakUxTWlJZ2FHVnBaMmgwUFNJeE1EQWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqQXpJaUJ5ZUQwaU1UVWlJSEo1UFNJeE5TSWdjM1J5YjJ0bFBTSWpabVptSWlCemRISnZhMlV0YjNCaFkybDBlVDBpTGpFaUlITjBjbTlyWlMxM2FXUjBhRDBpTkNJdlBqeDBaWGgwSUhnOUlqSXdJaUI1UFNJek5DSWdabTl1ZEMxbVlXMXBiSGs5SWlkRGIzVnlhV1Z5SUU1bGR5Y3NRWEpwWVd3c2JXOXViM053WVdObElpQm1iMjUwTFhOcGVtVTlJakl5Y0hnaVBrUjFjbUYwYVc5dVBDOTBaWGgwUGp4MFpYaDBJSGc5SWpJd0lpQjVQU0kzTWlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGlac2REc2dNU0JFWVhrOEwzUmxlSFErUEM5blBqd3ZaR1ZtY3o0OGRHVjRkQ0IwWlhoMExYSmxibVJsY21sdVp6MGliM0IwYVcxcGVtVlRjR1ZsWkNJK1BIUmxlSFJRWVhSb0lITjBZWEowVDJabWMyVjBQU0l0TVRBd0pTSWdhSEpsWmowaUkwWnNiMkYwYVc1blZHVjRkQ0lnWm1sc2JEMGlJMlptWmlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ0SWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGp4aGJtbHRZWFJsSUdGa1pHbDBhWFpsUFNKemRXMGlJR0YwZEhKcFluVjBaVTVoYldVOUluTjBZWEowVDJabWMyVjBJaUJpWldkcGJqMGlNSE1pSUdSMWNqMGlOVEJ6SWlCbWNtOXRQU0l3SlNJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhSdlBTSXhNREFsSWk4K01IaGtZakkxWVRkaU56WTRNekV4WkdVeE1qaGlZbVJoTjJJNE5ESTJZek5tT1dNM05HWXpNalF3SU9LQW9pQlRZV0pzYVdWeUlGWXlJRXh2WTJ0MWNDQkVlVzVoYldsalBDOTBaWGgwVUdGMGFENDhkR1Y0ZEZCaGRHZ2djM1JoY25SUFptWnpaWFE5SWpBbElpQm9jbVZtUFNJalJteHZZWFJwYm1kVVpYaDBJaUJtYVd4c1BTSWpabVptSWlCbWIyNTBMV1poYldsc2VUMGlKME52ZFhKcFpYSWdUbVYzSnl4QmNtbGhiQ3h0YjI1dmMzQmhZMlVpSUdacGJHd3RiM0JoWTJsMGVUMGlMamdpSUdadmJuUXRjMmw2WlQwaU1qWndlQ0krUEdGdWFXMWhkR1VnWVdSa2FYUnBkbVU5SW5OMWJTSWdZWFIwY21saWRYUmxUbUZ0WlQwaWMzUmhjblJQWm1aelpYUWlJR0psWjJsdVBTSXdjeUlnWkhWeVBTSTFNSE1pSUdaeWIyMDlJakFsSWlCeVpYQmxZWFJEYjNWdWREMGlhVzVrWldacGJtbDBaU0lnZEc4OUlqRXdNQ1VpTHo0d2VHUmlNalZoTjJJM05qZ3pNVEZrWlRFeU9HSmlaR0UzWWpnME1qWmpNMlk1WXpjMFpqTXlOREFnNG9DaUlGTmhZbXhwWlhJZ1ZqSWdURzlqYTNWd0lFUjVibUZ0YVdNOEwzUmxlSFJRWVhSb1BqeDBaWGgwVUdGMGFDQnpkR0Z5ZEU5bVpuTmxkRDBpTFRVd0pTSWdhSEpsWmowaUkwWnNiMkYwYVc1blZHVjRkQ0lnWm1sc2JEMGlJMlptWmlJZ1ptOXVkQzFtWVcxcGJIazlJaWREYjNWeWFXVnlJRTVsZHljc1FYSnBZV3dzYlc5dWIzTndZV05sSWlCbWFXeHNMVzl3WVdOcGRIazlJaTQ0SWlCbWIyNTBMWE5wZW1VOUlqSTJjSGdpUGp4aGJtbHRZWFJsSUdGa1pHbDBhWFpsUFNKemRXMGlJR0YwZEhKcFluVjBaVTVoYldVOUluTjBZWEowVDJabWMyVjBJaUJpWldkcGJqMGlNSE1pSUdSMWNqMGlOVEJ6SWlCbWNtOXRQU0l3SlNJZ2NtVndaV0YwUTI5MWJuUTlJbWx1WkdWbWFXNXBkR1VpSUhSdlBTSXhNREFsSWk4K01IZ3dNMkUyWVRnMFkyUTNOakprT1Rjd04yRXlNVFl3TldJMU5EaGhZV0ZpT0RreE5UWXlZV0ZpSU9LQW9pQkVRVWs4TDNSbGVIUlFZWFJvUGp4MFpYaDBVR0YwYUNCemRHRnlkRTltWm5ObGREMGlOVEFsSWlCb2NtVm1QU0lqUm14dllYUnBibWRVWlhoMElpQm1hV3hzUFNJalptWm1JaUJtYjI1MExXWmhiV2xzZVQwaUowTnZkWEpwWlhJZ1RtVjNKeXhCY21saGJDeHRiMjV2YzNCaFkyVWlJR1pwYkd3dGIzQmhZMmwwZVQwaUxqZ2lJR1p2Ym5RdGMybDZaVDBpTWpad2VDSStQR0Z1YVcxaGRHVWdZV1JrYVhScGRtVTlJbk4xYlNJZ1lYUjBjbWxpZFhSbFRtRnRaVDBpYzNSaGNuUlBabVp6WlhRaUlHSmxaMmx1UFNJd2N5SWdaSFZ5UFNJMU1ITWlJR1p5YjIwOUlqQWxJaUJ5WlhCbFlYUkRiM1Z1ZEQwaWFXNWtaV1pwYm1sMFpTSWdkRzg5SWpFd01DVWlMejR3ZURBellUWmhPRFJqWkRjMk1tUTVOekEzWVRJeE5qQTFZalUwT0dGaFlXSTRPVEUxTmpKaFlXSWc0b0NpSUVSQlNUd3ZkR1Y0ZEZCaGRHZytQQzkwWlhoMFBqeDFjMlVnYUhKbFpqMGlJMGRzYjNjaUlHWnBiR3d0YjNCaFkybDBlVDBpTGpraUx6NDhkWE5sSUdoeVpXWTlJaU5IYkc5M0lpQjRQU0l4TURBd0lpQjVQU0l4TURBd0lpQm1hV3hzTFc5d1lXTnBkSGs5SWk0NUlpOCtQSFZ6WlNCb2NtVm1QU0lqVEc5bmJ5SWdlRDBpTVRjd0lpQjVQU0l4TnpBaUlIUnlZVzV6Wm05eWJUMGljMk5oYkdVb0xqWXBJaTgrUEhWelpTQm9jbVZtUFNJalNHOTFjbWRzWVhOeklpQjRQU0l4TlRBaUlIazlJamt3SWlCMGNtRnVjMlp2Y20wOUluSnZkR0YwWlNneE1Da2lJSFJ5WVc1elptOXliUzF2Y21sbmFXNDlJalV3TUNBMU1EQWlMejQ4ZFhObElHaHlaV1k5SWlOUWNtOW5jbVZ6Y3lJZ2VEMGlNVFEwSWlCNVBTSTNPVEFpTHo0OGRYTmxJR2h5WldZOUlpTlRkR0YwZFhNaUlIZzlJak0yT0NJZ2VUMGlOemt3SWk4K1BIVnpaU0JvY21WbVBTSWpRVzF2ZFc1MElpQjRQU0kxTmpnaUlIazlJamM1TUNJdlBqeDFjMlVnYUhKbFpqMGlJMFIxY21GMGFXOXVJaUI0UFNJM01EUWlJSGs5SWpjNU1DSXZQand2YzNablBnPT0ifQ=="; assertEq(actualTokenURI, expectedTokenURI, "token URI"); diff --git a/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree index 079a20aec..7fbcf727e 100644 --- a/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree +++ b/test/core/integration/concrete/lockup-tranched/token-uri/tokenURI.tree @@ -1,4 +1,4 @@ -TokenURI_LockupTranched_Integration_Concrete_Test +TokenURI_Lockup_Tranched_Integration_Concrete_Test ├── given NFT not exist │ └── it should revert └── given NFT exists 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 1bdac3a06..ebb883009 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 @@ -2,20 +2,20 @@ pragma solidity >=0.8.22 <0.9.0; import { WithdrawableAmountOf_Integration_Concrete_Test } from - "./../../lockup/withdrawable-amount-of/withdrawableAmountOf.t.sol"; -import { LockupTranched_Integration_Shared_Test, Integration_Test } from "./../LockupTranched.t.sol"; + "./../../lockup-base/withdrawable-amount-of/withdrawableAmountOf.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test, Integration_Test } from "./../LockupTranched.t.sol"; -contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawableAmountOf_Lockup_Tranched_Integration_Concrete_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawableAmountOf_Integration_Concrete_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } function test_GivenStartTimeInPresent() external givenSTREAMINGStatus { vm.warp({ newTimestamp: defaults.START_TIME() }); - uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -25,7 +25,7 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Run the test. - uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = defaults.tranches()[0].amount; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -35,10 +35,10 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test is vm.warp({ newTimestamp: defaults.START_TIME() + defaults.CLIFF_DURATION() }); // Make the withdrawal. - lockupTranched.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); + lockup.withdraw({ streamId: defaultStreamId, to: users.recipient, amount: defaults.CLIFF_AMOUNT() }); // Run the test. - uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = defaults.tranches()[0].amount - defaults.CLIFF_AMOUNT(); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); diff --git a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree index e3c4147d9..17ee40277 100644 --- a/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree +++ b/test/core/integration/concrete/lockup-tranched/withdrawable-amount-of/withdrawableAmountOf.tree @@ -1,4 +1,4 @@ -WithdrawableAmountOf_LockupTranched_Integration_Concrete_Test +WithdrawableAmountOf_Lockup_Tranched_Integration_Concrete_Test └── given STREAMING status ├── given start time in present │ └── it should return zero 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 812b7ed60..57d67c82c 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 @@ -16,21 +16,9 @@ contract MapSymbol_Integration_Concrete_Test is NFTDescriptor_Integration_Shared nftDescriptorMock.mapSymbol_(IERC721Metadata(address(nft))); } - function test_WhenLockupDynamicNFT() external view givenKnownNFTContract { - string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupDynamic); - string memory expectedLockupModel = "Sablier Lockup Dynamic"; - assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); - } - - function test_WhenLockupLinearNFT() external view givenKnownNFTContract { - string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupLinear); - string memory expectedLockupModel = "Sablier Lockup Linear"; - assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); - } - - function test_WhenLockupTranchedNFT() external view givenKnownNFTContract { - string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockupTranched); - string memory expectedLockupModel = "Sablier Lockup Tranched"; + function test_GivenKnownNFTContract() external view { + string memory actualLockupModel = nftDescriptorMock.mapSymbol_(lockup); + string memory expectedLockupModel = "Sablier Lockup"; assertEq(actualLockupModel, expectedLockupModel, "lockupModel"); } } diff --git a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree index 9a23e6f40..1193e42ce 100644 --- a/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree +++ b/test/core/integration/concrete/nft-descriptor/map-symbol/mapSymbol.tree @@ -2,9 +2,4 @@ MapSymbol_Integration_Concrete_Test ├── given unknown NFT contract │ └── it should revert └── given known NFT contract - ├── when LockupDynamic NFT - │ └── it should map the ERC-721 symbol to Lockup Dynamic - ├── when LockupLinear NFT - │ └── it should map the ERC-721 symbol to Lockup Linear - └── when LockupTranched NFT - └── it should map the ERC-721 symbol to Lockup Linear + └── it should map the ERC-721 symbol to Lockup Linear diff --git a/test/core/integration/fuzz/lockup/cancel.t.sol b/test/core/integration/fuzz/lockup-base/cancel.t.sol similarity index 77% rename from test/core/integration/fuzz/lockup/cancel.t.sol rename to test/core/integration/fuzz/lockup-base/cancel.t.sol index a258395f1..67ccc4625 100644 --- a/test/core/integration/fuzz/lockup/cancel.t.sol +++ b/test/core/integration/fuzz/lockup-base/cancel.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -62,48 +62,45 @@ abstract contract Cancel_Integration_Fuzz_Test is Integration_Test { lockup.allowToHook(address(recipientGood)); resetPrank({ msgSender: users.sender }); - // Create the stream. - uint256 streamId = createDefaultStreamWithRecipient(address(recipientGood)); - // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. - uint128 streamedAmount = lockup.streamedAmountOf(streamId); + uint128 streamedAmount = lockup.streamedAmountOf(recipientGoodStreamId); withdrawAmount = boundUint128(withdrawAmount, 0, streamedAmount - 1); // Make the withdrawal only if the amount is greater than zero. if (withdrawAmount > 0) { - lockup.withdraw({ streamId: streamId, to: address(recipientGood), amount: withdrawAmount }); + lockup.withdraw({ streamId: recipientGoodStreamId, to: address(recipientGood), amount: withdrawAmount }); } // Expect the assets to be refunded to the Sender. - uint128 senderAmount = lockup.refundableAmountOf(streamId); + uint128 senderAmount = lockup.refundableAmountOf(recipientGoodStreamId); expectCallToTransfer({ to: users.sender, value: senderAmount }); // Expect the relevant events to be emitted. - uint128 recipientAmount = lockup.withdrawableAmountOf(streamId); + uint128 recipientAmount = lockup.withdrawableAmountOf(recipientGoodStreamId); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream( - streamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount + emit ISablierLockupBase.CancelLockupStream( + recipientGoodStreamId, users.sender, address(recipientGood), dai, senderAmount, recipientAmount ); vm.expectEmit({ emitter: address(lockup) }); - emit IERC4906.MetadataUpdate({ _tokenId: streamId }); + emit IERC4906.MetadataUpdate({ _tokenId: recipientGoodStreamId }); // Cancel the stream. - lockup.cancel(streamId); + lockup.cancel(recipientGoodStreamId); // Assert that the stream's status is "CANCELED". - Lockup.Status actualStatus = lockup.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(recipientGoodStreamId); Lockup.Status expectedStatus = Lockup.Status.CANCELED; assertEq(actualStatus, expectedStatus); // Assert that the stream is not cancelable anymore. - bool isCancelable = lockup.isCancelable(streamId); + bool isCancelable = lockup.isCancelable(recipientGoodStreamId); assertFalse(isCancelable, "isCancelable"); // Assert that the not burned NFT. - address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: recipientGoodStreamId }); address expectedNFTOwner = address(recipientGood); assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol b/test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol similarity index 74% rename from test/core/integration/fuzz/lockup/cancelMultiple.t.sol rename to test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol index d500d3355..5372c1a8c 100644 --- a/test/core/integration/fuzz/lockup/cancelMultiple.t.sol +++ b/test/core/integration/fuzz/lockup-base/cancelMultiple.t.sol @@ -3,14 +3,19 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { CancelMultiple_Integration_Shared_Test } from "../../shared/lockup/cancelMultiple.t.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; -abstract contract CancelMultiple_Integration_Fuzz_Test is CancelMultiple_Integration_Shared_Test { function setUp() public virtual override { - CancelMultiple_Integration_Shared_Test.setUp(); + Lockup_Integration_Shared_Test.setUp(); + originalTime = getBlockTimestamp(); } function testFuzz_CancelMultiple( @@ -21,20 +26,27 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is CancelMultiple_Integra whenNoDelegateCall givenNotNull givenNoColdStreams - whenCallerAuthorizedForAll + 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 = createDefaultStreamWithEndTime(endTime); + 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(testStreamIds[0], streamId); + uint256[] memory streamIds = Solarray.uint256s(cancelMultipleStreamIds[0], streamId); // Expect the assets to be refunded to the Sender. uint128 senderAmount0 = lockup.refundableAmountOf(streamIds[0]); @@ -44,7 +56,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is CancelMultiple_Integra // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream({ + emit ISablierLockupBase.CancelLockupStream({ streamId: streamIds[0], sender: users.sender, recipient: users.recipient, @@ -53,7 +65,7 @@ abstract contract CancelMultiple_Integration_Fuzz_Test is CancelMultiple_Integra recipientAmount: defaults.DEPOSIT_AMOUNT() - senderAmount0 }); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.CancelLockupStream({ + emit ISablierLockupBase.CancelLockupStream({ streamId: streamIds[1], sender: users.sender, recipient: users.recipient, diff --git a/test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol b/test/core/integration/fuzz/lockup-base/getWithdrawnAmount.t.sol similarity index 100% rename from test/core/integration/fuzz/lockup/getWithdrawnAmount.t.sol rename to test/core/integration/fuzz/lockup-base/getWithdrawnAmount.t.sol diff --git a/test/core/integration/fuzz/lockup/refundableAmountOf.t.sol b/test/core/integration/fuzz/lockup-base/refundableAmountOf.t.sol similarity index 100% rename from test/core/integration/fuzz/lockup/refundableAmountOf.t.sol rename to test/core/integration/fuzz/lockup-base/refundableAmountOf.t.sol diff --git a/test/core/integration/fuzz/lockup/withdraw.t.sol b/test/core/integration/fuzz/lockup-base/withdraw.t.sol similarity index 96% rename from test/core/integration/fuzz/lockup/withdraw.t.sol rename to test/core/integration/fuzz/lockup-base/withdraw.t.sol index b8948ae1f..1d2b1958b 100644 --- a/test/core/integration/fuzz/lockup/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdraw.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -114,7 +114,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test { // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream(defaultStreamId, to, dai, withdrawAmount); + emit ISablierLockupBase.WithdrawFromLockupStream(defaultStreamId, to, dai, withdrawAmount); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: defaultStreamId }); @@ -177,7 +177,7 @@ abstract contract Withdraw_Integration_Fuzz_Test is Integration_Test { // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream(defaultStreamId, to, dai, withdrawAmount); + emit ISablierLockupBase.WithdrawFromLockupStream(defaultStreamId, to, dai, withdrawAmount); vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: defaultStreamId }); diff --git a/test/core/integration/fuzz/lockup/withdrawMax.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol similarity index 94% rename from test/core/integration/fuzz/lockup/withdrawMax.t.sol rename to test/core/integration/fuzz/lockup-base/withdrawMax.t.sol index eb7281ab0..0e0db13b1 100644 --- a/test/core/integration/fuzz/lockup/withdrawMax.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdrawMax.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -18,7 +18,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, asset: dai, @@ -62,7 +62,7 @@ abstract contract WithdrawMax_Integration_Fuzz_Test is Integration_Test { // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, asset: dai, diff --git a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol similarity index 94% rename from test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol rename to test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol index cca86581f..033286ff7 100644 --- a/test/core/integration/fuzz/lockup/withdrawMaxAndTransfer.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdrawMaxAndTransfer.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Integration_Test } from "../../Integration.t.sol"; @@ -12,6 +12,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Te /// /// - New recipient same and different from the current one /// - Withdrawable amount zero and not zero + function testFuzz_WithdrawMaxAndTransfer( uint256 timeJump, address newRecipient @@ -38,7 +39,7 @@ abstract contract WithdrawMaxAndTransfer_Integration_Fuzz_Test is Integration_Te // Expect the relevant event to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: defaultStreamId, to: users.recipient, asset: dai, diff --git a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol b/test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol similarity index 70% rename from test/core/integration/fuzz/lockup/withdrawMultiple.t.sol rename to test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol index 8a160e2f5..1a478dbb7 100644 --- a/test/core/integration/fuzz/lockup/withdrawMultiple.t.sol +++ b/test/core/integration/fuzz/lockup-base/withdrawMultiple.t.sol @@ -2,14 +2,20 @@ pragma solidity >=0.8.22 <0.9.0; import { Solarray } from "solarray/src/Solarray.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup } from "src/core/types/DataTypes.sol"; -import { WithdrawMultiple_Integration_Shared_Test } from "./../../shared/lockup/withdrawMultiple.t.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; -abstract contract WithdrawMultiple_Integration_Fuzz_Test is WithdrawMultiple_Integration_Shared_Test { function setUp() public virtual override { - WithdrawMultiple_Integration_Shared_Test.setUp(); + Lockup_Integration_Shared_Test.setUp(); + originalTime = getBlockTimestamp(); } function testFuzz_WithdrawMultiple( @@ -21,7 +27,7 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is WithdrawMultiple_Int whenArraysEqual givenNotNull givenNoDEPLETEDStreams - whenCallerAuthorizedAllStreams + whenCallerAuthorizedForAllStreams whenWithdrawalAddressNotZero whenNoZeroAmounts whenNoAmountOverdraws @@ -30,13 +36,22 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is WithdrawMultiple_Int // Create a new stream with an end time double that of the default stream. uint40 ongoingEndTime = defaults.END_TIME() + defaults.TOTAL_DURATION(); - uint256 ongoingStreamId = createDefaultStreamWithEndTime(ongoingEndTime); + + // 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 = createDefaultStream(); + uint256 settledStreamId = createDefaultStreamLD(); uint128 settledWithdrawAmount = defaults.DEPOSIT_AMOUNT(); - // Run the test with the caller provided in {whenCallerAuthorizedAllStreams}. + // Run the test with the caller provided in {whenCallerAuthorizedForAllStreams}. resetPrank({ msgSender: caller }); // Simulate the passage of time. @@ -52,14 +67,14 @@ abstract contract WithdrawMultiple_Integration_Fuzz_Test is WithdrawMultiple_Int // Expect the relevant events to be emitted. vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: ongoingStreamId, to: users.recipient, asset: dai, amount: ongoingWithdrawAmount }); vm.expectEmit({ emitter: address(lockup) }); - emit ISablierLockup.WithdrawFromLockupStream({ + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: settledStreamId, to: users.recipient, asset: dai, diff --git a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol index b7f49050d..b95b0e975 100644 --- a/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/LockupDynamic.t.sol @@ -1,90 +1,98 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { - LockupDynamic_Integration_Shared_Test, Integration_Test -} from "../../shared/lockup-dynamic/LockupDynamic.t.sol"; -import { Cancel_Integration_Fuzz_Test } from "../lockup/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "../lockup/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "../lockup/getWithdrawnAmount.t.sol"; -import { RefundableAmountOf_Integration_Fuzz_Test } from "../lockup/refundableAmountOf.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "../lockup/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "../lockup/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultiple.t.sol"; - +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 { 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_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, +contract Cancel_Lockup_Dynamic_Integration_Fuzz_Test is + Lockup_Dynamic_Integration_Shared_Test, Cancel_Integration_Fuzz_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, - CancelMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Shared_Test, CancelMultiple_Integration_Fuzz_Test) - { - LockupDynamic_Integration_Shared_Test.setUp(); +contract CancelMultiple_Lockup_Dynamic_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { + modifier whenCallerAuthorizedForAllStreams() override { + cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLD({ warpTime: originalTime }); + _; + } + + function setUp() public virtual override { CancelMultiple_Integration_Fuzz_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_DYNAMIC; } } -contract RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, - RefundableAmountOf_Integration_Fuzz_Test +contract GetWithdrawnAmount_Lockup_Dynamic_Integration_Fuzz_Test is + Lockup_Dynamic_Integration_Shared_Test, + GetWithdrawnAmount_Integration_Fuzz_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, - GetWithdrawnAmount_Integration_Fuzz_Test +contract RefundableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is + Lockup_Dynamic_Integration_Shared_Test, + RefundableAmountOf_Integration_Fuzz_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawMax_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawMax_Lockup_Dynamic_Integration_Fuzz_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawMax_Integration_Fuzz_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Dynamic_Integration_Fuzz_Test is + Lockup_Dynamic_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Fuzz_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, - WithdrawMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupDynamic_Integration_Shared_Test, WithdrawMultiple_Integration_Fuzz_Test) - { - LockupDynamic_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; + _; + } + + function setUp() public virtual override { WithdrawMultiple_Integration_Fuzz_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_DYNAMIC; } } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol similarity index 61% rename from test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol index 3523882ad..94503e435 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithDurationsLD.t.sol @@ -1,17 +1,16 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; +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"; -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; - -contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithDurationsLD_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupDynamic_Integration_Shared_Test.setUp(); - streamId = lockupDynamic.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } struct Vars { @@ -29,7 +28,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynami uint128 totalAmount; } - function testFuzz_CreateWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) + function testFuzz_CreateWithDurationsLD(LockupDynamic.SegmentWithDuration[] memory segments) external whenNoDelegateCall whenSegmentCountNotExceedMaxValue @@ -51,7 +50,7 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynami deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. - expectCallToTransferFrom({ from: vars.funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); + expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -60,14 +59,15 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynami // Create the timestamps struct. vars.segmentsWithTimestamps = getSegmentsWithTimestamps(segments); - LockupDynamic.Timestamps memory timestamps = LockupDynamic.Timestamps({ + 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(lockupDynamic) }); - emit ISablierLockupDynamic.CreateLockupDynamicStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupDynamicStream({ streamId: streamId, funder: vars.funder, sender: users.sender, @@ -82,44 +82,42 @@ contract CreateWithDurations_LockupDynamic_Integration_Fuzz_Test is LockupDynami }); // Create the stream. - LockupDynamic.CreateWithDurations memory params = defaults.createWithDurationsLD(); - params.segments = segments; + Lockup.CreateWithDurations memory params = defaults.createWithDurations(); params.totalAmount = vars.totalAmount; params.transferable = true; - lockupDynamic.createWithDurations(params); + lockup.createWithDurationsLD(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. - vars.isSettled = lockupDynamic.refundableAmountOf(streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(streamId) == 0; vars.isCancelable = vars.isSettled ? false : true; - // Assert that the stream has been created. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, users.recipient, "recipient"); - assertEq(actualStream.segments, vars.segmentsWithTimestamps, "segments"); - assertEq(actualStream.sender, users.sender, "sender"); - assertEq(actualStream.startTime, timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + // 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.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), 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.getSegments(streamId), vars.segmentsWithTimestamps, "segments"); // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(streamId); + vars.actualStatus = lockup.statusOf(streamId); vars.expectedStatus = vars.isSettled ? Lockup.Status.SETTLED : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupDynamic.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = users.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol similarity index 72% rename from test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol index feb2f9417..63fb20781 100644 --- a/test/core/integration/fuzz/lockup-dynamic/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/createWithTimestampsLD.t.sol @@ -3,19 +3,17 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; - -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.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"; -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; - -contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Shared_Test { +contract CreateWithTimestampsLD_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupDynamic_Integration_Shared_Test.setUp(); - streamId = lockupDynamic.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function testFuzz_RevertWhen_SegmentCountTooHigh(uint256 segmentCount) @@ -26,11 +24,11 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam whenDepositAmountNotZero whenSegmentCountNotZero { - uint256 defaultMax = defaults.MAX_SEGMENT_COUNT(); + 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.SablierLockupDynamic_SegmentCountTooHigh.selector, segmentCount)); - createDefaultStreamWithSegments(segments); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_SegmentCountTooHigh.selector, segmentCount)); + createDefaultStreamWithSegmentsLD(segments); } function testFuzz_RevertWhen_SegmentAmountsSumOverflows( @@ -51,7 +49,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam segments[0].amount = amount0; segments[1].amount = amount1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithSegments(segments); + createDefaultStreamWithSegmentsLD(segments); } function testFuzz_RevertWhen_StartTimeNotLessThanFirstSegmentTimestamp(uint40 firstTimestamp) @@ -73,14 +71,14 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_StartTimeNotLessThanFirstSegmentTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstSegmentTimestamp.selector, defaults.START_TIME(), segments[0].timestamp ) ); // Create the stream. - createDefaultStreamWithSegments(segments); + createDefaultStreamWithSegmentsLD(segments); } function testFuzz_RevertWhen_DepositAmountNotEqualToSegmentAmountsSum(uint128 depositDiff) @@ -104,20 +102,21 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; + LockupDynamic.Segment[] memory segments = defaults.segments(); // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupDynamic_DepositAmountNotEqualToSegmentAmountsSum.selector, + Errors.SablierLockup_DepositAmountNotEqualToSegmentAmountsSum.selector, depositAmount, defaultDepositAmount ) ); // Create the stream. - lockupDynamic.createWithTimestamps(params); + lockup.createWithTimestampsLD(params, segments); } function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) @@ -138,7 +137,7 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(broker); + createDefaultStreamWithBrokerLD(broker); } struct Vars { @@ -164,9 +163,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam /// - Start time in the future /// - Start time equal and not equal to the first segment timestamp /// - Multiple values for the broker fee, including zero - function testFuzz_CreateWithTimestamps( + function testFuzz_CreateWithTimestampsLD( address funder, - LockupDynamic.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + LockupDynamic.Segment[] memory segments ) external whenNoDelegateCall @@ -188,21 +188,18 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam funder != address(0) && params.sender != address(0) && params.recipient != address(0) && params.broker.account != address(0) ); - vm.assume(params.segments.length != 0); + 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.transferable = true; // Fuzz the segment timestamps. - fuzzSegmentTimestamps(params.segments, params.startTime); + fuzzSegmentTimestamps(segments, params.startTime); // 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: params.segments, - brokerFee: params.broker.fee - }); + (vars.totalAmount, vars.createAmounts) = + fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128, segments: segments, brokerFee: params.broker.fee }); // Make the fuzzed funder the caller in the rest of this test. resetPrank(funder); @@ -211,10 +208,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam deal({ token: address(dai), to: funder, give: vars.totalAmount }); // Approve {SablierLockupDynamic} to transfer the assets from the fuzzed funder. - dai.approve({ spender: address(lockupDynamic), value: MAX_UINT256 }); + dai.approve({ spender: address(lockup), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierLockupDynamic}. - expectCallToTransferFrom({ from: funder, to: address(lockupDynamic), value: vars.createAmounts.deposit }); + expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -222,12 +219,10 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam } // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(lockupDynamic) }); - LockupDynamic.Timestamps memory timestamps = LockupDynamic.Timestamps({ - start: params.startTime, - end: params.segments[params.segments.length - 1].timestamp - }); - emit ISablierLockupDynamic.CreateLockupDynamicStream({ + 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, funder: funder, sender: params.sender, @@ -236,14 +231,14 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam asset: dai, cancelable: params.cancelable, transferable: params.transferable, - segments: params.segments, + segments: segments, timestamps: timestamps, broker: params.broker.account }); // Create the stream. - lockupDynamic.createWithTimestamps( - LockupDynamic.CreateWithTimestamps({ + lockup.createWithTimestampsLD( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, @@ -251,33 +246,33 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam cancelable: params.cancelable, transferable: params.transferable, startTime: params.startTime, - segments: params.segments, + endTime: segments[segments.length - 1].timestamp, broker: params.broker - }) + }), + 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. - vars.isSettled = (lockupDynamic.getDepositedAmount(streamId) - lockupDynamic.streamedAmountOf(streamId)) == 0; + vars.isSettled = (lockup.getDepositedAmount(streamId) - lockup.streamedAmountOf(streamId)) == 0; vars.isCancelable = vars.isSettled ? false : params.cancelable; - // Assert that the stream has been created. - LockupDynamic.StreamLD memory actualStream = lockupDynamic.getStream(streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isStream"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.segments, params.segments, "segments"); - assertEq(actualStream.startTime, timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + // 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.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"); + assertEq(lockup.getSender(streamId), params.sender, "sender"); + assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getSegments(streamId), segments, "segments"); // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(streamId); + vars.actualStatus = lockup.statusOf(streamId); if (params.startTime > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { @@ -288,12 +283,12 @@ contract CreateWithTimestamps_LockupDynamic_Integration_Fuzz_Test is LockupDynam assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupDynamic.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupDynamic.ownerOf({ tokenId: streamId }); + 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-dynamic/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol index 165cea435..5ab9c490a 100644 --- a/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/streamedAmountOf.t.sol @@ -2,11 +2,11 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; -contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic_Integration_Shared_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -35,17 +35,18 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_I deal({ token: address(dai), to: users.sender, give: segment.amount }); // Create the stream with the fuzzed segment. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); - params.segments = segments; + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = segment.amount; - uint256 streamId = lockupDynamic.createWithTimestamps(params); + params.endTime = segment.timestamp; + uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForOneSegment(segment, defaults.START_TIME()); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); + uint128 expectedStreamedAmount = + calculateLockupDynamicStreamedAmount(segments, defaults.START_TIME(), params.totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -86,18 +87,18 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_I deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); - params.segments = segments; + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = totalAmount; - uint256 streamId = lockupDynamic.createWithTimestamps(params); + params.endTime = segments[segments.length - 1].timestamp; + uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. - uint128 actualStreamedAmount = lockupDynamic.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = - calculateStreamedAmountForMultipleSegments(segments, defaults.START_TIME(), totalAmount); + calculateLockupDynamicStreamedAmount(segments, defaults.START_TIME(), totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -133,22 +134,22 @@ contract StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_I deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); - params.segments = segments; + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = totalAmount; - uint256 streamId = lockupDynamic.createWithTimestamps(params); + params.endTime = segments[segments.length - 1].timestamp; + uint256 streamId = lockup.createWithTimestampsLD(params, segments); // Warp to the future for the first time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. - uint128 streamedAmount0 = lockupDynamic.streamedAmountOf(streamId); + uint128 streamedAmount0 = lockup.streamedAmountOf(streamId); // Warp to the future for the second time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. - uint128 streamedAmount1 = lockupDynamic.streamedAmountOf(streamId); + uint128 streamedAmount1 = lockup.streamedAmountOf(streamId); assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol index c547d55ed..a305c6f00 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdraw.t.sol @@ -2,22 +2,21 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; - -import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; -import { LockupDynamic_Integration_Shared_Test, Integration_Test } from "./LockupDynamic.t.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_LockupDynamic_Integration_Fuzz_Test is - LockupDynamic_Integration_Shared_Test, - Withdraw_Integration_Fuzz_Test +contract Withdraw_Lockup_Dynamic_Integration_Fuzz_Test is + Withdraw_Integration_Fuzz_Test, + Lockup_Dynamic_Integration_Shared_Test { - function setUp() public virtual override(LockupDynamic_Integration_Shared_Test, Integration_Test) { - LockupDynamic_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Dynamic_Integration_Shared_Test, Integration_Test) { + Lockup_Dynamic_Integration_Shared_Test.setUp(); } struct Params { @@ -74,17 +73,17 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is resetPrank({ msgSender: users.sender }); // Create the stream with the fuzzed segments. - LockupDynamic.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLD(); + Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestamps(); createParams.totalAmount = vars.totalAmount; - createParams.segments = params.segments; + createParams.endTime = params.segments[params.segments.length - 1].timestamp; - vars.streamId = lockupDynamic.createWithTimestamps(createParams); + vars.streamId = lockup.createWithTimestampsLD(createParams, params.segments); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + params.timeJump }); // Query the withdrawable amount. - vars.withdrawableAmount = lockupDynamic.withdrawableAmountOf(vars.streamId); + vars.withdrawableAmount = lockup.withdrawableAmountOf(vars.streamId); // Halt the test if the withdraw amount is zero. if (vars.withdrawableAmount == 0) { @@ -98,29 +97,29 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupDynamic) }); - emit ISablierLockup.WithdrawFromLockupStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount, asset: dai }); - vm.expectEmit({ emitter: address(lockupDynamic) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Make the Recipient the caller. resetPrank({ msgSender: users.recipient }); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); + lockup.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); // Check if the stream is depleted or settled. It is possible for the stream to be just settled // and not depleted because the withdraw amount is fuzzed. vars.isDepleted = vars.withdrawAmount == vars.createAmounts.deposit; - vars.isSettled = lockupDynamic.refundableAmountOf(vars.streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0; // Assert that the stream's status is correct. - vars.actualStatus = lockupDynamic.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (vars.isDepleted) { vars.expectedStatus = Lockup.Status.DEPLETED; } else if (vars.isSettled) { @@ -131,7 +130,7 @@ contract Withdraw_LockupDynamic_Integration_Fuzz_Test is assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the withdrawn amount has been updated. - vars.actualWithdrawnAmount = lockupDynamic.getWithdrawnAmount(vars.streamId); + vars.actualWithdrawnAmount = lockup.getWithdrawnAmount(vars.streamId); vars.expectedWithdrawnAmount = vars.withdrawAmount; assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "withdrawnAmount"); } diff --git a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol index 602ac655c..f066d14e4 100644 --- a/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-dynamic/withdrawableAmountOf.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupDynamic_Integration_Shared_Test } from "./LockupDynamic.t.sol"; +import { Lockup_Dynamic_Integration_Shared_Test } from "./../../shared/lockup/LockupDynamic.t.sol"; -contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynamic_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Dynamic_Integration_Fuzz_Test is Lockup_Dynamic_Integration_Shared_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -18,18 +18,17 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynam // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); - uint256 streamId = lockupDynamic.createWithTimestamps(params); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); + uint256 streamId = lockup.createWithTimestampsLD(params, defaults.segments()); // Simulate the passage of time. uint40 blockTimestamp = defaults.START_TIME() + timeJump; vm.warp({ newTimestamp: blockTimestamp }); // Run the test. - uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); - uint128 expectedWithdrawableAmount = calculateStreamedAmountForMultipleSegments( - defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT() - ); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); + uint128 expectedWithdrawableAmount = + calculateLockupDynamicStreamedAmount(defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT()); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -53,9 +52,9 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynam { // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupDynamic.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLD(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = defaults.DEPOSIT_AMOUNT(); - uint256 streamId = lockupDynamic.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLD(params, defaults.segments()); timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); @@ -63,16 +62,15 @@ contract WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test is LockupDynam vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. - uint128 streamedAmount = calculateStreamedAmountForMultipleSegments( - defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT() - ); + uint128 streamedAmount = + calculateLockupDynamicStreamedAmount(defaults.segments(), defaults.START_TIME(), defaults.DEPOSIT_AMOUNT()); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupDynamic.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. - uint128 actualWithdrawableAmount = lockupDynamic.withdrawableAmountOf(streamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = streamedAmount - withdrawAmount; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } diff --git a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol index 9247145f1..cded1d063 100644 --- a/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol +++ b/test/core/integration/fuzz/lockup-linear/LockupLinear.t.sol @@ -1,98 +1,109 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear_Integration_Shared_Test, Integration_Test } from "../../shared/lockup-linear/LockupLinear.t.sol"; -import { Cancel_Integration_Fuzz_Test } from "../lockup/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "../lockup/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "../lockup/getWithdrawnAmount.t.sol"; -import { RefundableAmountOf_Integration_Fuzz_Test } from "../lockup/refundableAmountOf.t.sol"; -import { Withdraw_Integration_Fuzz_Test } from "../lockup/withdraw.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "../lockup/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "../lockup/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultiple.t.sol"; +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_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract Cancel_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, Cancel_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, - CancelMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Shared_Test, CancelMultiple_Integration_Fuzz_Test) - { - LockupLinear_Integration_Shared_Test.setUp(); +contract CancelMultiple_Lockup_Linear_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { + modifier whenCallerAuthorizedForAllStreams() override { + cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLL({ warpTime: originalTime }); + _; + } + + function setUp() public virtual override { CancelMultiple_Integration_Fuzz_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_LINEAR; } } -contract GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract GetWithdrawnAmount_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, GetWithdrawnAmount_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract RefundableAmountOf_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract RefundableAmountOf_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, RefundableAmountOf_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract Withdraw_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract Withdraw_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, Withdraw_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawMax_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawMax_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawMax_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Linear_Integration_Fuzz_Test is + Lockup_Linear_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Fuzz_Test { - function setUp() public virtual override(LockupLinear_Integration_Shared_Test, Integration_Test) { - LockupLinear_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Linear_Integration_Shared_Test, Integration_Test) { + Lockup_Linear_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupLinear_Integration_Fuzz_Test is - LockupLinear_Integration_Shared_Test, - WithdrawMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupLinear_Integration_Shared_Test, WithdrawMultiple_Integration_Fuzz_Test) - { - LockupLinear_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; } } diff --git a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol similarity index 61% rename from test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol index f1135bcaa..b9167e80a 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithDurationsLL.t.sol @@ -1,18 +1,18 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +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 { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; +import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; -contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is LockupLinear_Integration_Shared_Test { +contract CreateWithDurationsLL_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupLinear_Integration_Shared_Test.setUp(); - streamId = lockupLinear.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function testFuzz_RevertWhen_TotalDurationCalculationOverflows(LockupLinear.Durations memory durations) @@ -34,14 +34,14 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is LockupLinear_ // Expect the relevant error to be thrown. vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) + abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); // Create the stream. - createDefaultStreamWithDurations(durations); + createDefaultStreamWithDurationsLL(durations); } - function testFuzz_CreateWithDurations(LockupLinear.Durations memory durations) + function testFuzz_CreateWithDurationsLL(LockupLinear.Durations memory durations) external whenNoDelegateCall WhenCliffTimeCalculationNotOverflow @@ -54,21 +54,21 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is LockupLinear_ address funder = users.sender; // Expect the assets to be transferred from the funder to {SablierLockupLinear}. - expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: defaults.DEPOSIT_AMOUNT() }); + 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. - LockupLinear.Timestamps memory timestamps = LockupLinear.Timestamps({ + Lockup.Timestamps memory timestamps = Lockup.Timestamps({ start: getBlockTimestamp(), cliff: durations.cliff == 0 ? 0 : getBlockTimestamp() + durations.cliff, end: getBlockTimestamp() + durations.total }); // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockupLinear.CreateLockupLinearStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ streamId: streamId, funder: funder, sender: users.sender, @@ -82,28 +82,34 @@ contract CreateWithDurations_LockupLinear_Integration_Fuzz_Test is LockupLinear_ }); // Create the stream. - createDefaultStreamWithDurations(durations); - - // Assert that the stream has been created. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); - LockupLinear.StreamLL memory expectedStream = defaults.lockupLinearStream(); - expectedStream.cliffTime = timestamps.cliff; - expectedStream.endTime = timestamps.end; - expectedStream.startTime = timestamps.start; - assertEq(actualStream, expectedStream); + createDefaultStreamWithDurationsLL(durations); + + // 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"); + 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"); // Assert that the stream's status is "STREAMING". - Lockup.Status actualStatus = lockupLinear.statusOf(streamId); + Lockup.Status actualStatus = lockup.statusOf(streamId); Lockup.Status expectedStatus = Lockup.Status.STREAMING; assertEq(actualStatus, expectedStatus); // Assert that the next stream ID has been bumped. - uint256 actualNextStreamId = lockupLinear.nextStreamId(); + uint256 actualNextStreamId = lockup.nextStreamId(); uint256 expectedNextStreamId = streamId + 1; assertEq(actualNextStreamId, expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - address actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + address actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); address expectedNFTOwner = users.recipient; assertEq(actualNFTOwner, expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol similarity index 62% rename from test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol index 8a144b490..29ff5ec53 100644 --- a/test/core/integration/fuzz/lockup-linear/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-linear/createWithTimestampsLL.t.sol @@ -3,18 +3,18 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Errors } from "src/core/libraries/Errors.sol"; -import { Broker, Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; +import { Broker, Lockup } from "src/core/types/DataTypes.sol"; -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; +import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; -contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear_Integration_Shared_Test { +contract CreateWithTimestampsLL_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupLinear_Integration_Shared_Test.setUp(); - streamId = lockupLinear.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) @@ -29,7 +29,7 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(broker); + createDefaultStreamWithBrokerLL(broker); } function testFuzz_RevertWhen_StartTimeNotLessThanCliffTime(uint40 startTime) @@ -42,10 +42,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear startTime = boundUint40(startTime, defaults.CLIFF_TIME() + 1 seconds, defaults.END_TIME() - 1 seconds); vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupLinear_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() + Errors.SablierLockup_StartTimeNotLessThanCliffTime.selector, startTime, defaults.CLIFF_TIME() ) ); - createDefaultStreamWithStartTime(startTime); + createDefaultStreamWithStartTimeLL(startTime); } function testFuzz_RevertWhen_CliffTimeNotLessThanEndTime( @@ -63,9 +63,9 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear cliffTime = boundUint40(cliffTime, endTime, MAX_UNIX_TIMESTAMP); vm.expectRevert( - abi.encodeWithSelector(Errors.SablierLockupLinear_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) + abi.encodeWithSelector(Errors.SablierLockup_CliffTimeNotLessThanEndTime.selector, cliffTime, endTime) ); - createDefaultStreamWithTimestamps(LockupLinear.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); + createDefaultStreamWithTimestampsLL(Lockup.Timestamps({ start: startTime, cliff: cliffTime, end: endTime })); } struct Vars { @@ -90,9 +90,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear /// - Cliff time zero and not zero /// - Multiple values for the cliff time and the end time /// - Multiple values for the broker fee, including zero - function testFuzz_CreateWithTimestamps( + function testFuzz_CreateWithTimestampsLL( address funder, - LockupLinear.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + uint40 cliffTime ) external whenNoDelegateCall @@ -110,21 +111,16 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear && params.broker.account != address(0) ); vm.assume(params.totalAmount != 0); - params.timestamps.start = - boundUint40(params.timestamps.start, defaults.START_TIME(), defaults.START_TIME() + 10_000 seconds); + params.startTime = boundUint40(params.startTime, 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 (params.timestamps.cliff > 0) { - 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); + 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); } else { - params.timestamps.end = - boundUint40(params.timestamps.end, params.timestamps.start + 1 seconds, MAX_UNIX_TIMESTAMP); + params.endTime = boundUint40(params.endTime, params.startTime + 1 seconds, MAX_UNIX_TIMESTAMP); } // Calculate the fee amounts and the deposit amount. @@ -140,10 +136,10 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear deal({ token: address(dai), to: funder, give: params.totalAmount }); // Approve {SablierLockupLinear} to transfer the assets from the fuzzed funder. - dai.approve({ spender: address(lockupLinear), value: MAX_UINT256 }); + dai.approve({ spender: address(lockup), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierLockupLinear}. - expectCallToTransferFrom({ from: funder, to: address(lockupLinear), value: vars.createAmounts.deposit }); + expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -151,8 +147,8 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear } // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(lockupLinear) }); - emit ISablierLockupLinear.CreateLockupLinearStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupLinearStream({ streamId: streamId, funder: funder, sender: params.sender, @@ -161,52 +157,52 @@ contract CreateWithTimestamps_LockupLinear_Integration_Fuzz_Test is LockupLinear asset: dai, cancelable: params.cancelable, transferable: params.transferable, - timestamps: params.timestamps, + timestamps: Lockup.Timestamps({ start: params.startTime, cliff: cliffTime, end: params.endTime }), broker: params.broker.account }); // Create the stream. - lockupLinear.createWithTimestamps( - LockupLinear.CreateWithTimestamps({ + lockup.createWithTimestampsLL( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.totalAmount, asset: dai, cancelable: params.cancelable, transferable: params.transferable, - timestamps: params.timestamps, + startTime: params.startTime, + endTime: params.endTime, broker: params.broker - }) + }), + cliffTime ); - // Assert that the stream has been created. - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.cliffTime, params.timestamps.cliff, "cliffTime"); - assertEq(actualStream.endTime, params.timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, params.cancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isStream"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.startTime, params.timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + // 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"); // Assert that the stream's status is correct. - vars.actualStatus = lockupLinear.statusOf(streamId); - vars.expectedStatus = - params.timestamps.start > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; + vars.actualStatus = lockup.statusOf(streamId); + vars.expectedStatus = params.startTime > getBlockTimestamp() ? Lockup.Status.PENDING : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupLinear.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupLinear.ownerOf({ tokenId: streamId }); + 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 5411cc50b..88ce9a5b9 100644 --- a/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/streamedAmountOf.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; -contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Shared_Test { function testFuzz_StreamedAmountOf_CliffTimeInFuture(uint40 timeJump) external givenNotNull @@ -13,7 +13,7 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear_Int { timeJump = boundUint40(timeJump, 0, defaults.CLIFF_DURATION() - 1); vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(defaultStreamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(defaultStreamId); uint128 expectedStreamedAmount = 0; assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -42,17 +42,17 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear_Int deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLL(params, defaults.CLIFF_TIME()); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. - uint128 actualStreamedAmount = lockupLinear.streamedAmountOf(streamId); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); uint128 expectedStreamedAmount = - calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); + calculateLockupLinearStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -75,21 +75,21 @@ contract StreamedAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear_Int deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream with the fuzzed deposit amount. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLL(params, defaults.CLIFF_TIME()); // Warp to the future for the first time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. - uint128 streamedAmount0 = lockupLinear.streamedAmountOf(streamId); + uint128 streamedAmount0 = lockup.streamedAmountOf(streamId); // Warp to the future for the second time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. - uint128 streamedAmount1 = lockupLinear.streamedAmountOf(streamId); + uint128 streamedAmount1 = lockup.streamedAmountOf(streamId); assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol index d5b2bf022..97f3b5bff 100644 --- a/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-linear/withdrawableAmountOf.t.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupLinear_Integration_Shared_Test } from "./LockupLinear.t.sol"; +import { Lockup_Linear_Integration_Shared_Test } from "./../../shared/lockup/LockupLinear.t.sol"; -contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Linear_Integration_Fuzz_Test is Lockup_Linear_Integration_Shared_Test { function testFuzz_WithdrawableAmountOf_CliffTimeInFuture(uint40 timeJump) external givenNotNull @@ -13,7 +13,7 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear { timeJump = boundUint40(timeJump, 0, defaults.CLIFF_DURATION() - 1); vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(defaultStreamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(defaultStreamId); uint128 expectedWithdrawableAmount = 0; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -41,17 +41,17 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLL(params, defaults.CLIFF_TIME()); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Run the test. - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = - calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); + calculateLockupLinearStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -83,9 +83,9 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear deal({ token: address(dai), to: users.sender, give: depositAmount }); // Create the stream. The broker fee is disabled so that it doesn't interfere with the calculations. - LockupLinear.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLL(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNull(); params.totalAmount = depositAmount; - uint256 streamId = lockupLinear.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLL(params, defaults.CLIFF_TIME()); timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); @@ -93,14 +93,15 @@ contract WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test is LockupLinear vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. - uint128 streamedAmount = calculateStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); + uint128 streamedAmount = + calculateLockupLinearStreamedAmount(defaults.START_TIME(), defaults.END_TIME(), depositAmount); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupLinear.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. - uint128 actualWithdrawableAmount = lockupLinear.withdrawableAmountOf(streamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = streamedAmount - withdrawAmount; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } diff --git a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol index 5b2f71e33..2720b4286 100644 --- a/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/LockupTranched.t.sol @@ -1,90 +1,99 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { - LockupTranched_Integration_Shared_Test, Integration_Test -} from "../../shared/lockup-tranched/LockupTranched.t.sol"; -import { Cancel_Integration_Fuzz_Test } from "../lockup/cancel.t.sol"; -import { CancelMultiple_Integration_Fuzz_Test } from "../lockup/cancelMultiple.t.sol"; -import { GetWithdrawnAmount_Integration_Fuzz_Test } from "../lockup/getWithdrawnAmount.t.sol"; -import { RefundableAmountOf_Integration_Fuzz_Test } from "../lockup/refundableAmountOf.t.sol"; -import { WithdrawMax_Integration_Fuzz_Test } from "../lockup/withdrawMax.t.sol"; -import { WithdrawMaxAndTransfer_Integration_Fuzz_Test } from "../lockup/withdrawMaxAndTransfer.t.sol"; -import { WithdrawMultiple_Integration_Fuzz_Test } from "../lockup/withdrawMultiple.t.sol"; +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_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, +contract Cancel_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Shared_Test, Cancel_Integration_Fuzz_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract CancelMultiple_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, - CancelMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupTranched_Integration_Shared_Test, CancelMultiple_Integration_Fuzz_Test) - { - LockupTranched_Integration_Shared_Test.setUp(); +contract CancelMultiple_Lockup_Tranched_Integration_Fuzz_Test is CancelMultiple_Integration_Fuzz_Test { + modifier whenCallerAuthorizedForAllStreams() override { + cancelMultipleStreamIds = WarpAndCreateStreamsForCancelMultipleLT({ warpTime: originalTime }); + _; + } + + function setUp() public virtual override { CancelMultiple_Integration_Fuzz_Test.setUp(); + lockupModel = Lockup.Model.LOCKUP_TRANCHED; } } -contract RefundableAmountOf_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, +contract RefundableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Shared_Test, RefundableAmountOf_Integration_Fuzz_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract GetWithdrawnAmount_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, +contract GetWithdrawnAmount_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Shared_Test, GetWithdrawnAmount_Integration_Fuzz_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawMax_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawMax_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawMax_Integration_Fuzz_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawMaxAndTransfer_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, +contract WithdrawMaxAndTransfer_Lockup_Tranched_Integration_Fuzz_Test is + Lockup_Tranched_Integration_Shared_Test, WithdrawMaxAndTransfer_Integration_Fuzz_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } } -contract WithdrawMultiple_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, - WithdrawMultiple_Integration_Fuzz_Test -{ - function setUp() - public - virtual - override(LockupTranched_Integration_Shared_Test, WithdrawMultiple_Integration_Fuzz_Test) - { - LockupTranched_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; } } diff --git a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol similarity index 61% rename from test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol rename to test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol index c07397e85..f4392d604 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithDurations.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithDurationsLT.t.sol @@ -1,17 +1,17 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; +import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; -contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Shared_Test { +contract CreateWithDurationsLT_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupTranched_Integration_Shared_Test.setUp(); - streamId = lockupTranched.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } struct Vars { @@ -29,7 +29,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranc uint128 totalAmount; } - function testFuzz_CreateWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) + function testFuzz_CreateWithDurationsLT(LockupTranched.TrancheWithDuration[] memory tranches) external whenNoDelegateCall whenTrancheCountNotExceedMaxValue @@ -51,7 +51,7 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranc deal({ token: address(dai), to: vars.funder, give: vars.totalAmount }); // Expect the assets to be transferred from the funder to {SablierLockupTranched}. - expectCallToTransferFrom({ from: vars.funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); + expectCallToTransferFrom({ from: vars.funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -60,14 +60,15 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranc // Create the timestamps struct. vars.tranchesWithTimestamps = getTranchesWithTimestamps(tranches); - LockupTranched.Timestamps memory timestamps = LockupTranched.Timestamps({ + 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(lockupTranched) }); - emit ISablierLockupTranched.CreateLockupTranchedStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockup.CreateLockupTranchedStream({ streamId: streamId, funder: vars.funder, sender: users.sender, @@ -82,44 +83,42 @@ contract CreateWithDurations_LockupTranched_Integration_Fuzz_Test is LockupTranc }); // Create the stream. - LockupTranched.CreateWithDurations memory params = defaults.createWithDurationsLT(); - params.tranches = tranches; + Lockup.CreateWithDurations memory params = defaults.createWithDurations(); params.totalAmount = vars.totalAmount; params.transferable = true; - lockupTranched.createWithDurations(params); + lockup.createWithDurationsLT(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. - vars.isSettled = lockupTranched.refundableAmountOf(streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(streamId) == 0; vars.isCancelable = vars.isSettled ? false : true; - // Assert that the stream has been created. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isDepleted"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.tranches, vars.tranchesWithTimestamps, "tranches"); - assertEq(actualStream.sender, users.sender, "sender"); - assertEq(actualStream.startTime, timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + // 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.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"); + assertEq(lockup.getSender(streamId), users.sender, "sender"); + assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getTranches(streamId), vars.tranchesWithTimestamps, "tranches"); // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(streamId); + vars.actualStatus = lockup.statusOf(streamId); vars.expectedStatus = vars.isSettled ? Lockup.Status.SETTLED : Lockup.Status.STREAMING; assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + vars.actualNFTOwner = lockup.ownerOf({ tokenId: streamId }); vars.expectedNFTOwner = users.recipient; assertEq(vars.actualNFTOwner, vars.expectedNFTOwner, "NFT owner"); } diff --git a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol b/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol similarity index 72% rename from test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol rename to test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol index 8f604642c..f06a05414 100644 --- a/test/core/integration/fuzz/lockup-tranched/createWithTimestamps.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/createWithTimestampsLT.t.sol @@ -4,18 +4,18 @@ pragma solidity >=0.8.22 <0.9.0; import { MAX_UD60x18, ud } from "@prb/math/src/UD60x18.sol"; import { stdError } from "forge-std/src/StdError.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.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 { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; +import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; -contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Shared_Test { +contract CreateWithTimestampsLT_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { uint256 internal streamId; function setUp() public virtual override { - LockupTranched_Integration_Shared_Test.setUp(); - streamId = lockupTranched.nextStreamId(); + Lockup_Integration_Shared_Test.setUp(); + streamId = lockup.nextStreamId(); } function testFuzz_RevertWhen_TrancheCountTooHigh(uint256 trancheCount) @@ -26,11 +26,11 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran whenDepositAmountNotZero whenTrancheCountNotZero { - uint256 defaultMax = defaults.MAX_TRANCHE_COUNT(); + 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.SablierLockupTranched_TrancheCountTooHigh.selector, trancheCount)); - createDefaultStreamWithTranches(tranches); + vm.expectRevert(abi.encodeWithSelector(Errors.SablierLockup_TrancheCountTooHigh.selector, trancheCount)); + createDefaultStreamWithTranchesLT(tranches); } function testFuzz_RevertWhen_TrancheAmountsSumOverflows( @@ -51,7 +51,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran tranches[0].amount = amount0; tranches[1].amount = amount1; vm.expectRevert(stdError.arithmeticError); - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function testFuzz_RevertWhen_StartTimeNotLessThanFirstTrancheTimestamp(uint40 firstTimestamp) @@ -73,14 +73,14 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran // Expect the relevant error to be thrown. vm.expectRevert( abi.encodeWithSelector( - Errors.SablierLockupTranched_StartTimeNotLessThanFirstTrancheTimestamp.selector, + Errors.SablierLockup_StartTimeNotLessThanFirstTrancheTimestamp.selector, defaults.START_TIME(), tranches[0].timestamp ) ); // Create the stream. - createDefaultStreamWithTranches(tranches); + createDefaultStreamWithTranchesLT(tranches); } function testFuzz_RevertWhen_DepositAmountNotEqualToTrancheAmountsSum(uint128 depositDiff) @@ -104,20 +104,21 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran uint128 depositAmount = defaultDepositAmount + depositDiff; // Prepare the params. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsBrokerNullLT(); + 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.SablierLockupTranched_DepositAmountNotEqualToTrancheAmountsSum.selector, + Errors.SablierLockup_DepositAmountNotEqualToTrancheAmountsSum.selector, depositAmount, defaultDepositAmount ) ); // Create the stream. - lockupTranched.createWithTimestamps(params); + lockup.createWithTimestampsLT(params, tranches); } function testFuzz_RevertWhen_BrokerFeeTooHigh(Broker memory broker) @@ -138,7 +139,7 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran vm.expectRevert( abi.encodeWithSelector(Errors.SablierLockup_BrokerFeeTooHigh.selector, broker.fee, MAX_BROKER_FEE) ); - createDefaultStreamWithBroker(broker); + createDefaultStreamWithBrokerLT(broker); } struct Vars { @@ -164,9 +165,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran /// - Start time in the future /// - Start time equal and not equal to the first tranche timestamp /// - Multiple values for the broker fee, including zero - function testFuzz_CreateWithTimestamps( + function testFuzz_CreateWithTimestampsLT( address funder, - LockupTranched.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + LockupTranched.Tranche[] memory tranches ) external whenNoDelegateCall @@ -188,22 +190,19 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran funder != address(0) && params.sender != address(0) && params.recipient != address(0) && params.broker.account != address(0) ); - vm.assume(params.tranches.length != 0); + 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.transferable = true; // Fuzz the tranche timestamps. - fuzzTrancheTimestamps(params.tranches, params.startTime); + fuzzTrancheTimestamps(tranches, params.startTime); // 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: params.tranches, - brokerFee: params.broker.fee - }); + (vars.totalAmount, vars.createAmounts) = + fuzzTranchedStreamAmounts({ upperBound: MAX_UINT128, tranches: tranches, brokerFee: params.broker.fee }); // Make the fuzzed funder the caller in the rest of this test. resetPrank(funder); @@ -212,10 +211,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran deal({ token: address(dai), to: funder, give: vars.totalAmount }); // Approve {SablierLockupTranched} to transfer the assets from the fuzzed funder. - dai.approve({ spender: address(lockupTranched), value: MAX_UINT256 }); + dai.approve({ spender: address(lockup), value: MAX_UINT256 }); // Expect the assets to be transferred from the funder to {SablierLockupTranched}. - expectCallToTransferFrom({ from: funder, to: address(lockupTranched), value: vars.createAmounts.deposit }); + expectCallToTransferFrom({ from: funder, to: address(lockup), value: vars.createAmounts.deposit }); // Expect the broker fee to be paid to the broker, if not zero. if (vars.createAmounts.brokerFee > 0) { @@ -223,12 +222,10 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran } // Expect the relevant event to be emitted. - vm.expectEmit({ emitter: address(lockupTranched) }); - LockupTranched.Timestamps memory timestamps = LockupTranched.Timestamps({ - start: params.startTime, - end: params.tranches[params.tranches.length - 1].timestamp - }); - emit ISablierLockupTranched.CreateLockupTranchedStream({ + 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, funder: funder, sender: params.sender, @@ -237,14 +234,14 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran asset: dai, cancelable: params.cancelable, transferable: params.transferable, - tranches: params.tranches, + tranches: tranches, timestamps: timestamps, broker: params.broker.account }); // Create the stream. - lockupTranched.createWithTimestamps( - LockupTranched.CreateWithTimestamps({ + lockup.createWithTimestampsLT( + Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: vars.totalAmount, @@ -252,33 +249,33 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran cancelable: params.cancelable, transferable: params.transferable, startTime: params.startTime, - tranches: params.tranches, + endTime: tranches[tranches.length - 1].timestamp, broker: params.broker - }) + }), + 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. - vars.isSettled = (lockupTranched.getDepositedAmount(streamId) - lockupTranched.streamedAmountOf(streamId)) == 0; + vars.isSettled = (lockup.getDepositedAmount(streamId) - lockup.streamedAmountOf(streamId)) == 0; vars.isCancelable = vars.isSettled ? false : params.cancelable; - // Assert that the stream has been created. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(streamId); - assertEq(actualStream.amounts, Lockup.Amounts(vars.createAmounts.deposit, 0, 0)); - assertEq(actualStream.asset, dai, "asset"); - assertEq(actualStream.endTime, timestamps.end, "endTime"); - assertEq(actualStream.isCancelable, vars.isCancelable, "isCancelable"); - assertEq(actualStream.isDepleted, false, "isStream"); - assertEq(actualStream.isStream, true, "isStream"); - assertEq(actualStream.isTransferable, true, "isTransferable"); - assertEq(actualStream.recipient, params.recipient, "recipient"); - assertEq(actualStream.sender, params.sender, "sender"); - assertEq(actualStream.tranches, params.tranches, "tranches"); - assertEq(actualStream.startTime, timestamps.start, "startTime"); - assertEq(actualStream.wasCanceled, false, "wasCanceled"); + // 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.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"); + assertEq(lockup.getSender(streamId), params.sender, "sender"); + assertEq(lockup.getStartTime(streamId), timestamps.start, "startTime"); + assertEq(lockup.wasCanceled(streamId), false, "wasCanceled"); + assertEq(lockup.getTranches(streamId), tranches, "tranches"); // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(streamId); + vars.actualStatus = lockup.statusOf(streamId); if (params.startTime > getBlockTimestamp()) { vars.expectedStatus = Lockup.Status.PENDING; } else if (vars.isSettled) { @@ -289,12 +286,12 @@ contract CreateWithTimestamps_LockupTranched_Integration_Fuzz_Test is LockupTran assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the next stream ID has been bumped. - vars.actualNextStreamId = lockupTranched.nextStreamId(); + vars.actualNextStreamId = lockup.nextStreamId(); vars.expectedNextStreamId = streamId + 1; assertEq(vars.actualNextStreamId, vars.expectedNextStreamId, "nextStreamId"); // Assert that the NFT has been minted. - vars.actualNFTOwner = lockupTranched.ownerOf({ tokenId: streamId }); + 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-tranched/streamedAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol index 426cf595b..1dc868de1 100644 --- a/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/streamedAmountOf.t.sol @@ -2,11 +2,11 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; +import { Broker, Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; +import { Lockup_Tranched_Integration_Shared_Test } from "./../../shared/lockup/LockupTranched.t.sol"; -contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Shared_Test { +contract StreamedAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Tranched_Integration_Shared_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -44,19 +44,19 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed tranches. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); - params.tranches = tranches; params.totalAmount = totalAmount; - uint256 streamId = lockupTranched.createWithTimestamps(params); + params.endTime = 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 }); // Run the test. - uint128 actualStreamedAmount = lockupTranched.streamedAmountOf(streamId); - uint128 expectedStreamedAmount = calculateStreamedAmountForTranches(tranches, totalAmount); + uint128 actualStreamedAmount = lockup.streamedAmountOf(streamId); + uint128 expectedStreamedAmount = calculateLockupTranchedStreamedAmount(tranches, totalAmount); assertEq(actualStreamedAmount, expectedStreamedAmount, "streamedAmount"); } @@ -92,23 +92,23 @@ contract StreamedAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched deal({ token: address(dai), to: users.sender, give: totalAmount }); // Create the stream with the fuzzed tranches. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); - params.tranches = tranches; params.totalAmount = totalAmount; - uint256 streamId = lockupTranched.createWithTimestamps(params); + params.endTime = tranches[tranches.length - 1].timestamp; + uint256 streamId = lockup.createWithTimestampsLT(params, tranches); // Warp to the future for the first time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp0 }); // Calculate the streamed amount at this midpoint in time. - uint128 streamedAmount0 = lockupTranched.streamedAmountOf(streamId); + uint128 streamedAmount0 = lockup.streamedAmountOf(streamId); // Warp to the future for the second time. vm.warp({ newTimestamp: defaults.START_TIME() + timeWarp1 }); // Assert that this streamed amount is greater than or equal to the previous streamed amount. - uint128 streamedAmount1 = lockupTranched.streamedAmountOf(streamId); + uint128 streamedAmount1 = lockup.streamedAmountOf(streamId); assertGe(streamedAmount1, streamedAmount0, "streamedAmount"); } } diff --git a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol index 59781cceb..76e7025bf 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdraw.t.sol @@ -2,22 +2,21 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC4906 } from "@openzeppelin/contracts/interfaces/IERC4906.sol"; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; - -import { Withdraw_Integration_Fuzz_Test, Integration_Test } from "../lockup/withdraw.t.sol"; -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.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"; /// @dev This contract complements the tests in {Withdraw_Integration_Fuzz_Test} by testing the withdraw function /// against /// streams created with fuzzed tranches. -contract Withdraw_LockupTranched_Integration_Fuzz_Test is - LockupTranched_Integration_Shared_Test, - Withdraw_Integration_Fuzz_Test +contract Withdraw_Lockup_Tranched_Integration_Fuzz_Test is + Withdraw_Integration_Fuzz_Test, + Lockup_Tranched_Integration_Shared_Test { - function setUp() public virtual override(LockupTranched_Integration_Shared_Test, Integration_Test) { - LockupTranched_Integration_Shared_Test.setUp(); + function setUp() public virtual override(Lockup_Tranched_Integration_Shared_Test, Integration_Test) { + Lockup_Tranched_Integration_Shared_Test.setUp(); } struct Params { @@ -74,17 +73,17 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is resetPrank({ msgSender: users.sender }); // Create the stream with the fuzzed tranches. - LockupTranched.CreateWithTimestamps memory createParams = defaults.createWithTimestampsLT(); + Lockup.CreateWithTimestamps memory createParams = defaults.createWithTimestamps(); createParams.totalAmount = vars.totalAmount; - createParams.tranches = params.tranches; + createParams.endTime = params.tranches[params.tranches.length - 1].timestamp; - vars.streamId = lockupTranched.createWithTimestamps(createParams); + vars.streamId = lockup.createWithTimestampsLT(createParams, params.tranches); // Simulate the passage of time. vm.warp({ newTimestamp: defaults.START_TIME() + params.timeJump }); // Query the withdrawable amount. - vars.withdrawableAmount = lockupTranched.withdrawableAmountOf(vars.streamId); + vars.withdrawableAmount = lockup.withdrawableAmountOf(vars.streamId); // Halt the test if the withdraw amount is zero. if (vars.withdrawableAmount == 0) { @@ -101,26 +100,26 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is expectCallToTransfer({ to: params.to, value: vars.withdrawAmount }); // Expect the relevant events to be emitted. - vm.expectEmit({ emitter: address(lockupTranched) }); - emit ISablierLockup.WithdrawFromLockupStream({ + vm.expectEmit({ emitter: address(lockup) }); + emit ISablierLockupBase.WithdrawFromLockupStream({ streamId: vars.streamId, to: params.to, asset: dai, amount: vars.withdrawAmount }); - vm.expectEmit({ emitter: address(lockupTranched) }); + vm.expectEmit({ emitter: address(lockup) }); emit IERC4906.MetadataUpdate({ _tokenId: vars.streamId }); // Make the withdrawal. - lockupTranched.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); + lockup.withdraw({ streamId: vars.streamId, to: params.to, amount: vars.withdrawAmount }); // Check if the stream is depleted or settled. It is possible for the stream to be just settled // and not depleted because the withdraw amount is fuzzed. vars.isDepleted = vars.withdrawAmount == vars.createAmounts.deposit; - vars.isSettled = lockupTranched.refundableAmountOf(vars.streamId) == 0; + vars.isSettled = lockup.refundableAmountOf(vars.streamId) == 0; // Assert that the stream's status is correct. - vars.actualStatus = lockupTranched.statusOf(vars.streamId); + vars.actualStatus = lockup.statusOf(vars.streamId); if (vars.isDepleted) { vars.expectedStatus = Lockup.Status.DEPLETED; } else if (vars.isSettled) { @@ -131,7 +130,7 @@ contract Withdraw_LockupTranched_Integration_Fuzz_Test is assertEq(vars.actualStatus, vars.expectedStatus); // Assert that the withdrawn amount has been updated. - vars.actualWithdrawnAmount = lockupTranched.getWithdrawnAmount(vars.streamId); + vars.actualWithdrawnAmount = lockup.getWithdrawnAmount(vars.streamId); vars.expectedWithdrawnAmount = vars.withdrawAmount; assertEq(vars.actualWithdrawnAmount, vars.expectedWithdrawnAmount, "withdrawnAmount"); } diff --git a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol index 5f9fd4020..a592e8412 100644 --- a/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol +++ b/test/core/integration/fuzz/lockup-tranched/withdrawableAmountOf.t.sol @@ -2,11 +2,11 @@ pragma solidity >=0.8.22 <0.9.0; import { ZERO } from "@prb/math/src/UD60x18.sol"; -import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; +import { Broker, Lockup } from "src/core/types/DataTypes.sol"; -import { LockupTranched_Integration_Shared_Test } from "./LockupTranched.t.sol"; +import { Lockup_Integration_Shared_Test } from "./../../shared/lockup/Lockup.t.sol"; -contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTranched_Integration_Shared_Test { +contract WithdrawableAmountOf_Lockup_Tranched_Integration_Fuzz_Test is Lockup_Integration_Shared_Test { /// @dev Given enough fuzz runs, all of the following scenarios will be fuzzed: /// /// - End time in the past @@ -19,19 +19,19 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTran // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = defaults.DEPOSIT_AMOUNT(); - uint256 streamId = lockupTranched.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLT(params, defaults.tranches()); // Simulate the passage of time. uint40 blockTimestamp = defaults.START_TIME() + timeJump; vm.warp({ newTimestamp: blockTimestamp }); // Run the test. - uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = - calculateStreamedAmountForTranches(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + calculateLockupTranchedStreamedAmount(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } @@ -55,10 +55,10 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTran { // Create the stream with a custom total amount. The broker fee is disabled so that it doesn't interfere with // the calculations. - LockupTranched.CreateWithTimestamps memory params = defaults.createWithTimestampsLT(); + Lockup.CreateWithTimestamps memory params = defaults.createWithTimestamps(); params.broker = Broker({ account: address(0), fee: ZERO }); params.totalAmount = defaults.DEPOSIT_AMOUNT(); - uint256 streamId = lockupTranched.createWithTimestamps(params); + uint256 streamId = lockup.createWithTimestampsLT(params, defaults.tranches()); timeJump = boundUint40(timeJump, defaults.CLIFF_DURATION(), defaults.TOTAL_DURATION() * 2); @@ -66,14 +66,14 @@ contract WithdrawableAmountOf_LockupTranched_Integration_Fuzz_Test is LockupTran vm.warp({ newTimestamp: defaults.START_TIME() + timeJump }); // Bound the withdraw amount. - uint128 streamedAmount = calculateStreamedAmountForTranches(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); + uint128 streamedAmount = calculateLockupTranchedStreamedAmount(defaults.tranches(), defaults.DEPOSIT_AMOUNT()); withdrawAmount = boundUint128(withdrawAmount, 1, streamedAmount); // Make the withdrawal. - lockupTranched.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); + lockup.withdraw({ streamId: streamId, to: users.recipient, amount: withdrawAmount }); // Run the test. - uint128 actualWithdrawableAmount = lockupTranched.withdrawableAmountOf(streamId); + uint128 actualWithdrawableAmount = lockup.withdrawableAmountOf(streamId); uint128 expectedWithdrawableAmount = streamedAmount - withdrawAmount; assertEq(actualWithdrawableAmount, expectedWithdrawableAmount, "withdrawableAmount"); } diff --git a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol b/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol deleted file mode 100644 index 2de692918..000000000 --- a/test/core/integration/shared/lockup-dynamic/LockupDynamic.t.sol +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Broker, LockupDynamic } from "src/core/types/DataTypes.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -/// @notice Common testing logic needed across {SablierLockupDynamic} integration tests. -abstract contract LockupDynamic_Integration_Shared_Test is Integration_Test { - struct CreateParams { - LockupDynamic.CreateWithDurations createWithDurations; - LockupDynamic.CreateWithTimestamps createWithTimestamps; - } - - /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. - /// See https://github.com/foundry-rs/foundry/issues/4762. - CreateParams private _params; - - function setUp() public virtual override { - Integration_Test.setUp(); - - _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient; - _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithDurations.asset = dai; - _params.createWithDurations.cancelable = true; - _params.createWithDurations.transferable = true; - _params.createWithDurations.broker = defaults.broker(); - - _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient; - _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithTimestamps.asset = dai; - _params.createWithTimestamps.cancelable = true; - _params.createWithTimestamps.transferable = true; - _params.createWithTimestamps.startTime = defaults.START_TIME(); - _params.createWithTimestamps.broker = defaults.broker(); - - // See https://github.com/ethereum/solidity/issues/12783 - LockupDynamic.SegmentWithDuration[] memory segmentsWithDurations = defaults.segmentsWithDurations(); - LockupDynamic.Segment[] memory segments = defaults.segments(); - for (uint256 i = 0; i < defaults.SEGMENT_COUNT(); ++i) { - _params.createWithDurations.segments.push(segmentsWithDurations[i]); - _params.createWithTimestamps.segments.push(segments[i]); - } - - // Cast the {LockupDynamic} contract as {ISablierLockup}. - lockup = ISablierLockup(lockupDynamic); - - // Create the default stream. - defaultStreamId = createDefaultStream(); - - // Create a non-transferable stream. - notTransferableStreamId = createDefaultStreamNotTransferable(); - } - - /// @inheritdoc Integration_Test - function createDefaultStream() internal override returns (uint256 streamId) { - streamId = lockupDynamic.createWithTimestamps(_params.createWithTimestamps); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurations() internal returns (uint256 streamId) { - streamId = lockupDynamic.createWithDurations(_params.createWithDurations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupDynamic.SegmentWithDuration[] memory segments) - internal - returns (uint256 streamId) - { - LockupDynamic.CreateWithDurations memory params = _params.createWithDurations; - params.segments = segments; - streamId = lockupDynamic.createWithDurations(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.segments[1].timestamp = endTime; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided segments. - function createDefaultStreamWithSegments(LockupDynamic.Segment[] memory segments) - internal - returns (uint256 streamId) - { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.segments = segments; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = startTime; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupDynamic.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = timestamps.start; - params.segments[1].timestamp = timestamps.end; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockupDynamic.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - override - returns (uint256 streamId) - { - LockupDynamic.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockupDynamic.createWithTimestamps(params); - } -} diff --git a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol b/test/core/integration/shared/lockup-linear/LockupLinear.t.sol deleted file mode 100644 index 7ef270538..000000000 --- a/test/core/integration/shared/lockup-linear/LockupLinear.t.sol +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Broker, LockupLinear } from "src/core/types/DataTypes.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -/// @notice Common testing logic needed by all {SablierLockupLinear} integration tests. -abstract contract LockupLinear_Integration_Shared_Test is Integration_Test { - struct Params { - LockupLinear.CreateWithDurations createWithDurations; - LockupLinear.CreateWithTimestamps createWithTimestamps; - } - - /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. - /// See https://github.com/foundry-rs/foundry/issues/4762. - Params private _params; - - function setUp() public virtual override { - Integration_Test.setUp(); - _params.createWithDurations = defaults.createWithDurationsLL(); - _params.createWithTimestamps = defaults.createWithTimestampsLL(); - - // Cast the LockupLinear contract as {ISablierLockup}. - lockup = ISablierLockup(lockupLinear); - - // Create the default stream. - defaultStreamId = createDefaultStream(); - - // Create a non-transferable stream. - notTransferableStreamId = createDefaultStreamNotTransferable(); - } - - /// @inheritdoc Integration_Test - function createDefaultStream() internal override returns (uint256 streamId) { - streamId = lockupLinear.createWithTimestamps(_params.createWithTimestamps); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurations() internal returns (uint256 streamId) { - streamId = lockupLinear.createWithDurations(_params.createWithDurations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupLinear.Durations memory durations) - internal - returns (uint256 streamId) - { - LockupLinear.CreateWithDurations memory params = _params.createWithDurations; - params.durations = durations; - streamId = lockupLinear.createWithDurations(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.timestamps.end = endTime; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.timestamps.start = startTime; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupLinear.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.timestamps = timestamps; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockupLinear.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - override - returns (uint256 streamId) - { - LockupLinear.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockupLinear.createWithTimestamps(params); - } -} diff --git a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol b/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol deleted file mode 100644 index c120ad375..000000000 --- a/test/core/integration/shared/lockup-tranched/LockupTranched.t.sol +++ /dev/null @@ -1,187 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Broker, LockupTranched } from "src/core/types/DataTypes.sol"; - -import { Integration_Test } from "../../Integration.t.sol"; - -/// @notice Common testing logic needed across {SablierLockupTranched} integration tests. -abstract contract LockupTranched_Integration_Shared_Test is Integration_Test { - struct CreateParams { - LockupTranched.CreateWithDurations createWithDurations; - LockupTranched.CreateWithTimestamps createWithTimestamps; - } - - /// @dev These have to be pre-declared so that `vm.expectRevert` does not expect a revert in `defaults`. - /// See https://github.com/foundry-rs/foundry/issues/4762. - CreateParams private _params; - - function setUp() public virtual override { - Integration_Test.setUp(); - - _params.createWithDurations.sender = users.sender; - _params.createWithDurations.recipient = users.recipient; - _params.createWithDurations.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithDurations.asset = dai; - _params.createWithDurations.cancelable = true; - _params.createWithDurations.transferable = true; - _params.createWithDurations.broker = defaults.broker(); - - _params.createWithTimestamps.sender = users.sender; - _params.createWithTimestamps.recipient = users.recipient; - _params.createWithTimestamps.totalAmount = defaults.TOTAL_AMOUNT(); - _params.createWithTimestamps.asset = dai; - _params.createWithTimestamps.cancelable = true; - _params.createWithTimestamps.transferable = true; - _params.createWithTimestamps.startTime = defaults.START_TIME(); - _params.createWithTimestamps.broker = defaults.broker(); - - // See https://github.com/ethereum/solidity/issues/12783 - LockupTranched.TrancheWithDuration[] memory tranchesWithDurations = defaults.tranchesWithDurations(); - LockupTranched.Tranche[] memory tranches = defaults.tranches(); - for (uint256 i = 0; i < defaults.TRANCHE_COUNT(); ++i) { - _params.createWithDurations.tranches.push(tranchesWithDurations[i]); - _params.createWithTimestamps.tranches.push(tranches[i]); - } - - // Cast the LockupTranched contract as {ISablierLockup}. - lockup = ISablierLockup(lockupTranched); - - // Create the default stream. - defaultStreamId = createDefaultStream(); - - // Create a non-transferable stream. - notTransferableStreamId = createDefaultStreamNotTransferable(); - } - - /// @inheritdoc Integration_Test - function createDefaultStream() internal override returns (uint256 streamId) { - streamId = lockupTranched.createWithTimestamps(_params.createWithTimestamps); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithAsset(IERC20 asset) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.asset = asset; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithBroker(Broker memory broker) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.broker = broker; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @dev Creates the default stream with durations. - function createDefaultStreamWithDurations() internal returns (uint256 streamId) { - streamId = lockupTranched.createWithDurations(_params.createWithDurations); - } - - /// @dev Creates the default stream with the provided durations. - function createDefaultStreamWithDurations(LockupTranched.TrancheWithDuration[] memory tranches) - internal - returns (uint256 streamId) - { - LockupTranched.CreateWithDurations memory params = _params.createWithDurations; - params.tranches = tranches; - streamId = lockupTranched.createWithDurations(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithEndTime(uint40 endTime) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.tranches[2].timestamp = endTime; - - // Ensure the timestamps are arranged in ascending order. - if (params.tranches[2].timestamp <= params.tranches[1].timestamp) { - params.tranches[1].timestamp = params.tranches[2].timestamp - 1; - } - if (params.tranches[1].timestamp <= params.tranches[0].timestamp) { - params.tranches[0].timestamp = params.tranches[1].timestamp - 1; - } - - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotCancelable() internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.cancelable = false; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamNotTransferable() internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.transferable = false; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided timestamps. - function createDefaultStreamWithTimestamps(LockupTranched.Timestamps memory timestamps) - internal - returns (uint256 streamId) - { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = timestamps.start; - params.tranches[1].timestamp = timestamps.end; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithRecipient(address recipient) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @dev Creates the default stream with the provided tranches. - function createDefaultStreamWithTranches(LockupTranched.Tranche[] memory tranches) - internal - returns (uint256 streamId) - { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.tranches = tranches; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithSender(address sender) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.sender = sender; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithStartTime(uint40 startTime) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.startTime = startTime; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithTotalAmount(uint128 totalAmount) internal override returns (uint256 streamId) { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.totalAmount = totalAmount; - streamId = lockupTranched.createWithTimestamps(params); - } - - /// @inheritdoc Integration_Test - function createDefaultStreamWithUsers( - address recipient, - address sender - ) - internal - override - returns (uint256 streamId) - { - LockupTranched.CreateWithTimestamps memory params = _params.createWithTimestamps; - params.recipient = recipient; - params.sender = sender; - streamId = lockupTranched.createWithTimestamps(params); - } -} diff --git a/test/core/integration/shared/lockup/Lockup.t.sol b/test/core/integration/shared/lockup/Lockup.t.sol new file mode 100644 index 000000000..e23e5ce06 --- /dev/null +++ b/test/core/integration/shared/lockup/Lockup.t.sol @@ -0,0 +1,454 @@ +// 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 new file mode 100644 index 000000000..c9ba5a1f0 --- /dev/null +++ b/test/core/integration/shared/lockup/LockupDynamic.t.sol @@ -0,0 +1,26 @@ +// 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 new file mode 100644 index 000000000..04920379c --- /dev/null +++ b/test/core/integration/shared/lockup/LockupLinear.t.sol @@ -0,0 +1,26 @@ +// 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 new file mode 100644 index 000000000..8e31db98e --- /dev/null +++ b/test/core/integration/shared/lockup/LockupTranched.t.sol @@ -0,0 +1,26 @@ +// 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/lockup/cancelMultiple.t.sol b/test/core/integration/shared/lockup/cancelMultiple.t.sol deleted file mode 100644 index 6fb78c8de..000000000 --- a/test/core/integration/shared/lockup/cancelMultiple.t.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Integration_Test } from "../../Integration.t.sol"; - -abstract contract CancelMultiple_Integration_Shared_Test is Integration_Test { - uint40 internal originalTime; - uint256[] internal testStreamIds; - - function setUp() public virtual override { - originalTime = getBlockTimestamp(); - createTestStreams(); - } - - /// @dev Creates the default streams used throughout the tests. - function createTestStreams() internal { - // Warp back to the original timestamp. - vm.warp({ newTimestamp: originalTime }); - - // Create the test streams. - testStreamIds = new uint256[](2); - testStreamIds[0] = createDefaultStream(); - // Create a stream with an end time double that of the default stream so that the refund amounts are different. - testStreamIds[1] = createDefaultStreamWithEndTime(defaults.END_TIME() + defaults.TOTAL_DURATION()); - } - - modifier whenCallerAuthorizedForAll() { - _; - vm.warp({ newTimestamp: originalTime }); - createTestStreams(); - _; - } -} diff --git a/test/core/integration/shared/lockup/withdrawMultiple.t.sol b/test/core/integration/shared/lockup/withdrawMultiple.t.sol deleted file mode 100644 index cde5025f7..000000000 --- a/test/core/integration/shared/lockup/withdrawMultiple.t.sol +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Integration_Test } from "../../Integration.t.sol"; - -abstract contract WithdrawMultiple_Integration_Shared_Test is Integration_Test { - address internal caller; - uint40 internal earlyStopTime; - uint40 internal originalTime; - uint128[] internal testAmounts; - uint256[] internal testStreamIds; - - function setUp() public virtual override { - earlyStopTime = defaults.WARP_26_PERCENT(); - originalTime = getBlockTimestamp(); - createTestStreams(); - } - - /// @dev Creates the default streams used throughout the tests. - function createTestStreams() internal { - // Warp back to the original timestamp. - vm.warp({ newTimestamp: originalTime }); - - // Define the default amounts. - testAmounts = new uint128[](3); - testAmounts[0] = defaults.WITHDRAW_AMOUNT(); - testAmounts[1] = defaults.DEPOSIT_AMOUNT(); - testAmounts[2] = defaults.WITHDRAW_AMOUNT() / 2; - - // 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 - testStreamIds = new uint256[](3); - testStreamIds[0] = createDefaultStream(); - testStreamIds[1] = createDefaultStreamWithEndTime(earlyStopTime); - testStreamIds[2] = createDefaultStream(); - } - - /// @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 whenCallerAuthorizedAllStreams() { - caller = users.sender; - _; - - createTestStreams(); - caller = users.recipient; - _; - - createTestStreams(); - caller = users.operator; - _; - } -} diff --git a/test/core/invariant/Invariant.t.sol b/test/core/invariant/Invariant.t.sol index 36981f2d0..b5a849008 100644 --- a/test/core/invariant/Invariant.t.sol +++ b/test/core/invariant/Invariant.t.sol @@ -2,11 +2,22 @@ pragma solidity >=0.8.22 <0.9.0; import { StdInvariant } from "forge-std/src/StdInvariant.sol"; - +import { Lockup, LockupDynamic, LockupTranched } from "src/core/types/DataTypes.sol"; import { Base_Test } from "../../Base.t.sol"; +import { LockupCreateHandler } from "./handlers/LockupCreateHandler.sol"; +import { LockupHandler } from "./handlers/LockupHandler.sol"; +import { LockupStore } from "./stores/LockupStore.sol"; + +/// @notice Invariants of {SablierLockup} contract. +contract Invariant_Test is Base_Test, StdInvariant { + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + LockupHandler internal handler; + LockupStore internal lockupStore; + LockupCreateHandler internal createHandler; -/// @notice Common logic needed by all invariant tests. -abstract contract Invariant_Test is Base_Test, StdInvariant { /*////////////////////////////////////////////////////////////////////////// SET-UP FUNCTION //////////////////////////////////////////////////////////////////////////*/ @@ -14,8 +25,402 @@ abstract contract Invariant_Test is Base_Test, StdInvariant { function setUp() public virtual override { Base_Test.setUp(); - // Prevent these contracts from being fuzzed as `msg.sender`. - excludeSender(address(lockupDynamic)); - excludeSender(address(lockupLinear)); + // Deploy and label the lockup store contract. + lockupStore = new LockupStore(); + vm.label({ account: address(lockupStore), newLabel: "LockupStore" }); + + // Deploy the Lockup handlers. + createHandler = new LockupCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockup_: lockup }); + handler = new LockupHandler({ asset_: dai, lockupStore_: lockupStore, lockup_: lockup }); + + // Label the contracts. + vm.label({ account: address(createHandler), newLabel: "LockupCreateHandler" }); + vm.label({ account: address(handler), newLabel: "LockupHandler" }); + + // Target the LockupDynamic handlers for invariant testing. + targetContract(address(createHandler)); + targetContract(address(handler)); + + // Exclude the lockup store from being fuzzed as `msg.sender`. + excludeSender(address(createHandler)); + excludeSender(address(handler)); + excludeSender(address(lockup)); + excludeSender(address(lockupStore)); + } + + /*////////////////////////////////////////////////////////////////////////// + COMMON-INVARIANTS + //////////////////////////////////////////////////////////////////////////*/ + + // solhint-disable max-line-length + function invariant_ContractBalance() external view { + uint256 contractBalance = dai.balanceOf(address(lockup)); + + uint256 lastStreamId = lockupStore.lastStreamId(); + uint256 depositedAmountsSum; + uint256 refundedAmountsSum; + uint256 withdrawnAmountsSum; + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + depositedAmountsSum += uint256(lockup.getDepositedAmount(streamId)); + refundedAmountsSum += uint256(lockup.getRefundedAmount(streamId)); + withdrawnAmountsSum += uint256(lockup.getWithdrawnAmount(streamId)); + } + + assertGe( + contractBalance, + depositedAmountsSum - refundedAmountsSum - withdrawnAmountsSum, + unicode"Invariant violation: contract balances < Σ deposited amounts - Σ refunded amounts - Σ withdrawn amounts" + ); + } + + function invariant_DepositedAmountGteStreamedAmount() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGe( + lockup.getDepositedAmount(streamId), + lockup.streamedAmountOf(streamId), + "Invariant violation: deposited amount < streamed amount" + ); + } + } + + function invariant_DepositedAmountGteWithdrawableAmount() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGe( + lockup.getDepositedAmount(streamId), + lockup.withdrawableAmountOf(streamId), + "Invariant violation: deposited amount < withdrawable amount" + ); + } + } + + function invariant_DepositedAmountGteWithdrawnAmount() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGe( + lockup.getDepositedAmount(streamId), + lockup.getWithdrawnAmount(streamId), + "Invariant violation: deposited amount < withdrawn amount" + ); + } + } + + function invariant_DepositedAmountNotZero() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + uint128 depositAmount = lockup.getDepositedAmount(streamId); + assertNotEq(depositAmount, 0, "Invariant violated: stream non-null, deposited amount zero"); + } + } + + function invariant_EndTimeGtStartTime() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGt( + lockup.getEndTime(streamId), + lockup.getStartTime(streamId), + "Invariant violation: end time <= start time" + ); + } + } + + function invariant_NextStreamId() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 nextStreamId = lockup.nextStreamId(); + assertEq(nextStreamId, lastStreamId + 1, "Invariant violation: next stream ID not incremented"); + } + } + + function invariant_StartTimeNotZero() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + uint40 startTime = lockup.getStartTime(streamId); + assertGt(startTime, 0, "Invariant violated: start time zero"); + } + } + + function invariant_StatusCanceled() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.statusOf(streamId) == Lockup.Status.CANCELED) { + assertGt( + lockup.getRefundedAmount(streamId), + 0, + "Invariant violation: canceled stream with a zero refunded amount" + ); + assertFalse(lockup.isCancelable(streamId), "Invariant violation: canceled stream is cancelable"); + assertEq( + lockup.refundableAmountOf(streamId), + 0, + "Invariant violation: canceled stream with a non-zero refundable amount" + ); + assertGt( + lockup.withdrawableAmountOf(streamId), + 0, + "Invariant violation: canceled stream with a zero withdrawable amount" + ); + } + } + } + + function invariant_StatusDepleted() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.isDepleted(streamId)) { + assertEq( + lockup.getDepositedAmount(streamId) - lockup.getRefundedAmount(streamId), + lockup.getWithdrawnAmount(streamId), + "Invariant violation: depleted stream with deposited amount - refunded amount != withdrawn amount" + ); + assertFalse(lockup.isCancelable(streamId), "Invariant violation: depleted stream is cancelable"); + assertEq( + lockup.refundableAmountOf(streamId), + 0, + "Invariant violation: depleted stream with a non-zero refundable amount" + ); + assertEq( + lockup.withdrawableAmountOf(streamId), + 0, + "Invariant violation: depleted stream with a non-zero withdrawable amount" + ); + } + } + } + + function invariant_StatusPending() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.statusOf(streamId) == Lockup.Status.PENDING) { + assertEq( + lockup.getRefundedAmount(streamId), + 0, + "Invariant violation: pending stream with a non-zero refunded amount" + ); + assertEq( + lockup.getWithdrawnAmount(streamId), + 0, + "Invariant violation: pending stream with a non-zero withdrawn amount" + ); + assertEq( + lockup.refundableAmountOf(streamId), + lockup.getDepositedAmount(streamId), + "Invariant violation: pending stream with refundable amount != deposited amount" + ); + assertEq( + lockup.streamedAmountOf(streamId), + 0, + "Invariant violation: pending stream with a non-zero streamed amount" + ); + assertEq( + lockup.withdrawableAmountOf(streamId), + 0, + "Invariant violation: pending stream with a non-zero withdrawable amount" + ); + } + } + } + + function invariant_StatusSettled() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.statusOf(streamId) == Lockup.Status.SETTLED) { + assertEq( + lockup.getRefundedAmount(streamId), + 0, + "Invariant violation: settled stream with a non-zero refunded amount" + ); + assertFalse(lockup.isCancelable(streamId), "Invariant violation: settled stream is cancelable"); + assertEq( + lockup.refundableAmountOf(streamId), + 0, + "Invariant violation: settled stream with a non-zero refundable amount" + ); + assertEq( + lockup.streamedAmountOf(streamId), + lockup.getDepositedAmount(streamId), + "Invariant violation: settled stream with streamed amount != deposited amount" + ); + } + } + } + + function invariant_StatusStreaming() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.statusOf(streamId) == Lockup.Status.STREAMING) { + assertEq( + lockup.getRefundedAmount(streamId), + 0, + "Invariant violation: streaming stream with a non-zero refunded amount" + ); + assertLt( + lockup.streamedAmountOf(streamId), + lockup.getDepositedAmount(streamId), + "Invariant violation: streaming stream with streamed amount >= deposited amount" + ); + } + } + } + + /// @dev See diagram at https://docs.sablier.com/concepts/protocol/statuses#diagram + function invariant_StatusTransitions() external { + uint256 lastStreamId = lockupStore.lastStreamId(); + if (lastStreamId == 0) { + return; + } + + for (uint256 i = 0; i < lastStreamId - 1; ++i) { + uint256 streamId = lockupStore.streamIds(i); + Lockup.Status currentStatus = lockup.statusOf(streamId); + + // If this is the first time the status is checked for this stream, skip the invariant test. + if (!lockupStore.isPreviousStatusRecorded(streamId)) { + lockupStore.updateIsPreviousStatusRecorded(streamId); + return; + } + + // Check the status transition invariants. + Lockup.Status previousStatus = lockupStore.previousStatusOf(streamId); + if (previousStatus == Lockup.Status.PENDING) { + assertNotEq( + currentStatus, Lockup.Status.DEPLETED, "Invariant violation: pending stream turned depleted" + ); + } else if (previousStatus == Lockup.Status.STREAMING) { + assertNotEq( + currentStatus, Lockup.Status.PENDING, "Invariant violation: streaming stream turned pending" + ); + } else if (previousStatus == Lockup.Status.SETTLED) { + assertNotEq(currentStatus, Lockup.Status.PENDING, "Invariant violation: settled stream turned pending"); + assertNotEq( + currentStatus, Lockup.Status.STREAMING, "Invariant violation: settled stream turned streaming" + ); + assertNotEq( + currentStatus, Lockup.Status.CANCELED, "Invariant violation: settled stream turned canceled" + ); + } else if (previousStatus == Lockup.Status.CANCELED) { + assertNotEq(currentStatus, Lockup.Status.PENDING, "Invariant violation: canceled stream turned pending"); + assertNotEq( + currentStatus, Lockup.Status.STREAMING, "Invariant violation: canceled stream turned streaming" + ); + assertNotEq(currentStatus, Lockup.Status.SETTLED, "Invariant violation: canceled stream turned settled"); + } else if (previousStatus == Lockup.Status.DEPLETED) { + assertEq(currentStatus, Lockup.Status.DEPLETED, "Invariant violation: depleted status changed"); + } + + // Set the current status as the previous status. + lockupStore.updatePreviousStatusOf(streamId, currentStatus); + } + } + + function invariant_StreamedAmountGteWithdrawableAmount() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGe( + lockup.streamedAmountOf(streamId), + lockup.withdrawableAmountOf(streamId), + "Invariant violation: streamed amount < withdrawable amount" + ); + } + } + + function invariant_StreamedAmountGteWithdrawnAmount() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + assertGe( + lockup.streamedAmountOf(streamId), + lockup.getWithdrawnAmount(streamId), + "Invariant violation: streamed amount < withdrawn amount" + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + INVARIANTS-DYNAMIC-MODEL + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Unordered segment timestamps are not allowed. + function invariant_SegmentTimestampsOrdered() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.getLockupModel(streamId) == Lockup.Model.LOCKUP_DYNAMIC) { + LockupDynamic.Segment[] memory segments = lockup.getSegments(streamId); + uint40 previousTimestamp = segments[0].timestamp; + for (uint256 j = 1; j < segments.length; ++j) { + assertGt( + segments[j].timestamp, previousTimestamp, "Invariant violated: segment timestamps not ordered" + ); + previousTimestamp = segments[j].timestamp; + } + } + } + } + + /*////////////////////////////////////////////////////////////////////////// + INVARIANTS-LINEAR-MODEL + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev If it is not zero, the cliff time must be strictly greater than the start time. + function invariant_CliffTimeGtStartTimeOrZero() external view { + 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" + ); + } + } + } + + /// @dev The end time must not be less than or equal to the cliff time. + function invariant_EndTimeGtCliffTime() external view { + 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" + ); + } + } + + /*////////////////////////////////////////////////////////////////////////// + INVARIANTS-TRANCHED-MODEL + //////////////////////////////////////////////////////////////////////////*/ + + /// @dev Unordered tranche timestamps are not allowed. + function invariant_TrancheTimestampsOrdered() external view { + uint256 lastStreamId = lockupStore.lastStreamId(); + for (uint256 i = 0; i < lastStreamId; ++i) { + uint256 streamId = lockupStore.streamIds(i); + if (lockup.getLockupModel(streamId) == Lockup.Model.LOCKUP_TRANCHED) { + LockupTranched.Tranche[] memory tranches = lockup.getTranches(streamId); + uint40 previousTimestamp = tranches[0].timestamp; + for (uint256 j = 1; j < tranches.length; ++j) { + assertGt( + tranches[j].timestamp, previousTimestamp, "Invariant violated: tranche timestamps not ordered" + ); + previousTimestamp = tranches[j].timestamp; + } + } + } } } diff --git a/test/core/invariant/Lockup.t.sol b/test/core/invariant/Lockup.t.sol deleted file mode 100644 index 3d1701cdf..000000000 --- a/test/core/invariant/Lockup.t.sol +++ /dev/null @@ -1,336 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; -import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupHandler } from "./handlers/LockupHandler.sol"; -import { Invariant_Test } from "./Invariant.t.sol"; -import { LockupStore } from "./stores/LockupStore.sol"; - -/// @notice Common invariant test logic needed across contracts that inherit from {SablierLockup}. -abstract contract Lockup_Invariant_Test is Invariant_Test { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierLockup internal lockup; - LockupHandler internal lockupHandler; - LockupStore internal lockupStore; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Invariant_Test.setUp(); - - // Deploy and label the lockup store contract. - lockupStore = new LockupStore(); - vm.label({ account: address(lockupStore), newLabel: "LockupStore" }); - - // Exclude the lockup store from being fuzzed as `msg.sender`. - excludeSender(address(lockupStore)); - } - - /*////////////////////////////////////////////////////////////////////////// - INVARIANTS - //////////////////////////////////////////////////////////////////////////*/ - - // solhint-disable max-line-length - function invariant_ContractBalance() external view { - uint256 contractBalance = dai.balanceOf(address(lockup)); - - uint256 lastStreamId = lockupStore.lastStreamId(); - uint256 depositedAmountsSum; - uint256 refundedAmountsSum; - uint256 withdrawnAmountsSum; - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - depositedAmountsSum += uint256(lockup.getDepositedAmount(streamId)); - refundedAmountsSum += uint256(lockup.getRefundedAmount(streamId)); - withdrawnAmountsSum += uint256(lockup.getWithdrawnAmount(streamId)); - } - - assertGe( - contractBalance, - depositedAmountsSum - refundedAmountsSum - withdrawnAmountsSum, - unicode"Invariant violation: contract balances < Σ deposited amounts - Σ refunded amounts - Σ withdrawn amounts" - ); - } - - function invariant_DepositedAmountGteStreamedAmount() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGe( - lockup.getDepositedAmount(streamId), - lockup.streamedAmountOf(streamId), - "Invariant violation: deposited amount < streamed amount" - ); - } - } - - function invariant_DepositedAmountGteWithdrawableAmount() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGe( - lockup.getDepositedAmount(streamId), - lockup.withdrawableAmountOf(streamId), - "Invariant violation: deposited amount < withdrawable amount" - ); - } - } - - function invariant_DepositedAmountGteWithdrawnAmount() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGe( - lockup.getDepositedAmount(streamId), - lockup.getWithdrawnAmount(streamId), - "Invariant violation: deposited amount < withdrawn amount" - ); - } - } - - function invariant_DepositedAmountNotZero() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - uint128 depositAmount = lockup.getDepositedAmount(streamId); - assertNotEq(depositAmount, 0, "Invariant violated: stream non-null, deposited amount zero"); - } - } - - function invariant_EndTimeGtStartTime() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGt( - lockup.getEndTime(streamId), - lockup.getStartTime(streamId), - "Invariant violation: end time <= start time" - ); - } - } - - function invariant_NextStreamId() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 nextStreamId = lockup.nextStreamId(); - assertEq(nextStreamId, lastStreamId + 1, "Invariant violation: next stream ID not incremented"); - } - } - - function invariant_StartTimeNotZero() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - uint40 startTime = lockup.getStartTime(streamId); - assertGt(startTime, 0, "Invariant violated: start time zero"); - } - } - - function invariant_StatusCanceled() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockup.statusOf(streamId) == Lockup.Status.CANCELED) { - assertGt( - lockup.getRefundedAmount(streamId), - 0, - "Invariant violation: canceled stream with a zero refunded amount" - ); - assertFalse(lockup.isCancelable(streamId), "Invariant violation: canceled stream is cancelable"); - assertEq( - lockup.refundableAmountOf(streamId), - 0, - "Invariant violation: canceled stream with a non-zero refundable amount" - ); - assertGt( - lockup.withdrawableAmountOf(streamId), - 0, - "Invariant violation: canceled stream with a zero withdrawable amount" - ); - } - } - } - - function invariant_StatusDepleted() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockup.isDepleted(streamId)) { - assertEq( - lockup.getDepositedAmount(streamId) - lockup.getRefundedAmount(streamId), - lockup.getWithdrawnAmount(streamId), - "Invariant violation: depleted stream with deposited amount - refunded amount != withdrawn amount" - ); - assertFalse(lockup.isCancelable(streamId), "Invariant violation: depleted stream is cancelable"); - assertEq( - lockup.refundableAmountOf(streamId), - 0, - "Invariant violation: depleted stream with a non-zero refundable amount" - ); - assertEq( - lockup.withdrawableAmountOf(streamId), - 0, - "Invariant violation: depleted stream with a non-zero withdrawable amount" - ); - } - } - } - - function invariant_StatusPending() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockup.statusOf(streamId) == Lockup.Status.PENDING) { - assertEq( - lockup.getRefundedAmount(streamId), - 0, - "Invariant violation: pending stream with a non-zero refunded amount" - ); - assertEq( - lockup.getWithdrawnAmount(streamId), - 0, - "Invariant violation: pending stream with a non-zero withdrawn amount" - ); - assertEq( - lockup.refundableAmountOf(streamId), - lockup.getDepositedAmount(streamId), - "Invariant violation: pending stream with refundable amount != deposited amount" - ); - assertEq( - lockup.streamedAmountOf(streamId), - 0, - "Invariant violation: pending stream with a non-zero streamed amount" - ); - assertEq( - lockup.withdrawableAmountOf(streamId), - 0, - "Invariant violation: pending stream with a non-zero withdrawable amount" - ); - } - } - } - - function invariant_StatusSettled() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockup.statusOf(streamId) == Lockup.Status.SETTLED) { - assertEq( - lockup.getRefundedAmount(streamId), - 0, - "Invariant violation: settled stream with a non-zero refunded amount" - ); - assertFalse(lockup.isCancelable(streamId), "Invariant violation: settled stream is cancelable"); - assertEq( - lockup.refundableAmountOf(streamId), - 0, - "Invariant violation: settled stream with a non-zero refundable amount" - ); - assertEq( - lockup.streamedAmountOf(streamId), - lockup.getDepositedAmount(streamId), - "Invariant violation: settled stream with streamed amount != deposited amount" - ); - } - } - } - - function invariant_StatusStreaming() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockup.statusOf(streamId) == Lockup.Status.STREAMING) { - assertEq( - lockup.getRefundedAmount(streamId), - 0, - "Invariant violation: streaming stream with a non-zero refunded amount" - ); - assertLt( - lockup.streamedAmountOf(streamId), - lockup.getDepositedAmount(streamId), - "Invariant violation: streaming stream with streamed amount >= deposited amount" - ); - } - } - } - - /// @dev See diagram at https://docs.sablier.com/concepts/protocol/statuses#diagram - function invariant_StatusTransitions() external { - uint256 lastStreamId = lockupStore.lastStreamId(); - if (lastStreamId == 0) { - return; - } - - for (uint256 i = 0; i < lastStreamId - 1; ++i) { - uint256 streamId = lockupStore.streamIds(i); - Lockup.Status currentStatus = lockup.statusOf(streamId); - - // If this is the first time the status is checked for this stream, skip the invariant test. - if (!lockupStore.isPreviousStatusRecorded(streamId)) { - lockupStore.updateIsPreviousStatusRecorded(streamId); - return; - } - - // Check the status transition invariants. - Lockup.Status previousStatus = lockupStore.previousStatusOf(streamId); - if (previousStatus == Lockup.Status.PENDING) { - assertNotEq( - currentStatus, Lockup.Status.DEPLETED, "Invariant violation: pending stream turned depleted" - ); - } else if (previousStatus == Lockup.Status.STREAMING) { - assertNotEq( - currentStatus, Lockup.Status.PENDING, "Invariant violation: streaming stream turned pending" - ); - } else if (previousStatus == Lockup.Status.SETTLED) { - assertNotEq(currentStatus, Lockup.Status.PENDING, "Invariant violation: settled stream turned pending"); - assertNotEq( - currentStatus, Lockup.Status.STREAMING, "Invariant violation: settled stream turned streaming" - ); - assertNotEq( - currentStatus, Lockup.Status.CANCELED, "Invariant violation: settled stream turned canceled" - ); - } else if (previousStatus == Lockup.Status.CANCELED) { - assertNotEq(currentStatus, Lockup.Status.PENDING, "Invariant violation: canceled stream turned pending"); - assertNotEq( - currentStatus, Lockup.Status.STREAMING, "Invariant violation: canceled stream turned streaming" - ); - assertNotEq(currentStatus, Lockup.Status.SETTLED, "Invariant violation: canceled stream turned settled"); - } else if (previousStatus == Lockup.Status.DEPLETED) { - assertEq(currentStatus, Lockup.Status.DEPLETED, "Invariant violation: depleted status changed"); - } - - // Set the current status as the previous status. - lockupStore.updatePreviousStatusOf(streamId, currentStatus); - } - } - - function invariant_StreamedAmountGteWithdrawableAmount() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGe( - lockup.streamedAmountOf(streamId), - lockup.withdrawableAmountOf(streamId), - "Invariant violation: streamed amount < withdrawable amount" - ); - } - } - - function invariant_StreamedAmountGteWithdrawnAmount() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGe( - lockup.streamedAmountOf(streamId), - lockup.getWithdrawnAmount(streamId), - "Invariant violation: streamed amount < withdrawn amount" - ); - } - } -} diff --git a/test/core/invariant/LockupDynamic.t.sol b/test/core/invariant/LockupDynamic.t.sol deleted file mode 100644 index efcd0a517..000000000 --- a/test/core/invariant/LockupDynamic.t.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; -import { LockupDynamicCreateHandler } from "./handlers/LockupDynamicCreateHandler.sol"; -import { LockupDynamicHandler } from "./handlers/LockupDynamicHandler.sol"; -import { Lockup_Invariant_Test } from "./Lockup.t.sol"; - -/// @dev Invariant tests for {SablierLockupDynamic}. -contract LockupDynamic_Invariant_Test is Lockup_Invariant_Test { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - LockupDynamicHandler internal dynamicHandler; - LockupDynamicCreateHandler internal dynamicCreateHandler; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Lockup_Invariant_Test.setUp(); - - // Deploy the LockupDynamic handlers. - dynamicHandler = - new LockupDynamicHandler({ asset_: dai, lockupStore_: lockupStore, lockupDynamic_: lockupDynamic }); - dynamicCreateHandler = - new LockupDynamicCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupDynamic_: lockupDynamic }); - - // Label the contracts. - vm.label({ account: address(dynamicHandler), newLabel: "LockupDynamicHandler" }); - vm.label({ account: address(dynamicCreateHandler), newLabel: "LockupDynamicCreateHandler" }); - - // Cast the LockupDynamic contract and handler. - lockup = lockupDynamic; - lockupHandler = dynamicHandler; - - // Target the LockupDynamic handlers for invariant testing. - targetContract(address(dynamicHandler)); - targetContract(address(dynamicCreateHandler)); - - // Prevent these contracts from being fuzzed as `msg.sender`. - excludeSender(address(dynamicHandler)); - excludeSender(address(dynamicCreateHandler)); - } - - /*////////////////////////////////////////////////////////////////////////// - INVARIANTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Unordered segment timestamps are not allowed. - function invariant_SegmentTimestampsOrdered() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupDynamic.Segment[] memory segments = lockupDynamic.getSegments(streamId); - uint40 previousTimestamp = segments[0].timestamp; - for (uint256 j = 1; j < segments.length; ++j) { - assertGt(segments[j].timestamp, previousTimestamp, "Invariant violated: segment timestamps not ordered"); - previousTimestamp = segments[j].timestamp; - } - } - } - - /// @dev Settled streams must not appear as cancelable in {SablierLockupDynamic.getStream}. - function invariant_StatusSettled_GetStream() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockupDynamic.statusOf(streamId) == Lockup.Status.SETTLED) { - assertFalse( - lockupDynamic.getStream(streamId).isCancelable, - "Invariant violation: stream returned by getStream() is cancelable" - ); - } - } - } -} diff --git a/test/core/invariant/LockupLinear.t.sol b/test/core/invariant/LockupLinear.t.sol deleted file mode 100644 index 9673d643a..000000000 --- a/test/core/invariant/LockupLinear.t.sol +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup } from "src/core/types/DataTypes.sol"; -import { LockupLinearCreateHandler } from "./handlers/LockupLinearCreateHandler.sol"; -import { LockupLinearHandler } from "./handlers/LockupLinearHandler.sol"; -import { Lockup_Invariant_Test } from "./Lockup.t.sol"; - -/// @dev Invariant tests for {SablierLockupLinear}. -contract LockupLinear_Invariant_Test is Lockup_Invariant_Test { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - LockupLinearHandler internal lockupLinearHandler; - LockupLinearCreateHandler internal lockupLinearCreateHandler; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Lockup_Invariant_Test.setUp(); - - // Deploy the lockupLinear contract handlers. - lockupLinearHandler = - new LockupLinearHandler({ asset_: dai, lockupStore_: lockupStore, lockupLinear_: lockupLinear }); - lockupLinearCreateHandler = - new LockupLinearCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupLinear_: lockupLinear }); - - // Label the handler contracts. - vm.label({ account: address(lockupLinearHandler), newLabel: "LockupLinearHandler" }); - vm.label({ account: address(lockupLinearCreateHandler), newLabel: "LockupLinearCreateHandler" }); - - // Cast the lockupLinear contract as {ISablierLockup} and the lockupLinear handler as {LockupHandler}. - lockup = lockupLinear; - lockupHandler = lockupLinearHandler; - - // Target the lockupLinear handlers for invariant testing. - targetContract(address(lockupLinearHandler)); - targetContract(address(lockupLinearCreateHandler)); - - // Prevent these contracts from being fuzzed as `msg.sender`. - excludeSender(address(lockupLinearHandler)); - excludeSender(address(lockupLinearCreateHandler)); - } - - /*////////////////////////////////////////////////////////////////////////// - INVARIANTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev If it is not zero, the cliff time must be strictly greater than the start time. - function invariant_CliffTimeGtStartTimeOrZero() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockupLinear.getCliffTime(streamId) > 0) { - assertGt( - lockupLinear.getCliffTime(streamId), - lockupLinear.getStartTime(streamId), - "Invariant violated: cliff time <= start time" - ); - } - } - } - - /// @dev The end time must not be less than or equal to the cliff time. - function invariant_EndTimeGtCliffTime() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - assertGt( - lockupLinear.getEndTime(streamId), - lockupLinear.getCliffTime(streamId), - "Invariant violated: end time <= cliff time" - ); - } - } - - /// @dev Settled streams must not appear as cancelable in {SablierLockupLinear.getStream}. - function invariant_StatusSettled_GetStream() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockupLinear.statusOf(streamId) == Lockup.Status.SETTLED) { - assertFalse( - lockupLinear.getStream(streamId).isCancelable, - "Invariant violation: stream returned by getStream() is cancelable" - ); - } - } - } -} diff --git a/test/core/invariant/LockupTranched.t.sol b/test/core/invariant/LockupTranched.t.sol deleted file mode 100644 index f0f75649b..000000000 --- a/test/core/invariant/LockupTranched.t.sol +++ /dev/null @@ -1,79 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; -import { LockupTranchedCreateHandler } from "./handlers/LockupTranchedCreateHandler.sol"; -import { LockupTranchedHandler } from "./handlers/LockupTranchedHandler.sol"; -import { Lockup_Invariant_Test } from "./Lockup.t.sol"; - -/// @dev Invariant tests for {SablierLockupTranched}. -contract LockupTranched_Invariant_Test is Lockup_Invariant_Test { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - LockupTranchedHandler internal tranchedHandler; - LockupTranchedCreateHandler internal tranchedCreateHandler; - - /*////////////////////////////////////////////////////////////////////////// - SET-UP FUNCTION - //////////////////////////////////////////////////////////////////////////*/ - - function setUp() public virtual override { - Lockup_Invariant_Test.setUp(); - - // Deploy the LockupTranched handlers. - tranchedHandler = - new LockupTranchedHandler({ asset_: dai, lockupStore_: lockupStore, lockupTranched_: lockupTranched }); - tranchedCreateHandler = - new LockupTranchedCreateHandler({ asset_: dai, lockupStore_: lockupStore, lockupTranched_: lockupTranched }); - - // Label the contracts. - vm.label({ account: address(tranchedHandler), newLabel: "LockupTranchedHandler" }); - vm.label({ account: address(tranchedCreateHandler), newLabel: "LockupTranchedCreateHandler" }); - - // Cast the LockupTranched contract and handler. - lockup = lockupTranched; - lockupHandler = tranchedHandler; - - // Target the LockupTranched handlers for invariant testing. - targetContract(address(tranchedHandler)); - targetContract(address(tranchedCreateHandler)); - - // Prevent these contracts from being fuzzed as `msg.sender`. - excludeSender(address(tranchedHandler)); - excludeSender(address(tranchedCreateHandler)); - } - - /*////////////////////////////////////////////////////////////////////////// - INVARIANTS - //////////////////////////////////////////////////////////////////////////*/ - - /// @dev Settled streams must not appear as cancelable in {SablierLockupTranched.getStream}. - function invariant_StatusSettled_GetStream() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - if (lockupTranched.statusOf(streamId) == Lockup.Status.SETTLED) { - assertFalse( - lockupTranched.getStream(streamId).isCancelable, - "Invariant violation: stream returned by getStream() is cancelable" - ); - } - } - } - - /// @dev Unordered tranche timestamps are not allowed. - function invariant_TrancheTimestampsOrdered() external view { - uint256 lastStreamId = lockupStore.lastStreamId(); - for (uint256 i = 0; i < lastStreamId; ++i) { - uint256 streamId = lockupStore.streamIds(i); - LockupTranched.Tranche[] memory tranches = lockupTranched.getTranches(streamId); - uint40 previousTimestamp = tranches[0].timestamp; - for (uint256 j = 1; j < tranches.length; ++j) { - assertGt(tranches[j].timestamp, previousTimestamp, "Invariant violated: tranche timestamps not ordered"); - previousTimestamp = tranches[j].timestamp; - } - } - } -} diff --git a/test/core/invariant/handlers/BaseHandler.sol b/test/core/invariant/handlers/BaseHandler.sol index 2ed863920..bc5c46bd6 100644 --- a/test/core/invariant/handlers/BaseHandler.sol +++ b/test/core/invariant/handlers/BaseHandler.sol @@ -3,11 +3,12 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { StdCheats } from "forge-std/src/StdCheats.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { Constants } from "../../../utils/Constants.sol"; import { Fuzzers } from "../../../utils/Fuzzers.sol"; -/// @notice Base contract with common logic needed by all handler contracts. +/// @notice Base contract with common logic needed by {LockupHandler} and {LockupCreateHandler} contracts. abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /*////////////////////////////////////////////////////////////////////////// STATE-VARIABLES @@ -22,6 +23,8 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { /// @dev The total number of calls made to this contract. uint256 public totalCalls; + ISablierLockup public lockup; + /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ @@ -33,8 +36,9 @@ abstract contract BaseHandler is Constants, Fuzzers, StdCheats { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_) { + constructor(IERC20 asset_, ISablierLockup lockup_) { asset = asset_; + lockup = lockup_; } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/core/invariant/handlers/LockupCreateHandler.sol b/test/core/invariant/handlers/LockupCreateHandler.sol new file mode 100644 index 000000000..2edf4ea31 --- /dev/null +++ b/test/core/invariant/handlers/LockupCreateHandler.sol @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; + +import { LockupStore } from "../stores/LockupStore.sol"; +import { BaseHandler } from "./BaseHandler.sol"; + +/// @dev This contract is a complement of {LockupHandler}. +contract LockupCreateHandler is BaseHandler { + /*////////////////////////////////////////////////////////////////////////// + TEST CONTRACTS + //////////////////////////////////////////////////////////////////////////*/ + + LockupStore public lockupStore; + + /*////////////////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////////////////*/ + + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_, lockup_) { + lockupStore = lockupStore_; + } + + /*////////////////////////////////////////////////////////////////////////// + HANDLER FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function createWithDurationsLD( + uint256 timeJumpSeed, + Lockup.CreateWithDurations memory params, + LockupDynamic.SegmentWithDuration[] memory segments + ) + public + instrument("createWithDurationsLD") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); + + // The protocol doesn't allow empty segment arrays. + vm.assume(segments.length != 0); + + // Bound the broker fee. + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + + // Fuzz the durations. + fuzzSegmentDurations(segments); + + // Fuzz the segment amounts and calculate the total amount. + (params.totalAmount,) = + fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: segments, brokerFee: params.broker.fee }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockup.createWithDurationsLD(params, segments); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithDurationsLL( + uint256 timeJumpSeed, + Lockup.CreateWithDurations memory params, + LockupLinear.Durations memory durations + ) + public + instrument("createWithDurations") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); + + // Bound the stream parameters. + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + durations.cliff = boundUint40(durations.cliff, 1 seconds, 2500 seconds); + durations.total = boundUint40(durations.total, durations.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); + params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockup.createWithDurationsLL(params, durations); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithDurationsLT( + uint256 timeJumpSeed, + Lockup.CreateWithDurations memory params, + LockupTranched.TrancheWithDuration[] memory tranches + ) + public + instrument("createWithDurations") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); + + // The protocol doesn't allow empty tranche arrays. + vm.assume(tranches.length != 0); + + // Bound the broker fee. + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + + // Fuzz the durations. + fuzzTrancheDurations(tranches); + + // Fuzz the tranche amounts and calculate the total amount. + (params.totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: 1_000_000_000e18, + tranches: tranches, + brokerFee: params.broker.fee + }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockup.createWithDurationsLT(params, tranches); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithTimestampsLD( + uint256 timeJumpSeed, + Lockup.CreateWithTimestamps memory params, + LockupDynamic.Segment[] memory segments + ) + public + instrument("createWithTimestamps") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); + + // The protocol doesn't allow empty segment arrays. + vm.assume(segments.length != 0); + + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); + + // Fuzz the segment timestamps. + fuzzSegmentTimestamps(segments, params.startTime); + + // Fuzz the segment amounts and calculate the total amount. + (params.totalAmount,) = + fuzzDynamicStreamAmounts({ upperBound: 1_000_000_000e18, segments: segments, brokerFee: params.broker.fee }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + params.endTime = segments[segments.length - 1].timestamp; + uint256 streamId = lockup.createWithTimestampsLD(params, segments); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithTimestampsLL( + uint256 timeJumpSeed, + Lockup.CreateWithTimestamps memory params, + uint40 cliff + ) + public + instrument("createWithTimestamps") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + 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.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); + } + + // 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); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + uint256 streamId = lockup.createWithTimestampsLL(params, cliff); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } + + function createWithTimestampsLT( + uint256 timeJumpSeed, + Lockup.CreateWithTimestamps memory params, + LockupTranched.Tranche[] memory tranches + ) + public + instrument("createWithTimestamps") + adjustTimestamp(timeJumpSeed) + checkUsers(params.sender, params.recipient, params.broker.account) + useNewSender(params.sender) + { + // We don't want to create more than a certain number of streams. + vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); + + // The protocol doesn't allow empty tranche arrays. + vm.assume(tranches.length != 0); + + params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); + params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); + + // Fuzz the tranche timestamps. + fuzzTrancheTimestamps(tranches, params.startTime); + + // Fuzz the tranche amounts and calculate the total amount. + (params.totalAmount,) = fuzzTranchedStreamAmounts({ + upperBound: 1_000_000_000e18, + tranches: tranches, + brokerFee: params.broker.fee + }); + + // Mint enough assets to the Sender. + deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); + + // Approve {SablierLockup} to spend the assets. + asset.approve({ spender: address(lockup), value: params.totalAmount }); + + // Create the stream. + params.asset = asset; + params.endTime = tranches[tranches.length - 1].timestamp; + uint256 streamId = lockup.createWithTimestampsLT(params, tranches); + + // Store the stream ID. + lockupStore.pushStreamId(streamId, params.sender, params.recipient); + } +} diff --git a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol b/test/core/invariant/handlers/LockupDynamicCreateHandler.sol deleted file mode 100644 index bb13df540..000000000 --- a/test/core/invariant/handlers/LockupDynamicCreateHandler.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { LockupDynamic } from "src/core/types/DataTypes.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { BaseHandler } from "./BaseHandler.sol"; - -/// @dev This contract is a complement of {LockupDynamicHandler}. The goal is to bias the invariant calls toward the -/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. -contract LockupDynamicCreateHandler is BaseHandler { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierLockupDynamic public lockupDynamic; - LockupStore public lockupStore; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupDynamic lockupDynamic_) BaseHandler(asset_) { - lockupStore = lockupStore_; - lockupDynamic = lockupDynamic_; - } - - /*////////////////////////////////////////////////////////////////////////// - HANDLER FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - function createWithDurations( - uint256 timeJumpSeed, - LockupDynamic.CreateWithDurations memory params - ) - public - instrument("createWithDurations") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - // The protocol doesn't allow empty segment arrays. - vm.assume(params.segments.length != 0); - - // Bound the broker fee. - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - - // Fuzz the durations. - fuzzSegmentDurations(params.segments); - - // Fuzz the segment amounts and calculate the total amount. - (params.totalAmount,) = fuzzDynamicStreamAmounts({ - upperBound: 1_000_000_000e18, - segments: params.segments, - brokerFee: params.broker.fee - }); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupDynamic} to spend the assets. - asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupDynamic.createWithDurations(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } - - function createWithTimestamps( - uint256 timeJumpSeed, - LockupDynamic.CreateWithTimestamps memory params - ) - public - instrument("createWithTimestamps") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - // The protocol doesn't allow empty segment arrays. - vm.assume(params.segments.length != 0); - - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); - - // Fuzz the segment timestamps. - fuzzSegmentTimestamps(params.segments, params.startTime); - - // Fuzz the segment amounts and calculate the total amount. - (params.totalAmount,) = fuzzDynamicStreamAmounts({ - upperBound: 1_000_000_000e18, - segments: params.segments, - brokerFee: params.broker.fee - }); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupDynamic} to spend the assets. - asset.approve({ spender: address(lockupDynamic), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupDynamic.createWithTimestamps(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } -} diff --git a/test/core/invariant/handlers/LockupDynamicHandler.sol b/test/core/invariant/handlers/LockupDynamicHandler.sol deleted file mode 100644 index 0e9a2b9fc..000000000 --- a/test/core/invariant/handlers/LockupDynamicHandler.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { LockupHandler } from "./LockupHandler.sol"; - -/// @dev This contract and not {SablierLockupDynamic} is exposed to Foundry for invariant testing. The goal is -/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. -contract LockupDynamicHandler is LockupHandler { - constructor( - IERC20 asset_, - LockupStore lockupStore_, - ISablierLockupDynamic lockupDynamic_ - ) - LockupHandler(asset_, lockupStore_, lockupDynamic_) - { } -} diff --git a/test/core/invariant/handlers/LockupHandler.sol b/test/core/invariant/handlers/LockupHandler.sol index 5df991f2c..d648fb6a7 100644 --- a/test/core/invariant/handlers/LockupHandler.sol +++ b/test/core/invariant/handlers/LockupHandler.sol @@ -9,13 +9,11 @@ import { Lockup } from "src/core/types/DataTypes.sol"; import { LockupStore } from "../stores/LockupStore.sol"; import { BaseHandler } from "./BaseHandler.sol"; -/// @dev Common handler logic between {LockupLinearHandler} and {LockupDynamicHandler}. -abstract contract LockupHandler is BaseHandler { +contract LockupHandler is BaseHandler { /*////////////////////////////////////////////////////////////////////////// TEST CONTRACTS //////////////////////////////////////////////////////////////////////////*/ - ISablierLockup public lockup; LockupStore public lockupStore; /*////////////////////////////////////////////////////////////////////////// @@ -30,9 +28,8 @@ abstract contract LockupHandler is BaseHandler { CONSTRUCTOR //////////////////////////////////////////////////////////////////////////*/ - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_) { + constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockup lockup_) BaseHandler(asset_, lockup_) { lockupStore = lockupStore_; - lockup = lockup_; } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/core/invariant/handlers/LockupLinearCreateHandler.sol b/test/core/invariant/handlers/LockupLinearCreateHandler.sol deleted file mode 100644 index 6d233e1bf..000000000 --- a/test/core/invariant/handlers/LockupLinearCreateHandler.sol +++ /dev/null @@ -1,111 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { LockupLinear } from "src/core/types/DataTypes.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { BaseHandler } from "./BaseHandler.sol"; - -/// @dev This contract is a complement of {LockupLinearHandler}. The goal is to bias the invariant calls toward the -/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. -contract LockupLinearCreateHandler is BaseHandler { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - ISablierLockupLinear public lockupLinear; - LockupStore public lockupStore; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupLinear lockupLinear_) BaseHandler(asset_) { - lockupStore = lockupStore_; - lockupLinear = lockupLinear_; - } - - /*////////////////////////////////////////////////////////////////////////// - HANDLER FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - function createWithDurations( - uint256 timeJumpSeed, - LockupLinear.CreateWithDurations memory params - ) - public - instrument("createWithDurations") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - // Bound the stream parameters. - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.durations.cliff = boundUint40(params.durations.cliff, 1 seconds, 2500 seconds); - params.durations.total = - boundUint40(params.durations.total, params.durations.cliff + 1 seconds, MAX_UNIX_TIMESTAMP); - params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupLinear} to spend the assets. - asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupLinear.createWithDurations(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } - - function createWithTimestamps( - uint256 timeJumpSeed, - LockupLinear.CreateWithTimestamps memory params - ) - public - instrument("createWithTimestamps") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - uint40 blockTimestamp = getBlockTimestamp(); - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.timestamps.start = boundUint40(params.timestamps.start, 1 seconds, blockTimestamp); - params.totalAmount = boundUint128(params.totalAmount, 1, 1_000_000_000e18); - - // The cliff time must be either zero or greater than the start time. - if (params.timestamps.cliff > 0) { - params.timestamps.cliff = boundUint40( - params.timestamps.cliff, params.timestamps.start + 1 seconds, params.timestamps.start + 52 weeks - ); - } - - // Bound the end time so that it is always greater than the start time, and the cliff time. - uint40 endTimeLowerBound = maxOfTwo(params.timestamps.start, params.timestamps.cliff); - params.timestamps.end = boundUint40(params.timestamps.end, endTimeLowerBound + 1 seconds, MAX_UNIX_TIMESTAMP); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupLinear} to spend the assets. - asset.approve({ spender: address(lockupLinear), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupLinear.createWithTimestamps(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } -} diff --git a/test/core/invariant/handlers/LockupLinearHandler.sol b/test/core/invariant/handlers/LockupLinearHandler.sol deleted file mode 100644 index 075effb8c..000000000 --- a/test/core/invariant/handlers/LockupLinearHandler.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { LockupHandler } from "./LockupHandler.sol"; - -/// @dev This contract and not {SablierLockupLinear} is exposed to Foundry for invariant testing. The goal is -/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. -contract LockupLinearHandler is LockupHandler { - constructor( - IERC20 asset_, - LockupStore lockupStore_, - ISablierLockupLinear lockupLinear_ - ) - LockupHandler(asset_, lockupStore_, lockupLinear_) - { } -} diff --git a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol b/test/core/invariant/handlers/LockupTranchedCreateHandler.sol deleted file mode 100644 index d19b287af..000000000 --- a/test/core/invariant/handlers/LockupTranchedCreateHandler.sol +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; -import { LockupTranched } from "src/core/types/DataTypes.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { BaseHandler } from "./BaseHandler.sol"; - -/// @dev This contract is a complement of {LockupTranchedHandler}. The goal is to bias the invariant calls toward the -/// lockup functions (especially the create stream functions) by creating multiple handlers for the Lockup contracts. -contract LockupTranchedCreateHandler is BaseHandler { - /*////////////////////////////////////////////////////////////////////////// - TEST CONTRACTS - //////////////////////////////////////////////////////////////////////////*/ - - LockupStore public lockupStore; - ISablierLockupTranched public lockupTranched; - - /*////////////////////////////////////////////////////////////////////////// - CONSTRUCTOR - //////////////////////////////////////////////////////////////////////////*/ - - constructor(IERC20 asset_, LockupStore lockupStore_, ISablierLockupTranched lockupTranched_) BaseHandler(asset_) { - lockupStore = lockupStore_; - lockupTranched = lockupTranched_; - } - - /*////////////////////////////////////////////////////////////////////////// - HANDLER FUNCTIONS - //////////////////////////////////////////////////////////////////////////*/ - - function createWithDurations( - uint256 timeJumpSeed, - LockupTranched.CreateWithDurations memory params - ) - public - instrument("createWithDurations") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - // The protocol doesn't allow empty tranche arrays. - vm.assume(params.tranches.length != 0); - - // Bound the broker fee. - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - - // Fuzz the durations. - fuzzTrancheDurations(params.tranches); - - // Fuzz the tranche amounts and calculate the total amount. - (params.totalAmount,) = fuzzTranchedStreamAmounts({ - upperBound: 1_000_000_000e18, - tranches: params.tranches, - brokerFee: params.broker.fee - }); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupTranched} to spend the assets. - asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupTranched.createWithDurations(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } - - function createWithTimestamps( - uint256 timeJumpSeed, - LockupTranched.CreateWithTimestamps memory params - ) - public - instrument("createWithTimestamps") - adjustTimestamp(timeJumpSeed) - checkUsers(params.sender, params.recipient, params.broker.account) - useNewSender(params.sender) - { - // We don't want to create more than a certain number of streams. - vm.assume(lockupStore.lastStreamId() <= MAX_STREAM_COUNT); - - // The protocol doesn't allow empty tranche arrays. - vm.assume(params.tranches.length != 0); - - params.broker.fee = _bound(params.broker.fee, 0, MAX_BROKER_FEE); - params.startTime = boundUint40(params.startTime, 1, getBlockTimestamp()); - - // Fuzz the tranche timestamps. - fuzzTrancheTimestamps(params.tranches, params.startTime); - - // Fuzz the tranche amounts and calculate the total amount. - (params.totalAmount,) = fuzzTranchedStreamAmounts({ - upperBound: 1_000_000_000e18, - tranches: params.tranches, - brokerFee: params.broker.fee - }); - - // Mint enough assets to the Sender. - deal({ token: address(asset), to: params.sender, give: asset.balanceOf(params.sender) + params.totalAmount }); - - // Approve {SablierLockupTranched} to spend the assets. - asset.approve({ spender: address(lockupTranched), value: params.totalAmount }); - - // Create the stream. - params.asset = asset; - uint256 streamId = lockupTranched.createWithTimestamps(params); - - // Store the stream ID. - lockupStore.pushStreamId(streamId, params.sender, params.recipient); - } -} diff --git a/test/core/invariant/handlers/LockupTranchedHandler.sol b/test/core/invariant/handlers/LockupTranchedHandler.sol deleted file mode 100644 index bb0c9f26b..000000000 --- a/test/core/invariant/handlers/LockupTranchedHandler.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity >=0.8.22 <0.9.0; - -import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; - -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; - -import { LockupStore } from "../stores/LockupStore.sol"; -import { LockupHandler } from "./LockupHandler.sol"; - -/// @dev This contract and not {SablierLockupTranched} is exposed to Foundry for invariant testing. The goal is -/// to bound and restrict the inputs that get passed to the real-world contract to avoid getting reverts. -contract LockupTranchedHandler is LockupHandler { - constructor( - IERC20 asset_, - LockupStore lockupStore_, - ISablierLockupTranched lockupTranched_ - ) - LockupHandler(asset_, lockupStore_, lockupTranched_) - { } -} diff --git a/test/mocks/Hooks.sol b/test/mocks/Hooks.sol index 6b7e1981a..203c2a91a 100644 --- a/test/mocks/Hooks.sol +++ b/test/mocks/Hooks.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22; import { IERC165, ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; -import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { ISablierLockupBase } from "src/core/interfaces/ISablierLockupBase.sol"; import { ISablierLockupRecipient } from "src/core/interfaces/ISablierLockupRecipient.sol"; contract RecipientGood is ISablierLockupRecipient, ERC165 { @@ -138,7 +138,7 @@ contract RecipientReentrant is ISablierLockupRecipient, ERC165 { senderAmount; recipientAmount; - ISablierLockup(msg.sender).withdraw(streamId, address(this), recipientAmount); + ISablierLockupBase(msg.sender).withdraw(streamId, address(this), recipientAmount); return ISablierLockupRecipient.onSablierLockupCancel.selector; } @@ -158,7 +158,7 @@ contract RecipientReentrant is ISablierLockupRecipient, ERC165 { to; amount; - ISablierLockup(msg.sender).withdraw(streamId, address(this), amount); + ISablierLockupBase(msg.sender).withdraw(streamId, address(this), amount); return ISablierLockupRecipient.onSablierLockupWithdraw.selector; } diff --git a/test/periphery/Periphery.t.sol b/test/periphery/Periphery.t.sol index 5f8ae5ea8..c2eecde78 100644 --- a/test/periphery/Periphery.t.sol +++ b/test/periphery/Periphery.t.sol @@ -3,10 +3,8 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; -import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierMerkleBase } from "src/periphery/interfaces/ISablierMerkleBase.sol"; import { SablierMerkleInstant } from "src/periphery/SablierMerkleInstant.sol"; @@ -41,93 +39,95 @@ contract Periphery_Test is Base_Test { CALL EXPECTS - LOCKUP //////////////////////////////////////////////////////////////////////////*/ - /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithDurations}, each with the specified - /// `params`. + /// @dev Expects multiple calls to {ISablierLockup.createWithDurationsLD}, each with the specified `params`. function expectMultipleCallsToCreateWithDurationsLD( uint64 count, - LockupDynamic.CreateWithDurations memory params + Lockup.CreateWithDurations memory params, + LockupDynamic.SegmentWithDuration[] memory segments ) internal { vm.expectCall({ - callee: address(lockupDynamic), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupDynamic.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockup.createWithDurationsLD, (params, segments)) }); } - /// @dev Expects multiple calls to {ISablierLockupLinear.createWithDurations}, each with the specified - /// `params`. + /// @dev Expects multiple calls to {ISablierLockup.createWithDurationsLL}, each with the specified `params`. function expectMultipleCallsToCreateWithDurationsLL( uint64 count, - LockupLinear.CreateWithDurations memory params + Lockup.CreateWithDurations memory params, + LockupLinear.Durations memory durations ) internal { vm.expectCall({ - callee: address(lockupLinear), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupLinear.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockup.createWithDurationsLL, (params, durations)) }); } - /// @dev Expects multiple calls to {ISablierLockupTranched.createWithDurations}, each with the specified - /// `params`. + /// @dev Expects multiple calls to {ISablierLockup.createWithDurationsLT}, each with the specified `params`. function expectMultipleCallsToCreateWithDurationsLT( uint64 count, - LockupTranched.CreateWithDurations memory params + Lockup.CreateWithDurations memory params, + LockupTranched.TrancheWithDuration[] memory tranches ) internal { vm.expectCall({ - callee: address(lockupTranched), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupTranched.createWithDurations, (params)) + data: abi.encodeCall(ISablierLockup.createWithDurationsLT, (params, tranches)) }); } - /// @dev Expects multiple calls to {ISablierLockupDynamic.createWithTimestamps}, each with the specified - /// `params`. + /// @dev Expects multiple calls to {ISablierLockup.createWithTimestampsLD}, each with the specified `params`. function expectMultipleCallsToCreateWithTimestampsLD( uint64 count, - LockupDynamic.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + LockupDynamic.Segment[] memory segments ) internal { vm.expectCall({ - callee: address(lockupDynamic), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupDynamic.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockup.createWithTimestampsLD, (params, segments)) }); } - /// @dev Expects multiple calls to {ISablierLockupLinear.createWithTimestamps}, each with the specified + /// @dev Expects multiple calls to {ISablierLockup.createWithTimestampsLL}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLL( uint64 count, - LockupLinear.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + uint40 cliff ) internal { vm.expectCall({ - callee: address(lockupLinear), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupLinear.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockup.createWithTimestampsLL, (params, cliff)) }); } - /// @dev Expects multiple calls to {ISablierLockupTranched.createWithTimestamps}, each with the specified + /// @dev Expects multiple calls to {ISablierLockup.createWithTimestampsLT}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLT( uint64 count, - LockupTranched.CreateWithTimestamps memory params + Lockup.CreateWithTimestamps memory params, + LockupTranched.Tranche[] memory tranches ) internal { vm.expectCall({ - callee: address(lockupTranched), + callee: address(lockup), count: count, - data: abi.encodeCall(ISablierLockupTranched.createWithTimestamps, (params)) + data: abi.encodeCall(ISablierLockup.createWithTimestampsLT, (params, tranches)) }); } @@ -220,7 +220,7 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), - lockupLinear, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), abi.encode(defaults.schedule()) @@ -256,7 +256,7 @@ contract Periphery_Test is Base_Test { abi.encode(defaults.IPFS_CID()), merkleRoot, defaults.NAME_BYTES32(), - lockupTranched, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), @@ -307,7 +307,7 @@ contract Periphery_Test is Base_Test { { bytes memory constructorArgs = abi.encode( defaults.baseParams(campaignOwner, asset_, expiration, merkleRoot), - lockupLinear, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.schedule(), @@ -333,7 +333,7 @@ contract Periphery_Test is Base_Test { { bytes memory constructorArgs = abi.encode( defaults.baseParams(campaignOwner, asset_, expiration, merkleRoot), - lockupTranched, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), diff --git a/test/periphery/fork/Fork.t.sol b/test/periphery/fork/Fork.t.sol index ac111cdd9..c7f3c38ad 100644 --- a/test/periphery/fork/Fork.t.sol +++ b/test/periphery/fork/Fork.t.sol @@ -2,9 +2,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; import { Merkle } from "./../../utils/Murky.sol"; import { Periphery_Test } from "./../Periphery.t.sol"; @@ -30,13 +27,14 @@ abstract contract Fork_Test is Periphery_Test, Merkle { function setUp() public virtual override { // Fork Ethereum Mainnet at a specific block number. - vm.createSelectFork({ blockNumber: 20_339_512, urlOrAlias: "mainnet" }); + vm.createSelectFork({ blockNumber: 20_428_723, urlOrAlias: "mainnet" }); // Set up the parent test contract. Periphery_Test.setUp(); - // Load the external dependencies. - loadDependencies(); + // Load the pre-deployed external dependencies. + // TODO: Update addresses once deployed. + // lockup = ISablierLockup(0x6Fe81F4Bf1aF1b829f0E701647808f3Aa4b0BdE7); } /*////////////////////////////////////////////////////////////////////////// @@ -50,20 +48,10 @@ abstract contract Fork_Test is Periphery_Test, Merkle { // The goal is to not have overlapping users because the asset balance tests would fail otherwise. vm.assume(user != recipient); - vm.assume(user != address(lockupDynamic) && recipient != address(lockupDynamic)); - vm.assume(user != address(lockupLinear) && recipient != address(lockupLinear)); - vm.assume(user != address(lockupTranched) && recipient != address(lockupTranched)); + vm.assume(user != address(lockup) && recipient != address(lockup)); // Avoid users blacklisted by USDC or USDT. assumeNoBlacklisted(address(FORK_ASSET), user); assumeNoBlacklisted(address(FORK_ASSET), recipient); } - - /// @dev Loads all dependencies pre-deployed on Mainnet. - // TODO: Update addresses once deployed. - function loadDependencies() private { - lockupDynamic = ISablierLockupDynamic(0x9DeaBf7815b42Bf4E9a03EEc35a486fF74ee7459); - lockupLinear = ISablierLockupLinear(0x3962f6585946823440d274aD7C719B02b49DE51E); - lockupTranched = ISablierLockupTranched(0xf86B359035208e4529686A1825F2D5BeE38c28A8); - } } diff --git a/test/periphery/fork/assets/USDC.t.sol b/test/periphery/fork/assets/USDC.t.sol index 868229bc5..e2700ecde 100644 --- a/test/periphery/fork/assets/USDC.t.sol +++ b/test/periphery/fork/assets/USDC.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; -import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; -import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; +import { CreateWithTimestampsLD_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; +import { CreateWithTimestampsLL_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; +import { CreateWithTimestampsLT_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; import { MerkleInstant_Fork_Test } from "../merkle-campaign/MerkleInstant.t.sol"; import { MerkleLL_Fork_Test } from "../merkle-campaign/MerkleLL.t.sol"; import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; @@ -13,17 +13,11 @@ import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; /// @dev An ERC-20 asset with 6 decimals. IERC20 constant usdc = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); -contract USDC_CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test(usdc) -{ } +contract USDC_CreateWithTimestampsLD_BatchLockup_Fork_Test is CreateWithTimestampsLD_BatchLockup_Fork_Test(usdc) { } -contract USDC_CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test(usdc) -{ } +contract USDC_CreateWithTimestampsLL_BatchLockup_Fork_Test is CreateWithTimestampsLL_BatchLockup_Fork_Test(usdc) { } -contract USDC_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdc) -{ } +contract USDC_CreateWithTimestampsLT_BatchLockup_Fork_Test is CreateWithTimestampsLT_BatchLockup_Fork_Test(usdc) { } contract USDC_MerkleInstant_Fork_Test is MerkleInstant_Fork_Test(usdc) { } diff --git a/test/periphery/fork/assets/USDT.t.sol b/test/periphery/fork/assets/USDT.t.sol index e5ada0ce0..8d3163dd9 100644 --- a/test/periphery/fork/assets/USDT.t.sol +++ b/test/periphery/fork/assets/USDT.t.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; -import { CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; -import { CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; +import { CreateWithTimestampsLD_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLD.t.sol"; +import { CreateWithTimestampsLL_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLL.t.sol"; +import { CreateWithTimestampsLT_BatchLockup_Fork_Test } from "../batch-lockup/createWithTimestampsLT.t.sol"; import { MerkleInstant_Fork_Test } from "../merkle-campaign/MerkleInstant.t.sol"; import { MerkleLL_Fork_Test } from "../merkle-campaign/MerkleLL.t.sol"; import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; @@ -13,17 +13,11 @@ import { MerkleLT_Fork_Test } from "../merkle-campaign/MerkleLT.t.sol"; /// @dev An ERC-20 asset that suffers from the missing return value bug. IERC20 constant usdt = IERC20(0xdAC17F958D2ee523a2206206994597C13D831ec7); -contract USDT_CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test(usdt) -{ } +contract USDT_CreateWithTimestampsLD_BatchLockup_Fork_Test is CreateWithTimestampsLD_BatchLockup_Fork_Test(usdt) { } -contract USDT_CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test(usdt) -{ } +contract USDT_CreateWithTimestampsLL_BatchLockup_Fork_Test is CreateWithTimestampsLL_BatchLockup_Fork_Test(usdt) { } -contract USDT_CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is - CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test(usdt) -{ } +contract USDT_CreateWithTimestampsLT_BatchLockup_Fork_Test is CreateWithTimestampsLT_BatchLockup_Fork_Test(usdt) { } contract USDT_MerkleInstant_Fork_Test is MerkleInstant_Fork_Test(usdt) { } diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol index 8658ed66d..0d5c97ecc 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLD.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupDynamic } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic } from "src/core/types/DataTypes.sol"; import { BatchLockup } from "src/periphery/types/DataTypes.sol"; import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; @@ -11,7 +11,7 @@ import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. -abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fork_Test { +abstract contract CreateWithTimestampsLD_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } struct CreateWithTimestampsParams { @@ -36,13 +36,13 @@ abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fo checkUsers(params.sender, params.recipient); - uint256 firstStreamId = lockupDynamic.nextStreamId(); + uint256 firstStreamId = lockup.nextStreamId(); uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); - LockupDynamic.CreateWithTimestamps memory createWithTimestamps = LockupDynamic.CreateWithTimestamps({ + Lockup.CreateWithTimestamps memory createWithTimestamps = Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.perStreamAmount, @@ -50,11 +50,11 @@ abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fo cancelable: true, transferable: true, startTime: params.startTime, - segments: params.segments, + endTime: params.segments[params.segments.length - 1].timestamp, broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLD[] memory batchParams = - BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); + BatchLockupBuilder.fillBatch(createWithTimestamps, params.segments, params.batchSize); expectCallToTransferFrom({ asset: FORK_ASSET, @@ -62,16 +62,20 @@ abstract contract CreateWithTimestamps_LockupDynamic_BatchLockup_Fork_Test is Fo to: address(batchLockup), value: totalTransferAmount }); - expectMultipleCallsToCreateWithTimestampsLD({ count: uint64(params.batchSize), params: createWithTimestamps }); + expectMultipleCallsToCreateWithTimestampsLD({ + count: uint64(params.batchSize), + params: createWithTimestamps, + segments: params.segments + }); expectMultipleCallsToTransferFrom({ asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), - to: address(lockupDynamic), + to: address(lockup), value: params.perStreamAmount }); - uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLD(lockupDynamic, FORK_ASSET, batchParams); + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLD(lockup, FORK_ASSET, batchParams); uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); assertEq(actualStreamIds, expectedStreamIds); } diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol index 919e4447b..5eab6a2a3 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLL.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupLinear } from "src/core/types/DataTypes.sol"; +import { Lockup } from "src/core/types/DataTypes.sol"; import { BatchLockup } from "src/periphery/types/DataTypes.sol"; import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; @@ -11,12 +11,12 @@ import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. -abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is Fork_Test { +abstract contract CreateWithTimestampsLL_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } struct CreateWithTimestampsParams { uint128 batchSize; - LockupLinear.Timestamps timestamps; + Lockup.Timestamps timestamps; address sender; address recipient; uint128 perStreamAmount; @@ -35,24 +35,25 @@ abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is For checkUsers(params.sender, params.recipient); - uint256 firstStreamId = lockupLinear.nextStreamId(); + uint256 firstStreamId = lockup.nextStreamId(); uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); - LockupLinear.CreateWithTimestamps memory createParams = LockupLinear.CreateWithTimestamps({ + Lockup.CreateWithTimestamps memory createParams = Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.perStreamAmount, asset: FORK_ASSET, cancelable: true, transferable: true, - timestamps: params.timestamps, + startTime: params.timestamps.start, + endTime: params.timestamps.end, broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLL[] memory batchParams = - BatchLockupBuilder.fillBatch(createParams, params.batchSize); + BatchLockupBuilder.fillBatch(createParams, params.timestamps.cliff, params.batchSize); // Asset flow: sender → batch → Sablier expectCallToTransferFrom({ @@ -61,16 +62,20 @@ abstract contract CreateWithTimestamps_LockupLinear_BatchLockup_Fork_Test is For to: address(batchLockup), value: totalTransferAmount }); - expectMultipleCallsToCreateWithTimestampsLL({ count: uint64(params.batchSize), params: createParams }); + expectMultipleCallsToCreateWithTimestampsLL({ + count: uint64(params.batchSize), + params: createParams, + cliff: params.timestamps.cliff + }); expectMultipleCallsToTransferFrom({ asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), - to: address(lockupLinear), + to: address(lockup), value: params.perStreamAmount }); - uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLL(lockupLinear, FORK_ASSET, batchParams); + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLL(lockup, FORK_ASSET, batchParams); uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); assertEq(actualStreamIds, expectedStreamIds); } diff --git a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol index 0f9849a22..eddc66bbc 100644 --- a/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol +++ b/test/periphery/fork/batch-lockup/createWithTimestampsLT.t.sol @@ -3,7 +3,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { LockupTranched } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { BatchLockup } from "src/periphery/types/DataTypes.sol"; import { ArrayBuilder } from "../../../utils/ArrayBuilder.sol"; @@ -11,7 +11,7 @@ import { BatchLockupBuilder } from "../../../utils/BatchLockupBuilder.sol"; import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. -abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is Fork_Test { +abstract contract CreateWithTimestampsLT_BatchLockup_Fork_Test is Fork_Test { constructor(IERC20 asset_) Fork_Test(asset_) { } struct CreateWithTimestampsParams { @@ -36,13 +36,13 @@ abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is F checkUsers(params.sender, params.recipient); - uint256 firstStreamId = lockupTranched.nextStreamId(); + uint256 firstStreamId = lockup.nextStreamId(); uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; deal({ token: address(FORK_ASSET), to: params.sender, give: uint256(totalTransferAmount) }); approveContract({ asset_: FORK_ASSET, from: params.sender, spender: address(batchLockup) }); - LockupTranched.CreateWithTimestamps memory createWithTimestamps = LockupTranched.CreateWithTimestamps({ + Lockup.CreateWithTimestamps memory createWithTimestamps = Lockup.CreateWithTimestamps({ sender: params.sender, recipient: params.recipient, totalAmount: params.perStreamAmount, @@ -50,11 +50,11 @@ abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is F cancelable: true, transferable: true, startTime: params.startTime, - tranches: params.tranches, + endTime: params.tranches[params.tranches.length - 1].timestamp, broker: defaults.brokerNull() }); BatchLockup.CreateWithTimestampsLT[] memory batchParams = - BatchLockupBuilder.fillBatch(createWithTimestamps, params.batchSize); + BatchLockupBuilder.fillBatch(createWithTimestamps, params.tranches, params.batchSize); expectCallToTransferFrom({ asset: FORK_ASSET, @@ -62,16 +62,20 @@ abstract contract CreateWithTimestamps_LockupTranched_BatchLockup_Fork_Test is F to: address(batchLockup), value: totalTransferAmount }); - expectMultipleCallsToCreateWithTimestampsLT({ count: uint64(params.batchSize), params: createWithTimestamps }); + expectMultipleCallsToCreateWithTimestampsLT({ + count: uint64(params.batchSize), + params: createWithTimestamps, + tranches: params.tranches + }); expectMultipleCallsToTransferFrom({ asset: FORK_ASSET, count: uint64(params.batchSize), from: address(batchLockup), - to: address(lockupTranched), + to: address(lockup), value: params.perStreamAmount }); - uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLT(lockupTranched, FORK_ASSET, batchParams); + uint256[] memory actualStreamIds = batchLockup.createWithTimestampsLT(lockup, FORK_ASSET, batchParams); uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); assertEq(actualStreamIds, expectedStreamIds); } diff --git a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol index dc11b680f..310ba031b 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLL.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLL.t.sol @@ -4,7 +4,6 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; -import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleBase, ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; @@ -32,13 +31,11 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { } struct Vars { - LockupLinear.StreamLL actualStream; uint256 aggregateAmount; uint128[] amounts; MerkleBase.ConstructorParams baseParams; uint128 clawbackAmount; address expectedLL; - LockupLinear.StreamLL expectedStream; uint256 expectedStreamId; uint256[] indexes; uint256 leafPos; @@ -119,7 +116,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { emit ISablierMerkleFactory.CreateMerkleLL({ merkleLL: ISablierMerkleLL(vars.expectedLL), baseParams: vars.baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), @@ -130,7 +127,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { vars.merkleLL = merkleFactory.createMerkleLL({ baseParams: vars.baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), @@ -161,7 +158,7 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { ); vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); - vars.expectedStreamId = lockupLinear.nextStreamId(); + vars.expectedStreamId = lockup.nextStreamId(); vm.expectEmit({ emitter: address(vars.merkleLL) }); emit ISablierMerkleLL.Claim( @@ -195,24 +192,27 @@ abstract contract MerkleLL_Fork_Test is Fork_Test { merkleProof: vars.merkleProof }); - vars.actualStream = lockupLinear.getStream(vars.expectedStreamId); - vars.expectedStream = LockupLinear.StreamLL({ - amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), - asset: FORK_ASSET, - cliffTime: getBlockTimestamp() + defaults.CLIFF_DURATION(), - endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), - isCancelable: defaults.CANCELABLE(), - isDepleted: false, - isStream: true, - isTransferable: defaults.TRANSFERABLE(), - recipient: vars.recipients[params.posBeforeSort], - sender: params.campaignOwner, - startTime: getBlockTimestamp(), - wasCanceled: false - }); + // Assert that the stream has been created successfully. + assertEq( + lockup.getDepositedAmount(vars.expectedStreamId), vars.amounts[params.posBeforeSort], "deposited amount" + ); + assertEq(lockup.getRefundedAmount(vars.expectedStreamId), 0, "refunded amount"); + assertEq(lockup.getWithdrawnAmount(vars.expectedStreamId), 0, "withdrawn amount"); + assertEq(lockup.getAsset(vars.expectedStreamId), FORK_ASSET, "asset"); + assertEq( + lockup.getCliffTime(vars.expectedStreamId), getBlockTimestamp() + defaults.CLIFF_DURATION(), "cliff time" + ); + assertEq(lockup.getEndTime(vars.expectedStreamId), getBlockTimestamp() + defaults.TOTAL_DURATION(), "end time"); + assertEq(lockup.isCancelable(vars.expectedStreamId), defaults.CANCELABLE(), "is cancelable"); + assertEq(lockup.isDepleted(vars.expectedStreamId), false, "is depleted"); + assertEq(lockup.isStream(vars.expectedStreamId), true, "is stream"); + assertEq(lockup.isTransferable(vars.expectedStreamId), defaults.TRANSFERABLE(), "is transferable"); + assertEq(lockup.getRecipient(vars.expectedStreamId), vars.recipients[params.posBeforeSort], "recipient"); + assertEq(lockup.getSender(vars.expectedStreamId), params.campaignOwner, "sender"); + assertEq(lockup.getStartTime(vars.expectedStreamId), getBlockTimestamp(), "start time"); + assertEq(lockup.wasCanceled(vars.expectedStreamId), false, "was canceled"); assertTrue(vars.merkleLL.hasClaimed(vars.indexes[params.posBeforeSort])); - assertEq(vars.actualStream, vars.expectedStream); /*////////////////////////////////////////////////////////////////////////// CLAWBACK diff --git a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol index 2bf1b2009..2dfc1ad3c 100644 --- a/test/periphery/fork/merkle-campaign/MerkleLT.t.sol +++ b/test/periphery/fork/merkle-campaign/MerkleLT.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Arrays } from "@openzeppelin/contracts/utils/Arrays.sol"; -import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; +import { LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { ISablierMerkleBase, ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { MerkleBase } from "src/periphery/types/DataTypes.sol"; @@ -32,14 +32,12 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { } struct Vars { - LockupTranched.StreamLT actualStream; LockupTranched.Tranche[] actualTranches; uint256 aggregateAmount; uint128[] amounts; MerkleBase.ConstructorParams baseParams; uint128 clawbackAmount; address expectedLT; - LockupTranched.StreamLT expectedStream; uint256 expectedStreamId; uint256[] indexes; uint256 leafPos; @@ -120,7 +118,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { emit ISablierMerkleFactory.CreateMerkleLT({ merkleLT: ISablierMerkleLT(vars.expectedLT), baseParams: vars.baseParams, - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_ZERO(), @@ -133,7 +131,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { vars.merkleLT = merkleFactory.createMerkleLT({ baseParams: vars.baseParams, - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_ZERO(), @@ -165,7 +163,7 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { ); vars.leafPos = Arrays.findUpperBound(leaves, vars.leafToClaim); - vars.expectedStreamId = lockupTranched.nextStreamId(); + vars.expectedStreamId = lockup.nextStreamId(); vm.expectEmit({ emitter: address(vars.merkleLT) }); emit ISablierMerkleLT.Claim( vars.indexes[params.posBeforeSort], @@ -198,27 +196,32 @@ abstract contract MerkleLT_Fork_Test is Fork_Test { merkleProof: vars.merkleProof }); - vars.actualStream = lockupTranched.getStream(vars.expectedStreamId); - vars.expectedStream = LockupTranched.StreamLT({ - amounts: Lockup.Amounts({ deposited: vars.amounts[params.posBeforeSort], refunded: 0, withdrawn: 0 }), - asset: FORK_ASSET, - endTime: getBlockTimestamp() + defaults.TOTAL_DURATION(), - isCancelable: defaults.CANCELABLE(), - isDepleted: false, - isStream: true, - isTransferable: defaults.TRANSFERABLE(), - recipient: vars.recipients[params.posBeforeSort], - sender: params.campaignOwner, - startTime: getBlockTimestamp(), - tranches: defaults.tranchesMerkleLT({ + // Assert that the stream has been creatUSDT_MerkleLL_Fork_Tested successfully. + assertEq( + lockup.getDepositedAmount(vars.expectedStreamId), vars.amounts[params.posBeforeSort], "deposited amount" + ); + assertEq(lockup.getRefundedAmount(vars.expectedStreamId), 0, "refunded amount"); + assertEq(lockup.getWithdrawnAmount(vars.expectedStreamId), 0, "withdrawn amount"); + assertEq(lockup.getAsset(vars.expectedStreamId), FORK_ASSET, "asset"); + assertEq(lockup.getEndTime(vars.expectedStreamId), getBlockTimestamp() + defaults.TOTAL_DURATION(), "end time"); + assertEq(lockup.isCancelable(vars.expectedStreamId), defaults.CANCELABLE(), "is cancelable"); + assertEq(lockup.isDepleted(vars.expectedStreamId), false, "is depleted"); + assertEq(lockup.isStream(vars.expectedStreamId), true, "is stream"); + assertEq(lockup.isTransferable(vars.expectedStreamId), defaults.TRANSFERABLE(), "is transferable"); + assertEq(lockup.getRecipient(vars.expectedStreamId), vars.recipients[params.posBeforeSort], "recipient"); + assertEq(lockup.getSender(vars.expectedStreamId), params.campaignOwner, "sender"); + assertEq(lockup.getStartTime(vars.expectedStreamId), getBlockTimestamp(), "start time"); + assertEq(lockup.wasCanceled(vars.expectedStreamId), false, "was canceled"); + assertEq( + lockup.getTranches(vars.expectedStreamId), + defaults.tranchesMerkleLT({ streamStartTime: defaults.STREAM_START_TIME_ZERO(), totalAmount: vars.amounts[params.posBeforeSort] }), - wasCanceled: false - }); + "tranches" + ); assertTrue(vars.merkleLT.hasClaimed(vars.indexes[params.posBeforeSort])); - assertEq(vars.actualStream, vars.expectedStream); /*////////////////////////////////////////////////////////////////////////// CLAWBACK diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol index 87d52daf5..e75f99091 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ld/createWithDurationsLD.t.sol @@ -15,7 +15,7 @@ contract CreateWithDurationsLD_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLD[] memory batchParams = new BatchLockup.CreateWithDurationsLD[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithDurationsLD(lockupDynamic, dai, batchParams); + batchLockup.createWithDurationsLD(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -28,18 +28,19 @@ contract CreateWithDurationsLD_Integration_Test is Periphery_Test { }); expectMultipleCallsToCreateWithDurationsLD({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsBrokerNullLD() + params: defaults.createWithDurationsBrokerNull(), + segments: defaults.segmentsWithDurations() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupDynamic), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithDurationsLD(lockupDynamic, dai, defaults.batchCreateWithDurationsLD()); + batchLockup.createWithDurationsLD(lockup, dai, defaults.batchCreateWithDurationsLD()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol index 882a491fd..813502cf1 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-ll/createWithDurationsLL.t.sol @@ -15,7 +15,7 @@ contract CreateWithDurationsLL_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLL[] memory batchParams = new BatchLockup.CreateWithDurationsLL[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithDurationsLL(lockupLinear, dai, batchParams); + batchLockup.createWithDurationsLL(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -26,20 +26,22 @@ contract CreateWithDurationsLL_Integration_Test is Periphery_Test { to: address(batchLockup), value: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithDurationsLL({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsBrokerNullLL() + params: defaults.createWithDurationsBrokerNull(), + durations: defaults.durations() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupLinear), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithDurationsLL(lockupLinear, dai, defaults.batchCreateWithDurationsLL()); + batchLockup.createWithDurationsLL(lockup, dai, defaults.batchCreateWithDurationsLL()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol index f2c471ca4..b8ae540d5 100644 --- a/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-durations-lt/createWithDurationsLT.t.sol @@ -15,7 +15,7 @@ contract CreateWithDurationsLT_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithDurationsLT[] memory batchParams = new BatchLockup.CreateWithDurationsLT[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithDurationsLT(lockupTranched, dai, batchParams); + batchLockup.createWithDurationsLT(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -26,20 +26,22 @@ contract CreateWithDurationsLT_Integration_Test is Periphery_Test { to: address(batchLockup), value: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithDurationsLT({ count: defaults.BATCH_SIZE(), - params: defaults.createWithDurationsBrokerNullLT() + params: defaults.createWithDurationsBrokerNull(), + tranches: defaults.tranchesWithDurations() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupTranched), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithDurationsLT(lockupTranched, dai, defaults.batchCreateWithDurationsLT()); + batchLockup.createWithDurationsLT(lockup, dai, defaults.batchCreateWithDurationsLT()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol index d48653bc2..e4b024deb 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ld/createWithTimestampsLD.t.sol @@ -15,7 +15,7 @@ contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLD[] memory batchParams = new BatchLockup.CreateWithTimestampsLD[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithTimestampsLD(lockupDynamic, dai, batchParams); + batchLockup.createWithTimestampsLD(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -26,20 +26,22 @@ contract CreateWithTimestampsLD_Integration_Test is Periphery_Test { to: address(batchLockup), value: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithTimestampsLD({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsBrokerNullLD() + params: defaults.createWithTimestampsBrokerNull(), + segments: defaults.segments() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupDynamic), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithTimestampsLD(lockupDynamic, dai, defaults.batchCreateWithTimestampsLD()); + batchLockup.createWithTimestampsLD(lockup, dai, defaults.batchCreateWithTimestampsLD()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol index 6fbb33ed9..8dc414936 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-ll/createWithTimestamps.t.sol @@ -15,7 +15,7 @@ contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLL[] memory batchParams = new BatchLockup.CreateWithTimestampsLL[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithTimestampsLL(lockupLinear, dai, batchParams); + batchLockup.createWithTimestampsLL(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -26,20 +26,22 @@ contract CreateWithTimestampsLL_Integration_Test is Periphery_Test { to: address(batchLockup), value: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithTimestampsLL({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsBrokerNullLL() + params: defaults.createWithTimestampsBrokerNull(), + cliff: defaults.CLIFF_TIME() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupLinear), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithTimestampsLL(lockupLinear, dai, defaults.batchCreateWithTimestampsLL()); + batchLockup.createWithTimestampsLL(lockup, dai, defaults.batchCreateWithTimestampsLL()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol index 1297f84bb..5fd468265 100644 --- a/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol +++ b/test/periphery/integration/batch-lockup/create-with-timestamps-lt/createWithTimestampsLT.t.sol @@ -15,7 +15,7 @@ contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { function test_RevertWhen_BatchSizeZero() external { BatchLockup.CreateWithTimestampsLT[] memory batchParams = new BatchLockup.CreateWithTimestampsLT[](0); vm.expectRevert(Errors.SablierBatchLockup_BatchSizeZero.selector); - batchLockup.createWithTimestampsLT(lockupTranched, dai, batchParams); + batchLockup.createWithTimestampsLT(lockup, dai, batchParams); } function test_WhenBatchSizeNotZero() external { @@ -26,20 +26,22 @@ contract CreateWithTimestampsLT_Integration_Test is Periphery_Test { to: address(batchLockup), value: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithTimestampsLT({ count: defaults.BATCH_SIZE(), - params: defaults.createWithTimestampsBrokerNullLT() + params: defaults.createWithTimestampsBrokerNull(), + tranches: defaults.tranches() }); expectMultipleCallsToTransferFrom({ count: defaults.BATCH_SIZE(), from: address(batchLockup), - to: address(lockupTranched), + to: address(lockup), value: defaults.DEPOSIT_AMOUNT() }); // Assert that the batch of streams has been created successfully. uint256[] memory actualStreamIds = - batchLockup.createWithTimestampsLT(lockupTranched, dai, defaults.batchCreateWithTimestampsLT()); + batchLockup.createWithTimestampsLT(lockup, dai, defaults.batchCreateWithTimestampsLT()); uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); } diff --git a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol index 4b064dc46..85dedf95f 100644 --- a/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol +++ b/test/periphery/integration/merkle-campaign/MerkleCampaign.t.sol @@ -198,7 +198,7 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function createMerkleLL(address campaignOwner, uint40 expiration) internal returns (ISablierMerkleLL) { return merkleFactory.createMerkleLL({ baseParams: defaults.baseParams(campaignOwner, dai, expiration, defaults.MERKLE_ROOT()), - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), @@ -278,7 +278,7 @@ abstract contract MerkleCampaign_Integration_Test is Periphery_Test { function createMerkleLT(address campaignOwner, uint40 expiration) internal returns (ISablierMerkleLT) { return merkleFactory.createMerkleLT({ baseParams: defaults.baseParams(campaignOwner, dai, expiration, defaults.MERKLE_ROOT()), - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_ZERO(), diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol index ab1dedc5f..3ec8b3710 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-ll/createMerkleLL.t.sol @@ -27,7 +27,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { merkleFactory.createMerkleLL({ baseParams: baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: cancelable, transferable: transferable, schedule: schedule, @@ -49,7 +49,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { vm.expectRevert(); merkleFactory.createMerkleLL({ baseParams: baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: cancelable, transferable: transferable, schedule: schedule, @@ -86,7 +86,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { emit ISablierMerkleFactory.CreateMerkleLL({ merkleLL: ISablierMerkleLL(expectedLL), baseParams: baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), @@ -128,7 +128,7 @@ contract CreateMerkleLL_Integration_Test is MerkleCampaign_Integration_Test { emit ISablierMerkleFactory.CreateMerkleLL({ merkleLL: ISablierMerkleLL(expectedLL), baseParams: baseParams, - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: defaults.schedule(), diff --git a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol index c0fb086b8..71a88e301 100644 --- a/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol +++ b/test/periphery/integration/merkle-campaign/factory/create-merkle-lt/createMerkleLT.t.sol @@ -28,7 +28,7 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { merkleFactory.createMerkleLT( baseParams, - lockupTranched, + lockup, cancelable, transferable, streamStartTime, @@ -52,7 +52,7 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { vm.expectRevert(); merkleFactory.createMerkleLT( baseParams, - lockupTranched, + lockup, cancelable, transferable, streamStartTime, @@ -90,7 +90,7 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { emit ISablierMerkleFactory.CreateMerkleLT({ merkleLT: ISablierMerkleLT(expectedLT), baseParams: baseParams, - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_ZERO(), @@ -132,7 +132,7 @@ contract CreateMerkleLT_Integration_Test is MerkleCampaign_Integration_Test { emit ISablierMerkleFactory.CreateMerkleLT({ merkleLT: ISablierMerkleLT(expectedLT), baseParams: baseParams, - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_ZERO(), diff --git a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol index d856ada05..0e4ba4c4b 100644 --- a/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/claim/claim.t.sol @@ -1,7 +1,6 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; -import { Lockup, LockupLinear } from "src/core/types/DataTypes.sol"; import { ISablierMerkleLL } from "src/periphery/interfaces/ISablierMerkleLL.sol"; import { MerkleLL } from "src/periphery/types/DataTypes.sol"; @@ -21,7 +20,7 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int merkleLL = merkleFactory.createMerkleLL({ baseParams: defaults.baseParams(), - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: schedule, @@ -45,7 +44,7 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int merkleLL = merkleFactory.createMerkleLL({ baseParams: defaults.baseParams(), - lockupLinear: lockupLinear, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), schedule: schedule, @@ -65,14 +64,14 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int uint256 sablierFee = defaults.DEFAULT_SABLIER_FEE(); deal({ token: address(dai), to: address(merkleLL), give: defaults.AGGREGATE_AMOUNT() }); - uint256 expectedStreamId = lockupLinear.nextStreamId(); + uint256 expectedStreamId = lockup.nextStreamId(); uint256 previousFeeAccrued = address(merkleLL).balance; // It should emit a {Claim} event. vm.expectEmit({ emitter: address(merkleLL) }); emit ISablierMerkleLL.Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); - expectCallToTransferFrom({ from: address(merkleLL), to: address(lockupLinear), value: defaults.CLAIM_AMOUNT() }); + expectCallToTransferFrom({ from: address(merkleLL), to: address(lockup), value: defaults.CLAIM_AMOUNT() }); expectCallToClaimWithMsgValue(address(merkleLL), sablierFee); // Claim the airstream. @@ -80,23 +79,20 @@ contract Claim_MerkleLL_Integration_Test is Claim_Integration_Test, MerkleLL_Int defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof() ); - LockupLinear.StreamLL memory actualStream = lockupLinear.getStream(expectedStreamId); - LockupLinear.StreamLL memory expectedStream = LockupLinear.StreamLL({ - amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), - asset: dai, - cliffTime: cliffTime, - endTime: startTime + defaults.TOTAL_DURATION(), - isCancelable: defaults.CANCELABLE(), - isDepleted: false, - isStream: true, - isTransferable: defaults.TRANSFERABLE(), - recipient: users.recipient1, - sender: users.campaignOwner, - startTime: startTime, - wasCanceled: false - }); + // Assert that the stream has been created successfully. + assertEq(lockup.getDepositedAmount(expectedStreamId), defaults.CLAIM_AMOUNT(), "depositedAmount"); + assertEq(lockup.getAsset(expectedStreamId), dai, "asset"); + assertEq(lockup.getCliffTime(expectedStreamId), cliffTime, "cliff time"); + assertEq(lockup.getEndTime(expectedStreamId), startTime + defaults.TOTAL_DURATION(), "end time"); + assertEq(lockup.isCancelable(expectedStreamId), defaults.CANCELABLE(), "is cancelable"); + assertEq(lockup.isDepleted(expectedStreamId), false, "is depleted"); + assertEq(lockup.isStream(expectedStreamId), true, "is stream"); + assertEq(lockup.isTransferable(expectedStreamId), defaults.TRANSFERABLE(), "is transferable"); + assertEq(lockup.getRecipient(expectedStreamId), users.recipient1, "recipient"); + assertEq(lockup.getSender(expectedStreamId), users.campaignOwner, "sender"); + assertEq(lockup.getStartTime(expectedStreamId), startTime, "start time"); + assertEq(lockup.wasCanceled(expectedStreamId), false, "was canceled"); - assertEq(actualStream, expectedStream); assertTrue(merkleLL.hasClaimed(defaults.INDEX1()), "not claimed"); assertEq(address(merkleLL).balance, previousFeeAccrued + defaults.DEFAULT_SABLIER_FEE(), "fee collected"); diff --git a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol index ad3440655..f59fc2535 100644 --- a/test/periphery/integration/merkle-campaign/ll/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/ll/constructor.t.sol @@ -16,7 +16,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes uint40 actualExpiration; address actualFactory; string actualIpfsCID; - address actualLockupLinear; + address actualLockup; bytes32 actualMerkleRoot; string actualName; uint256 actualSablierFee; @@ -29,7 +29,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes uint40 expectedExpiration; address expectedFactory; string expectedIpfsCID; - address expectedLockupLinear; + address expectedLockup; bytes32 expectedMerkleRoot; bytes32 expectedName; uint256 expectedSablierFee; @@ -43,7 +43,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes SablierMerkleLL constructedLL = new SablierMerkleLL( defaults.baseParams(), - lockupLinear, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.schedule(), @@ -56,7 +56,7 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedAdmin = users.campaignOwner; assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); - vars.actualAllowance = dai.allowance(address(constructedLL), address(lockupLinear)); + vars.actualAllowance = dai.allowance(address(constructedLL), address(lockup)); vars.expectedAllowance = MAX_UINT256; assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); @@ -80,9 +80,9 @@ contract Constructor_MerkleLL_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedIpfsCID = defaults.IPFS_CID(); assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); - vars.actualLockupLinear = address(constructedLL.LOCKUP_LINEAR()); - vars.expectedLockupLinear = address(lockupLinear); - assertEq(vars.actualLockupLinear, vars.expectedLockupLinear, "lockupLinear"); + vars.actualLockup = address(constructedLL.LOCKUP()); + vars.expectedLockup = address(lockup); + assertEq(vars.actualLockup, vars.expectedLockup, "lockup"); vars.actualMerkleRoot = constructedLL.MERKLE_ROOT(); vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); diff --git a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol index 5068c4467..981878010 100644 --- a/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/claim/claim.t.sol @@ -3,7 +3,6 @@ pragma solidity >=0.8.22 <0.9.0; import { ud2x18 } from "@prb/math/src/UD2x18.sol"; -import { Lockup, LockupTranched } from "src/core/types/DataTypes.sol"; import { ISablierMerkleLT } from "src/periphery/interfaces/ISablierMerkleLT.sol"; import { Errors } from "src/periphery/libraries/Errors.sol"; import { MerkleLT } from "src/periphery/types/DataTypes.sol"; @@ -26,7 +25,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int merkleLT = merkleFactory.createMerkleLT( defaults.baseParams(), - lockupTranched, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), @@ -62,7 +61,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int merkleLT = merkleFactory.createMerkleLT( defaults.baseParams(), - lockupTranched, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), @@ -97,7 +96,7 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int function test_WhenStreamStartTimeNotZero() external whenMerkleProofValid whenTotalPercentage100 { merkleLT = merkleFactory.createMerkleLT({ baseParams: defaults.baseParams(), - lockupTranched: lockupTranched, + lockup: lockup, cancelable: defaults.CANCELABLE(), transferable: defaults.TRANSFERABLE(), streamStartTime: defaults.STREAM_START_TIME_NON_ZERO(), @@ -119,14 +118,14 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int deal({ token: address(dai), to: address(merkleLT), give: defaults.AGGREGATE_AMOUNT() }); - uint256 expectedStreamId = lockupTranched.nextStreamId(); + uint256 expectedStreamId = lockup.nextStreamId(); uint256 previousFeeAccrued = address(merkleLL).balance; // It should emit a {Claim} event. vm.expectEmit({ emitter: address(merkleLT) }); emit ISablierMerkleLT.Claim(defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), expectedStreamId); - expectCallToTransferFrom({ from: address(merkleLT), to: address(lockupTranched), value: defaults.CLAIM_AMOUNT() }); + expectCallToTransferFrom({ from: address(merkleLT), to: address(lockup), value: defaults.CLAIM_AMOUNT() }); expectCallToClaimWithMsgValue(address(merkleLT), sablierFee); // Claim the airstream. @@ -134,24 +133,25 @@ contract Claim_MerkleLT_Integration_Test is Claim_Integration_Test, MerkleLT_Int defaults.INDEX1(), users.recipient1, defaults.CLAIM_AMOUNT(), defaults.index1Proof() ); + // Assert that the stream has been created successfully. + assertEq(lockup.getDepositedAmount(expectedStreamId), defaults.CLAIM_AMOUNT(), "depositedAmount"); + assertEq(lockup.getAsset(expectedStreamId), dai, "asset"); + assertEq(lockup.getEndTime(expectedStreamId), startTime + defaults.TOTAL_DURATION(), "end time"); + assertEq(lockup.isCancelable(expectedStreamId), defaults.CANCELABLE(), "is cancelable"); + assertEq(lockup.isDepleted(expectedStreamId), false, "is depleted"); + assertEq(lockup.isStream(expectedStreamId), true, "is stream"); + assertEq(lockup.isTransferable(expectedStreamId), defaults.TRANSFERABLE(), "is transferable"); + assertEq(lockup.getRecipient(expectedStreamId), users.recipient1, "recipient"); + assertEq(lockup.getSender(expectedStreamId), users.campaignOwner, "sender"); + assertEq(lockup.getStartTime(expectedStreamId), startTime, "start time"); + assertEq(lockup.wasCanceled(expectedStreamId), false, "was canceled"); // It should create a stream with `STREAM_START_TIME` as start time. - LockupTranched.StreamLT memory actualStream = lockupTranched.getStream(expectedStreamId); - LockupTranched.StreamLT memory expectedStream = LockupTranched.StreamLT({ - amounts: Lockup.Amounts({ deposited: defaults.CLAIM_AMOUNT(), refunded: 0, withdrawn: 0 }), - asset: dai, - endTime: startTime + defaults.TOTAL_DURATION(), - isCancelable: defaults.CANCELABLE(), - isDepleted: false, - isStream: true, - isTransferable: defaults.TRANSFERABLE(), - recipient: users.recipient1, - sender: users.campaignOwner, - startTime: startTime, - tranches: defaults.tranchesMerkleLT({ streamStartTime: streamStartTime, totalAmount: defaults.CLAIM_AMOUNT() }), - wasCanceled: false - }); + assertEq( + lockup.getTranches(expectedStreamId), + defaults.tranchesMerkleLT({ streamStartTime: streamStartTime, totalAmount: defaults.CLAIM_AMOUNT() }), + "tranches" + ); - assertEq(actualStream, expectedStream); assertTrue(merkleLT.hasClaimed(defaults.INDEX1()), "not claimed"); assertEq(address(merkleLT).balance, previousFeeAccrued + defaults.DEFAULT_SABLIER_FEE(), "fee collected"); diff --git a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol index 772eb86fd..e07e3b274 100644 --- a/test/periphery/integration/merkle-campaign/lt/constructor.t.sol +++ b/test/periphery/integration/merkle-campaign/lt/constructor.t.sol @@ -16,7 +16,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes uint40 actualExpiration; address actualFactory; string actualIpfsCID; - address actualLockupTranched; + address actualLockup; bytes32 actualMerkleRoot; string actualName; uint256 actualSablierFee; @@ -31,7 +31,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes uint40 expectedExpiration; address expectedFactory; string expectedIpfsCID; - address expectedLockupTranched; + address expectedLockup; bytes32 expectedMerkleRoot; bytes32 expectedName; uint256 expectedSablierFee; @@ -47,7 +47,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes SablierMerkleLT constructedLT = new SablierMerkleLT( defaults.baseParams(), - lockupTranched, + lockup, defaults.CANCELABLE(), defaults.TRANSFERABLE(), defaults.STREAM_START_TIME_ZERO(), @@ -61,7 +61,7 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedAdmin = users.campaignOwner; assertEq(vars.actualAdmin, vars.expectedAdmin, "admin"); - vars.actualAllowance = dai.allowance(address(constructedLT), address(lockupTranched)); + vars.actualAllowance = dai.allowance(address(constructedLT), address(lockup)); vars.expectedAllowance = MAX_UINT256; assertEq(vars.actualAllowance, vars.expectedAllowance, "allowance"); @@ -85,9 +85,9 @@ contract Constructor_MerkleLT_Integration_Test is MerkleCampaign_Integration_Tes vars.expectedIpfsCID = defaults.IPFS_CID(); assertEq(vars.actualIpfsCID, vars.expectedIpfsCID, "ipfsCID"); - vars.actualLockupTranched = address(constructedLT.LOCKUP_TRANCHED()); - vars.expectedLockupTranched = address(lockupTranched); - assertEq(vars.actualLockupTranched, vars.expectedLockupTranched, "lockupTranched"); + vars.actualLockup = address(constructedLT.LOCKUP()); + vars.expectedLockup = address(lockup); + assertEq(vars.actualLockup, vars.expectedLockup, "lockup"); vars.actualMerkleRoot = constructedLT.MERKLE_ROOT(); vars.expectedMerkleRoot = defaults.MERKLE_ROOT(); diff --git a/test/utils/Assertions.sol b/test/utils/Assertions.sol index d88b24ea9..c0983e6af 100644 --- a/test/utils/Assertions.sol +++ b/test/utils/Assertions.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PRBMathAssertions } from "@prb/math/test/utils/Assertions.sol"; -import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "../../src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupTranched } from "../../src/core/types/DataTypes.sol"; import { MerkleLT } from "../../src/periphery/types/DataTypes.sol"; abstract contract Assertions is PRBMathAssertions { @@ -44,67 +44,8 @@ abstract contract Assertions is PRBMathAssertions { assertEq(address(a), address(b), err); } - /// @dev Compares two {LockupDynamic.Stream} struct entities. - function assertEq(LockupDynamic.StreamLD memory a, LockupDynamic.StreamLD memory b) internal { - assertEq(a.asset, b.asset, "asset"); - assertEq(a.endTime, b.endTime, "endTime"); - assertEq(a.isCancelable, b.isCancelable, "isCancelable"); - assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isStream, b.isStream, "isStream"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); - assertEq(a.recipient, b.recipient, "recipient"); - assertEq(a.segments, b.segments, "segments"); - assertEq(a.sender, b.sender, "sender"); - assertEq(a.startTime, b.startTime, "startTime"); - assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); - } - - /// @dev Compares two {LockupLinear.Stream} struct entities. - function assertEq(LockupLinear.StreamLL memory a, LockupLinear.StreamLL memory b) internal { - assertEq(a.amounts, b.amounts); - assertEq(a.asset, b.asset, "asset"); - assertEq(a.cliffTime, b.cliffTime, "cliffTime"); - assertEq(a.endTime, b.endTime, "endTime"); - assertEq(a.isCancelable, b.isCancelable, "isCancelable"); - assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isStream, b.isStream, "isStream"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); - assertEq(a.recipient, b.recipient, "recipient"); - assertEq(a.sender, b.sender, "sender"); - assertEq(a.startTime, b.startTime, "startTime"); - assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); - } - - /// @dev Compares two {LockupTranched.Stream} struct entities. - function assertEq(LockupTranched.StreamLT memory a, LockupTranched.StreamLT memory b) internal { - assertEq(a.asset, b.asset, "asset"); - assertEq(a.endTime, b.endTime, "endTime"); - assertEq(a.isCancelable, b.isCancelable, "isCancelable"); - assertEq(a.isDepleted, b.isDepleted, "isDepleted"); - assertEq(a.isStream, b.isStream, "isStream"); - assertEq(a.isTransferable, b.isTransferable, "isTransferable"); - assertEq(a.recipient, b.recipient, "recipient"); - assertEq(a.sender, b.sender, "sender"); - assertEq(a.startTime, b.startTime, "startTime"); - assertEq(a.tranches, b.tranches, "tranches"); - assertEq(a.wasCanceled, b.wasCanceled, "wasCanceled"); - } - - /// @dev Compares two {LockupDynamic.Timestamps} struct entities. - function assertEq(LockupDynamic.Timestamps memory a, LockupDynamic.Timestamps memory b) internal { - assertEqUint40(a.end, b.end, "timestamps.end"); - assertEqUint40(a.start, b.start, "timestamps.start"); - } - - /// @dev Compares two {LockupLinear.Timestamps} struct entities. - function assertEq(LockupLinear.Timestamps memory a, LockupLinear.Timestamps memory b) internal { - assertEqUint40(a.cliff, b.cliff, "timestamps.cliff"); - assertEqUint40(a.end, b.end, "timestamps.end"); - assertEqUint40(a.start, b.start, "timestamps.start"); - } - - /// @dev Compares two {LockupTranched.Timestamps} struct entities. - function assertEq(LockupTranched.Timestamps memory a, LockupTranched.Timestamps memory b) internal { + /// @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"); assertEqUint40(a.start, b.start, "timestamps.start"); } diff --git a/test/utils/BaseScript.t.sol b/test/utils/BaseScript.t.sol index 764cb1eef..7302c29eb 100644 --- a/test/utils/BaseScript.t.sol +++ b/test/utils/BaseScript.t.sol @@ -17,7 +17,7 @@ contract BaseScript_Test is StdAssertions { function test_ConstructCreate2Salt() public view { string memory chainId = block.chainid.toString(); - string memory version = "1.2.0"; + string memory version = "1.3.0"; string memory salt = string.concat("ChainID ", chainId, ", Version ", version); bytes32 actualSalt = baseScript.constructCreate2Salt(); diff --git a/test/utils/BatchLockupBuilder.sol b/test/utils/BatchLockupBuilder.sol index 642eb8052..d1828f6a4 100644 --- a/test/utils/BatchLockupBuilder.sol +++ b/test/utils/BatchLockupBuilder.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; +import { Lockup, LockupDynamic, LockupLinear, LockupTranched } from "src/core/types/DataTypes.sol"; import { BatchLockup } from "src/periphery/types/DataTypes.sol"; @@ -21,9 +21,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLD} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithDurationsLD} structs. function fillBatch( - LockupDynamic.CreateWithDurations memory params, + Lockup.CreateWithDurations memory params, + LockupDynamic.SegmentWithDuration[] memory segments, uint256 batchSize ) internal @@ -37,7 +38,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - segments: params.segments, + segments: segments, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -58,9 +59,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLL} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithDurationsLL} structs. function fillBatch( - LockupLinear.CreateWithDurations memory params, + Lockup.CreateWithDurations memory params, + LockupLinear.Durations memory durations, uint256 batchSize ) internal @@ -74,7 +76,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - durations: params.durations, + durations: durations, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -95,9 +97,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithDurationsLT} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithDurationsLT} structs. function fillBatch( - LockupTranched.CreateWithDurations memory params, + Lockup.CreateWithDurations memory params, + LockupTranched.TrancheWithDuration[] memory tranches, uint256 batchSize ) internal @@ -111,7 +114,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - tranches: params.tranches, + tranches: tranches, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -132,9 +135,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLDs} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithTimestampsLDs} structs. function fillBatch( - LockupDynamic.CreateWithTimestamps memory params, + Lockup.CreateWithTimestamps memory params, + LockupDynamic.Segment[] memory segments, uint256 batchSize ) internal @@ -149,7 +153,7 @@ library BatchLockupBuilder { cancelable: params.cancelable, transferable: params.transferable, startTime: params.startTime, - segments: params.segments, + segments: segments, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -170,9 +174,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLL} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithTimestampsLL} structs. function fillBatch( - LockupLinear.CreateWithTimestamps memory params, + Lockup.CreateWithTimestamps memory params, + uint40 cliff, uint256 batchSize ) internal @@ -186,7 +191,7 @@ library BatchLockupBuilder { totalAmount: params.totalAmount, cancelable: params.cancelable, transferable: params.transferable, - timestamps: params.timestamps, + timestamps: Lockup.Timestamps({ start: params.startTime, cliff: cliff, end: params.endTime }), broker: params.broker }); batch = fillBatch(batchSingle, batchSize); @@ -207,9 +212,10 @@ library BatchLockupBuilder { } } - /// @notice Turns the `params` into an array of {BatchLockup.CreateWithTimestampsLT} structs. + /// @notice Turns the inputs into an array of {BatchLockup.CreateWithTimestampsLT} structs. function fillBatch( - LockupTranched.CreateWithTimestamps memory params, + Lockup.CreateWithTimestamps memory params, + LockupTranched.Tranche[] memory tranches, uint256 batchSize ) internal @@ -224,7 +230,7 @@ library BatchLockupBuilder { cancelable: params.cancelable, transferable: params.transferable, startTime: params.startTime, - tranches: params.tranches, + tranches: tranches, broker: params.broker }); batch = fillBatch(batchSingle, batchSize); diff --git a/test/utils/Calculations.sol b/test/utils/Calculations.sol index 58a84b61c..e54ddb137 100644 --- a/test/utils/Calculations.sol +++ b/test/utils/Calculations.sol @@ -18,30 +18,8 @@ abstract contract Calculations { return totalAmount - brokerFeeAmount; } - /// @dev Helper function that replicates the logic of {SablierLockupLinear.streamedAmountOf}. - function calculateStreamedAmount( - uint40 startTime, - uint40 endTime, - uint128 depositAmount - ) - internal - view - returns (uint128) - { - uint40 blockTimestamp = uint40(block.timestamp); - if (blockTimestamp >= endTime) { - return depositAmount; - } - unchecked { - UD60x18 elapsedTime = ud(blockTimestamp - startTime); - UD60x18 totalDuration = ud(endTime - startTime); - UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); - return elapsedTimePercentage.mul(ud(depositAmount)).intoUint128(); - } - } - - /// @dev Replicates the logic of {SablierLockupDynamic._calculateStreamedAmountForMultipleSegments}. - function calculateStreamedAmountForMultipleSegments( + /// @dev Replicates the logic of {VestingMath.calculateLockupDynamicStreamedAmount}. + function calculateLockupDynamicStreamedAmount( LockupDynamic.Segment[] memory segments, uint40 startTime, uint128 depositAmount @@ -86,33 +64,30 @@ abstract contract Calculations { } } - /// @dev Replicates the logic of {SablierLockupDynamic._calculateStreamedAmountForOneSegment}. - function calculateStreamedAmountForOneSegment( - LockupDynamic.Segment memory segment, - uint40 startTime + /// @dev Helper function that replicates the logic of {VestingMath.calculateLockupLinearStreamedAmount}. + function calculateLockupLinearStreamedAmount( + uint40 startTime, + uint40 endTime, + uint128 depositAmount ) internal view returns (uint128) { uint40 blockTimestamp = uint40(block.timestamp); - - if (blockTimestamp >= segment.timestamp) { - return segment.amount; + if (blockTimestamp >= endTime) { + return depositAmount; } unchecked { - SD59x18 elapsedTime = (blockTimestamp - startTime).intoSD59x18(); - SD59x18 totalDuration = (segment.timestamp - startTime).intoSD59x18(); - - SD59x18 elapsedTimePercentage = elapsedTime.div(totalDuration); - SD59x18 multiplier = elapsedTimePercentage.pow(segment.exponent.intoSD59x18()); - SD59x18 streamedAmount = multiplier.mul(segment.amount.intoSD59x18()); - return uint128(streamedAmount.intoUint256()); + UD60x18 elapsedTime = ud(blockTimestamp - startTime); + UD60x18 totalDuration = ud(endTime - startTime); + UD60x18 elapsedTimePercentage = elapsedTime.div(totalDuration); + return elapsedTimePercentage.mul(ud(depositAmount)).intoUint128(); } } - /// @dev Helper function that replicates the logic of {SablierLockupTranched._calculateStreamedAmount}. - function calculateStreamedAmountForTranches( + /// @dev Helper function that replicates the logic of {VestingMath.calculateLockupTranchedStreamedAmount}. + function calculateLockupTranchedStreamedAmount( LockupTranched.Tranche[] memory tranches, uint128 depositAmount ) diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 3ca9e8d16..e057c7fc7 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -32,9 +32,8 @@ contract Defaults is Constants, Merkle { uint40 public constant CLIFF_DURATION = 2500 seconds; uint128 public constant DEPOSIT_AMOUNT = 10_000e18; uint40 public immutable END_TIME; - uint256 public constant MAX_SEGMENT_COUNT = 10_000; + uint256 public constant MAX_COUNT = 10_000; uint40 public immutable MAX_SEGMENT_DURATION; - uint256 public constant MAX_TRANCHE_COUNT = 10_000; uint128 public constant REFUND_AMOUNT = DEPOSIT_AMOUNT - CLIFF_AMOUNT; uint256 public constant SEGMENT_COUNT = 2; uint40 public immutable START_TIME; @@ -86,7 +85,7 @@ contract Defaults is Constants, Merkle { CLIFF_TIME = START_TIME + CLIFF_DURATION; END_TIME = START_TIME + TOTAL_DURATION; EXPIRATION = JULY_1_2024 + 12 weeks; - MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_SEGMENT_COUNT); + MAX_SEGMENT_DURATION = TOTAL_DURATION / uint40(MAX_COUNT); WARP_26_PERCENT = START_TIME + CLIFF_DURATION + 100 seconds; } @@ -137,67 +136,16 @@ contract Defaults is Constants, Merkle { return Lockup.CreateAmounts({ deposit: DEPOSIT_AMOUNT, brokerFee: BROKER_FEE_AMOUNT }); } - function lockupDynamicStream() public view returns (LockupDynamic.StreamLD memory) { - return LockupDynamic.StreamLD({ - amounts: lockupAmounts(), - asset: asset, - endTime: END_TIME, - isCancelable: true, - isDepleted: false, - isStream: true, - isTransferable: true, - recipient: users.recipient, - segments: segments(), - sender: users.sender, - startTime: START_TIME, - wasCanceled: false - }); + function lockupDynamicTimestamps() public view returns (Lockup.Timestamps memory) { + return Lockup.Timestamps({ start: START_TIME, cliff: 0, end: END_TIME }); } - function lockupDynamicTimestamps() public view returns (LockupDynamic.Timestamps memory) { - return LockupDynamic.Timestamps({ start: START_TIME, end: END_TIME }); + function lockupLinearTimestamps() public view returns (Lockup.Timestamps memory) { + return Lockup.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); } - function lockupLinearStream() public view returns (LockupLinear.StreamLL memory) { - return LockupLinear.StreamLL({ - amounts: lockupAmounts(), - asset: asset, - cliffTime: CLIFF_TIME, - endTime: END_TIME, - isCancelable: true, - isTransferable: true, - isDepleted: false, - isStream: true, - recipient: users.recipient, - sender: users.sender, - startTime: START_TIME, - wasCanceled: false - }); - } - - function lockupLinearTimestamps() public view returns (LockupLinear.Timestamps memory) { - return LockupLinear.Timestamps({ start: START_TIME, cliff: CLIFF_TIME, end: END_TIME }); - } - - function lockupTranchedStream() public view returns (LockupTranched.StreamLT memory) { - return LockupTranched.StreamLT({ - amounts: lockupAmounts(), - asset: asset, - endTime: END_TIME, - isCancelable: true, - isDepleted: false, - isStream: true, - isTransferable: true, - recipient: users.recipient, - sender: users.sender, - startTime: START_TIME, - tranches: tranches(), - wasCanceled: false - }); - } - - function lockupTranchedTimestamps() public view returns (LockupTranched.Timestamps memory) { - return LockupTranched.Timestamps({ start: START_TIME, end: END_TIME }); + function lockupTranchedTimestamps() public view returns (Lockup.Timestamps memory) { + return Lockup.Timestamps({ start: START_TIME, cliff: 0, end: END_TIME }); } function segments() public view returns (LockupDynamic.Segment[] memory segments_) { @@ -255,68 +203,26 @@ contract Defaults is Constants, Merkle { CREATE-PARAMS //////////////////////////////////////////////////////////////////////////*/ - function createWithDurationsLD() public view returns (LockupDynamic.CreateWithDurations memory) { - return LockupDynamic.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - segments: segmentsWithDurations(), - broker: broker() - }); - } - - function createWithDurationsBrokerNullLD() public view returns (LockupDynamic.CreateWithDurations memory) { - LockupDynamic.CreateWithDurations memory params = createWithDurationsLD(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; - } - - function createWithDurationsLL() public view returns (LockupLinear.CreateWithDurations memory) { - return LockupLinear.CreateWithDurations({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - durations: durations(), - broker: broker() - }); - } - - function createWithDurationsBrokerNullLL() public view returns (LockupLinear.CreateWithDurations memory) { - LockupLinear.CreateWithDurations memory params = createWithDurationsLL(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; - } - - function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { - return LockupTranched.CreateWithDurations({ + function createWithDurations() public view returns (Lockup.CreateWithDurations memory) { + return Lockup.CreateWithDurations({ sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, asset: asset, cancelable: true, transferable: true, - tranches: tranchesWithDurations(), broker: broker() }); } - function createWithDurationsBrokerNullLT() public view returns (LockupTranched.CreateWithDurations memory) { - LockupTranched.CreateWithDurations memory params = createWithDurationsLT(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; + function createWithDurationsBrokerNull() public view returns (Lockup.CreateWithDurations memory params_) { + params_ = createWithDurations(); + params_.totalAmount = DEPOSIT_AMOUNT; + params_.broker = brokerNull(); } - function createWithTimestampsLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { - return LockupDynamic.CreateWithTimestamps({ + function createWithTimestamps() public view returns (Lockup.CreateWithTimestamps memory) { + return Lockup.CreateWithTimestamps({ sender: users.sender, recipient: users.recipient, totalAmount: TOTAL_AMOUNT, @@ -324,57 +230,15 @@ contract Defaults is Constants, Merkle { cancelable: true, transferable: true, startTime: START_TIME, - segments: segments(), - broker: broker() - }); - } - - function createWithTimestampsBrokerNullLD() public view returns (LockupDynamic.CreateWithTimestamps memory) { - LockupDynamic.CreateWithTimestamps memory params = createWithTimestampsLD(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; - } - - function createWithTimestampsLL() public view returns (LockupLinear.CreateWithTimestamps memory) { - return LockupLinear.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - timestamps: lockupLinearTimestamps(), - broker: broker() - }); - } - - function createWithTimestampsBrokerNullLL() public view returns (LockupLinear.CreateWithTimestamps memory) { - LockupLinear.CreateWithTimestamps memory params = createWithTimestampsLL(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; - } - - function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { - return LockupTranched.CreateWithTimestamps({ - sender: users.sender, - recipient: users.recipient, - totalAmount: TOTAL_AMOUNT, - asset: asset, - cancelable: true, - transferable: true, - startTime: START_TIME, - tranches: tranches(), + endTime: END_TIME, broker: broker() }); } - function createWithTimestampsBrokerNullLT() public view returns (LockupTranched.CreateWithTimestamps memory) { - LockupTranched.CreateWithTimestamps memory params = createWithTimestampsLT(); - params.totalAmount = DEPOSIT_AMOUNT; - params.broker = brokerNull(); - return params; + function createWithTimestampsBrokerNull() public view returns (Lockup.CreateWithTimestamps memory params_) { + params_ = createWithTimestamps(); + params_.totalAmount = DEPOSIT_AMOUNT; + params_.broker = brokerNull(); } /*////////////////////////////////////////////////////////////////////////// @@ -387,17 +251,17 @@ contract Defaults is Constants, Merkle { /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLD} parameters. function batchCreateWithDurationsLD() public view returns (BatchLockup.CreateWithDurationsLD[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLD(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNull(), segmentsWithDurations(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLL} parameters. function batchCreateWithDurationsLL() public view returns (BatchLockup.CreateWithDurationsLL[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLL(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNull(), durations(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithDurationsLT} parameters. function batchCreateWithDurationsLT() public view returns (BatchLockup.CreateWithDurationsLT[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNullLT(), BATCH_SIZE); + batch = BatchLockupBuilder.fillBatch(createWithDurationsBrokerNull(), tranchesWithDurations(), BATCH_SIZE); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLD} parameters. @@ -411,7 +275,7 @@ contract Defaults is Constants, Merkle { view returns (BatchLockup.CreateWithTimestampsLD[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLD(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNull(), segments(), batchSize); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLL} parameters. @@ -425,7 +289,7 @@ contract Defaults is Constants, Merkle { view returns (BatchLockup.CreateWithTimestampsLL[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLL(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNull(), CLIFF_TIME, batchSize); } /// @dev Returns a default-size batch of {BatchLockup.CreateWithTimestampsLT} parameters. @@ -439,7 +303,7 @@ contract Defaults is Constants, Merkle { view returns (BatchLockup.CreateWithTimestampsLT[] memory batch) { - batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNullLT(), batchSize); + batch = BatchLockupBuilder.fillBatch(createWithTimestampsBrokerNull(), tranches(), batchSize); } /*////////////////////////////////////////////////////////////////////////// diff --git a/test/utils/DeployOptimized.sol b/test/utils/DeployOptimized.sol index a39ed11e6..199786cdf 100644 --- a/test/utils/DeployOptimized.sol +++ b/test/utils/DeployOptimized.sol @@ -1,66 +1,44 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22 <0.9.0; +import { CommonBase } from "forge-std/src/Base.sol"; import { StdCheats } from "forge-std/src/StdCheats.sol"; import { ILockupNFTDescriptor } from "../../src/core/interfaces/ILockupNFTDescriptor.sol"; -import { ISablierLockupDynamic } from "../../src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "../../src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "../../src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockup } from "../../src/core/interfaces/ISablierLockup.sol"; import { ISablierBatchLockup } from "../../src/periphery/interfaces/ISablierBatchLockup.sol"; import { ISablierMerkleFactory } from "../../src/periphery/interfaces/ISablierMerkleFactory.sol"; -abstract contract DeployOptimized is StdCheats { +abstract contract DeployOptimized is StdCheats, CommonBase { /*////////////////////////////////////////////////////////////////////////// CORE //////////////////////////////////////////////////////////////////////////*/ - /// @dev Deploys {SablierLockupDynamic} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupDynamic( - address initialAdmin, - ILockupNFTDescriptor nftDescriptor_, - uint256 maxSegmentCount - ) - internal - returns (ISablierLockupDynamic) - { - return ISablierLockupDynamic( - deployCode( - "out-optimized/SablierLockupDynamic.sol/SablierLockupDynamic.json", - abi.encode(initialAdmin, address(nftDescriptor_), maxSegmentCount) - ) - ); + /// @dev Deploys the optimized {Helpers} and {VestingMath} libraries and assign them to linked addresses. + function deployOptimizedLibraries() internal { + address helpers = deployCode("out-optimized/Helpers.sol/Helpers.json"); + address vestingMath = deployCode("out-optimized/VestingMath.sol/VestingMath.json"); + vm.etch(0x7715bE116061E014Bb721b46Dc78Dd57C91FDF9b, helpers.code); + vm.etch(0x26F9d826BDed47Fc472526aE8095B75ac336963C, vestingMath.code); } - /// @dev Deploys {SablierLockupLinear} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupLinear( - address initialAdmin, - ILockupNFTDescriptor nftDescriptor_ - ) - internal - returns (ISablierLockupLinear) - { - return ISablierLockupLinear( - deployCode( - "out-optimized/SablierLockupLinear.sol/SablierLockupLinear.json", - abi.encode(initialAdmin, address(nftDescriptor_)) - ) - ); - } - - /// @dev Deploys {SablierLockupTranched} from an optimized source compiled with `--via-ir`. - function deployOptimizedLockupTranched( + /// @dev Deploys {SablierLockup} from an optimized source compiled with `--via-ir`. + function deployOptimizedLockup( address initialAdmin, ILockupNFTDescriptor nftDescriptor_, - uint256 maxTrancheCount + uint256 maxCount ) internal - returns (ISablierLockupTranched) + returns (ISablierLockup) { - return ISablierLockupTranched( + // Deploy the libraries. + deployOptimizedLibraries(); + + // Deploy the Lockup contract. + return ISablierLockup( deployCode( - "out-optimized/SablierLockupTranched.sol/SablierLockupTranched.json", - abi.encode(initialAdmin, address(nftDescriptor_), maxTrancheCount) + "out-optimized/SablierLockup.sol/SablierLockup.json", + abi.encode(initialAdmin, address(nftDescriptor_), maxCount) ) ); } @@ -73,26 +51,16 @@ abstract contract DeployOptimized is StdCheats { /// @notice Deploys all Lockup contracts from an optimized source compiled with `--via-ir` in the following order: /// /// 1. {LockupNFTDescriptor} - /// 2. {SablierLockupDynamic} - /// 3. {SablierLockupLinear} - /// 4. {SablierLockupTranched} + /// 2. {SablierLockup} function deployOptimizedCore( address initialAdmin, - uint256 maxSegmentCount, - uint256 maxTrancheCount + uint256 maxCount ) internal - returns ( - ILockupNFTDescriptor nftDescriptor_, - ISablierLockupDynamic lockupDynamic_, - ISablierLockupLinear lockupLinear_, - ISablierLockupTranched lockupTranched_ - ) + returns (ILockupNFTDescriptor nftDescriptor_, ISablierLockup lockup_) { nftDescriptor_ = deployOptimizedNFTDescriptor(); - lockupDynamic_ = deployOptimizedLockupDynamic(initialAdmin, nftDescriptor_, maxSegmentCount); - lockupLinear_ = deployOptimizedLockupLinear(initialAdmin, nftDescriptor_); - lockupTranched_ = deployOptimizedLockupTranched(initialAdmin, nftDescriptor_, maxTrancheCount); + lockup_ = deployOptimizedLockup(initialAdmin, nftDescriptor_, maxCount); } /*////////////////////////////////////////////////////////////////////////// @@ -129,28 +97,22 @@ abstract contract DeployOptimized is StdCheats { /// @notice Deploys all Lockup and Periphery contracts from an optimized source in the following order: /// /// 1. {LockupNFTDescriptor} - /// 2. {SablierLockupDynamic} - /// 3. {SablierLockupLinear} - /// 4. {SablierLockupTranched} + /// 2. {SablierLockup} /// 5. {SablierBatchLockup} /// 6. {SablierMerkleFactory} function deployOptimizedProtocol( address initialAdmin, - uint256 maxSegmentCount, - uint256 maxTrancheCount + uint256 maxCount ) internal returns ( ILockupNFTDescriptor nftDescriptor_, - ISablierLockupDynamic lockupDynamic_, - ISablierLockupLinear lockupLinear_, - ISablierLockupTranched lockupTranched_, + ISablierLockup lockup_, ISablierBatchLockup batchLockup_, ISablierMerkleFactory merkleFactory_ ) { - (nftDescriptor_, lockupDynamic_, lockupLinear_, lockupTranched_) = - deployOptimizedCore(initialAdmin, maxSegmentCount, maxTrancheCount); + (nftDescriptor_, lockup_) = deployOptimizedCore(initialAdmin, maxCount); (batchLockup_, merkleFactory_) = deployOptimizedPeriphery(initialAdmin); } } diff --git a/test/utils/Modifiers.sol b/test/utils/Modifiers.sol index 190f7f6d9..c0bb9c384 100644 --- a/test/utils/Modifiers.sol +++ b/test/utils/Modifiers.sol @@ -83,6 +83,10 @@ abstract contract Modifiers is Fuzzers { _; } + modifier whenCallerAuthorizedForAllStreams() virtual { + _; + } + modifier whenCallerRecipient() { resetPrank({ msgSender: users.recipient }); _; diff --git a/test/utils/Precompiles.t.sol b/test/utils/Precompiles.t.sol index 40355414c..f4ed7e50a 100644 --- a/test/utils/Precompiles.t.sol +++ b/test/utils/Precompiles.t.sol @@ -4,9 +4,7 @@ pragma solidity >=0.8.22 <0.9.0; import { Precompiles } from "precompiles/Precompiles.sol"; import { LibString } from "solady/src/utils/LibString.sol"; import { ILockupNFTDescriptor } from "src/core/interfaces/ILockupNFTDescriptor.sol"; -import { ISablierLockupDynamic } from "src/core/interfaces/ISablierLockupDynamic.sol"; -import { ISablierLockupLinear } from "src/core/interfaces/ISablierLockupLinear.sol"; -import { ISablierLockupTranched } from "src/core/interfaces/ISablierLockupTranched.sol"; +import { ISablierLockup } from "src/core/interfaces/ISablierLockup.sol"; import { ISablierBatchLockup } from "src/periphery/interfaces/ISablierBatchLockup.sol"; import { ISablierMerkleFactory } from "src/periphery/interfaces/ISablierMerkleFactory.sol"; import { Base_Test } from "./../Base.t.sol"; @@ -26,30 +24,11 @@ contract Precompiles_Test is Base_Test { CORE //////////////////////////////////////////////////////////////////////////*/ - function test_DeployLockupDynamic() external onlyTestOptimizedProfile { - address actualLockupDynamic = address(precompiles.deployLockupDynamic(users.admin, nftDescriptor)); - address expectedLockupDynamic = - address(deployOptimizedLockupDynamic(users.admin, nftDescriptor, precompiles.MAX_SEGMENT_COUNT())); - bytes memory expectedLockupDynamicCode = - adjustBytecode(expectedLockupDynamic.code, expectedLockupDynamic, actualLockupDynamic); - assertEq(actualLockupDynamic.code, expectedLockupDynamicCode, "bytecodes mismatch"); - } - - function test_DeployLockupLinear() external onlyTestOptimizedProfile { - address actualLockupLinear = address(precompiles.deployLockupLinear(users.admin, nftDescriptor)); - address expectedLockupLinear = address(deployOptimizedLockupLinear(users.admin, nftDescriptor)); - bytes memory expectedLockupLinearCode = - adjustBytecode(expectedLockupLinear.code, expectedLockupLinear, actualLockupLinear); - assertEq(actualLockupLinear.code, expectedLockupLinearCode, "bytecodes mismatch"); - } - - function test_DeployLockupTranched() external onlyTestOptimizedProfile { - address actualLockupTranched = address(precompiles.deployLockupTranched(users.admin, nftDescriptor)); - address expectedLockupTranched = - address(deployOptimizedLockupTranched(users.admin, nftDescriptor, precompiles.MAX_TRANCHE_COUNT())); - bytes memory expectedLockupTranchedCode = - adjustBytecode(expectedLockupTranched.code, expectedLockupTranched, actualLockupTranched); - assertEq(actualLockupTranched.code, expectedLockupTranchedCode, "bytecodes mismatch"); + function test_DeployLockup() external onlyTestOptimizedProfile { + address actualLockup = address(precompiles.deployLockup(users.admin, nftDescriptor)); + address expectedLockup = address(deployOptimizedLockup(users.admin, nftDescriptor, precompiles.MAX_COUNT())); + bytes memory expectedLockupCode = adjustBytecode(expectedLockup.code, expectedLockup, actualLockup); + assertEq(actualLockup.code, expectedLockupCode, "bytecodes mismatch"); } function test_DeployNFTDescriptor() external onlyTestOptimizedProfile { @@ -59,35 +38,15 @@ contract Precompiles_Test is Base_Test { } function test_DeployCore() external onlyTestOptimizedProfile { - ( - ILockupNFTDescriptor actualNFTDescriptor, - ISablierLockupDynamic actualLockupDynamic, - ISablierLockupLinear actualLockupLinear, - ISablierLockupTranched actualLockupTranched - ) = precompiles.deployCore(users.admin); - - ( - ILockupNFTDescriptor expectedNFTDescriptor, - ISablierLockupDynamic expectedLockupDynamic, - ISablierLockupLinear expectedLockupLinear, - ISablierLockupTranched expectedLockupTranched - ) = deployOptimizedCore(users.admin, precompiles.MAX_SEGMENT_COUNT(), precompiles.MAX_TRANCHE_COUNT()); - - bytes memory expectedLockupDynamicCode = adjustBytecode( - address(expectedLockupDynamic).code, address(expectedLockupDynamic), address(actualLockupDynamic) - ); + (ILockupNFTDescriptor actualNFTDescriptor, ISablierLockup actualLockup) = precompiles.deployCore(users.admin); - bytes memory expectedLockupLinearCode = adjustBytecode( - address(expectedLockupLinear).code, address(expectedLockupLinear), address(actualLockupLinear) - ); + (ILockupNFTDescriptor expectedNFTDescriptor, ISablierLockup expectedLockup) = + deployOptimizedCore(users.admin, precompiles.MAX_COUNT()); - bytes memory expectedLockupTranchedCode = adjustBytecode( - address(expectedLockupTranched).code, address(expectedLockupTranched), address(actualLockupTranched) - ); + bytes memory expectedLockupCode = + adjustBytecode(address(expectedLockup).code, address(expectedLockup), address(actualLockup)); - assertEq(address(actualLockupDynamic).code, expectedLockupDynamicCode, "bytecodes mismatch"); - assertEq(address(actualLockupLinear).code, expectedLockupLinearCode, "bytecodes mismatch"); - assertEq(address(actualLockupTranched).code, expectedLockupTranchedCode, "bytecodes mismatch"); + assertEq(address(actualLockup).code, expectedLockupCode, "bytecodes mismatch"); assertEq(address(actualNFTDescriptor).code, address(expectedNFTDescriptor).code, "bytecodes mismatch"); }