diff --git a/.gas-snapshot b/.gas-snapshot
index 40cb347b3..1ecfb10fc 100644
--- a/.gas-snapshot
+++ b/.gas-snapshot
@@ -1,302 +1,413 @@
-Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 82944)
-Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 70040)
-Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 83160)
-Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 70299)
-CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 825327)
-CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6249)
-CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1189888, ~: 1194666)
-CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 558971)
-CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6313)
-CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 792602, ~: 793724)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerRecipient() (gas: 388606)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderDoesNotImplementHook() (gas: 374225)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderNotContract() (gas: 100002)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderReentrancy() (gas: 376293)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderReverts() (gas: 374725)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerSender() (gas: 383652)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientDoesNotImplementHook() (gas: 369169)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientNotContract() (gas: 97284)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientReentrancy() (gas: 371361)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientReverts() (gas: 369748)
-Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76354)
-Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_CallerRecipient(uint256,uint128) (runs: 50, μ: 431864, ~: 433061)
-Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_CallerSender(uint256,uint128) (runs: 50, μ: 451169, ~: 452317)
-Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76922, ~: 77115)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerRecipient() (gas: 272486)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderDoesNotImplementHook() (gas: 258004)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderNotContract() (gas: 80382)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderReentrancy() (gas: 260080)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerRecipient_SenderReverts() (gas: 258504)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerSender() (gas: 267507)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientDoesNotImplementHook() (gas: 252935)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientNotContract() (gas: 77660)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientReentrancy() (gas: 255135)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_CallerSender_RecipientReverts() (gas: 253514)
-Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76412)
-Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_CallerRecipient(uint256,uint128) (runs: 50, μ: 288908, ~: 288864)
-Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_CallerSender(uint256,uint128) (runs: 50, μ: 308395, ~: 308310)
-Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76952, ~: 77027)
-ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 317052)
-ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 244406)
-Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5301627)
-Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 4113621)
-CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 376989)
-CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4097904, ~: 3555562)
-CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 282804)
-CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 283400, ~: 283496)
-CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 365507)
-CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 372340)
-CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3980454, ~: 3933203)
-CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 278259)
-CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 285026)
-CreateWithRange_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithRange(address,(address,address,uint128,address,bool,(uint40,uint40,uint40),(address,uint256)),uint256) (runs: 50, μ: 370254, ~: 369049)
+Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87602)
+Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78186)
+Burn_LockupDynamic_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78195)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79400)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11325)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 90312)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14289)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19525)
+Burn_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19561)
+Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerApprovedOperator() (gas: 87770)
+Burn_LockupLinear_Integration_Concrete_Test:test_Burn_CallerNFTOwner() (gas: 78343)
+Burn_LockupLinear_Integration_Concrete_Test:test_Burn_NonTransferableNFT() (gas: 78352)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 79539)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11311)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 81013)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusPending() (gas: 14275)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 19511)
+Burn_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusStreaming() (gas: 19547)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple() (gas: 833554)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6271)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32346)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 859532)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12362)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78556)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 341289)
+CancelMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 946037)
+CancelMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 1197185, ~: 1201634)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple() (gas: 565501)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_CancelMultiple_ArrayCountZero() (gas: 6294)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsCold() (gas: 32494)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStreamsNotCancelable() (gas: 572744)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 12391)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 78577)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsCold() (gas: 245380)
+CancelMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStreamsNotCancelable() (gas: 657233)
+CancelMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_CancelMultiple(uint256,uint40) (runs: 50, μ: 796979, ~: 798072)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel() (gas: 386274)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 371426)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 97176)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 373617)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 371993)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76401)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11321)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87398)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68055)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 27022)
+Cancel_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 261520)
+Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 453882, ~: 455045)
+Cancel_LockupDynamic_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 76949, ~: 77128)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel() (gas: 269481)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientDoesNotImplementHook() (gas: 254609)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientNotContract() (gas: 77523)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReentrancy() (gas: 256789)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_RecipientReverts() (gas: 255176)
+Cancel_LockupLinear_Integration_Concrete_Test:test_Cancel_StatusPending() (gas: 76441)
+Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11307)
+Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 78102)
+Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68238)
+Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 27130)
+Cancel_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 185647)
+Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel(uint256,uint128) (runs: 50, μ: 310112, ~: 310054)
+Cancel_LockupLinear_Integration_Fuzz_Test:testFuzz_Cancel_StatusPending(uint256) (runs: 50, μ: 77003, ~: 77168)
+ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 319728)
+ClaimProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18907)
+ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ClaimProtocolRevenues() (gas: 246456)
+ClaimProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolRevenuesZero() (gas: 18915)
+Constructor_LockupDynamic_Integration_Concrete_Test:test_Constructor() (gas: 5384679)
+Constructor_LockupLinear_Integration_Concrete_Test:test_Constructor() (gas: 4190426)
+CreateWithDeltas_LockupDynamic_Integration_Concrete_Test:test_CreateWithDeltas() (gas: 380621)
+CreateWithDeltas_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithDeltas((uint128,uint64,uint40)[]) (runs: 50, μ: 4100590, ~: 3557971)
+CreateWithDurations_LockupLinear_Integration_Concrete_Test:test_CreateWithDurations() (gas: 287592)
+CreateWithDurations_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithDurations((uint40,uint40)) (runs: 50, μ: 286543, ~: 286543)
+CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones() (gas: 370968)
+CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_CreateWithMilestones_AssetMissingReturnValue() (gas: 377756)
+CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 47537)
+CreateWithMilestones_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 58079)
+CreateWithMilestones_LockupDynamic_Integration_Fuzz_Test:testFuzz_CreateWithMilestones(address,(address,uint40,bool,bool,address,uint128,address,(address,uint256),(uint128,uint64,uint40)[]),uint256) (runs: 50, μ: 3951267, ~: 3991455)
+CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange() (gas: 282990)
+CreateWithRange_LockupLinear_Integration_Concrete_Test:test_CreateWithRange_AssetMissingReturnValue() (gas: 289757)
+CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_EndTimeNotInTheFuture() (gas: 41154)
+CreateWithRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_ProtocolFeeTooHigh() (gas: 51749)
+CreateWithRange_LockupLinear_Integration_Fuzz_Test:testFuzz_CreateWithRange(address,(address,address,uint128,address,bool,bool,(uint40,uint40,uint40),(address,uint256)),uint256) (runs: 50, μ: 374036, ~: 389079)
FlashFee_Integration_Concrete_Test:test_FlashFee() (gas: 50968)
-FlashFee_Integration_Fuzz_Test:testFuzz_FlashFee(uint256,uint256) (runs: 50, μ: 51825, ~: 52081)
-FlashFee_Unit_Concrete_Test:test_FlashFee() (gas: 38333)
-FlashFee_Unit_Concrete_Test:test_FlashFee_Zero() (gas: 7703)
+FlashFee_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 18626)
+FlashFee_Integration_Fuzz_Test:testFuzz_FlashFee(uint256,uint256) (runs: 50, μ: 51818, ~: 52081)
FlashLoanFunction_Integration_Concrete_Test:test_FlashLoan() (gas: 402140)
-FlashLoanFunction_Integration_Fuzz_Test:testFuzz_FlashLoanFunction(uint256,uint128,bytes) (runs: 50, μ: 403379, ~: 407116)
-GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 12968)
-GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 304908)
-GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 232195)
-GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 232745)
-GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 307727)
-GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 235010)
-GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 307525)
-GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 234884)
-GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 306932)
-GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 235033)
-GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 12630)
-GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 12654)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 360020)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 329847)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 335055)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 335069)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 374400)
-GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 396242)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 285519)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 255146)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 260354)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 260368)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 296443)
-GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 318241)
-GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 312411)
-GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 304626)
-GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 231929)
-GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 307832)
-GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 235141)
-GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 275361)
-GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 51468)
-GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 34457)
-GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 38946)
-GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 381641)
-GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 333074)
-GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 384690, ~: 385328)
-GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 334801, ~: 334953)
-GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 279721)
-GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 260373)
-GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 282907, ~: 282863)
-GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 262086, ~: 262252)
-IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 510191)
-IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 333252)
-IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 324518)
-IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 368272)
-IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 260725)
-IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 251874)
-IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 373153)
-IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 359721)
-IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 327808)
-IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 333578)
-IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 349896)
-IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 295291)
-IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 285322)
-IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 255209)
-IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 261091)
-IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 261670)
-IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 359126)
-IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 323942)
-IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 284667)
-IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 251283)
-IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 324260)
-IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8505)
-IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 251601)
-IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8548)
-IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 372669)
-IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 359213)
-IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 327267)
-IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 333145)
-IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 349315)
-IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 294776)
-IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 284776)
-IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 254630)
-IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 260630)
-IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 261051)
+FlashLoanFunction_Integration_Concrete_Test:test_RevertGiven_AssetNotFlashLoanable() (gas: 21603)
+FlashLoanFunction_Integration_Fuzz_Test:testFuzz_FlashLoanFunction(uint256,uint128,bytes) (runs: 50, μ: 402214, ~: 406940)
+GenerateAccentColor_Integration_Concrete_Test:test_GenerateAccentColor() (gas: 13215)
+GetAsset_LockupDynamic_Integration_Concrete_Test:test_GetAsset() (gas: 307759)
+GetAsset_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12049)
+GetAsset_LockupLinear_Integration_Concrete_Test:test_GetAsset() (gas: 234467)
+GetAsset_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12035)
+GetCliffTime_LockupLinear_Integration_Concrete_Test:test_GetCliffTime() (gas: 234951)
+GetCliffTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11392)
+GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 310556)
+GetDepositedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11682)
+GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_GetDepositedAmount() (gas: 237238)
+GetDepositedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11678)
+GetEndTime_LockupDynamic_Integration_Concrete_Test:test_GetEndTime() (gas: 310354)
+GetEndTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11538)
+GetEndTime_LockupLinear_Integration_Concrete_Test:test_GetEndTime() (gas: 237090)
+GetEndTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11546)
+GetRange_LockupDynamic_Integration_Concrete_Test:test_GetRange() (gas: 309780)
+GetRange_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13125)
+GetRange_LockupLinear_Integration_Concrete_Test:test_GetRange() (gas: 237308)
+GetRange_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13308)
+GetRecipient_LockupDynamic_Integration_Concrete_Test:test_GetRecipient() (gas: 12585)
+GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72494)
+GetRecipient_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 10989)
+GetRecipient_LockupLinear_Integration_Concrete_Test:test_GetRecipient() (gas: 12565)
+GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 72651)
+GetRecipient_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 10993)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 362837)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 332698)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 337906)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 337920)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 377552)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 399360)
+GetRefundedAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12045)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusDepleted() (gas: 287754)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusPending() (gas: 257418)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusSettled() (gas: 262626)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StatusStreaming() (gas: 262640)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusCanceled() (gas: 298987)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_GetRefundedAmount_StreamHasBeenCanceled_StatusDepleted() (gas: 320748)
+GetRefundedAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12031)
+GetSegments_LockupDynamic_Integration_Concrete_Test:test_GetSegments() (gas: 315258)
+GetSegments_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 13758)
+GetSender_LockupDynamic_Integration_Concrete_Test:test_GetSender() (gas: 307477)
+GetSender_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11814)
+GetSender_LockupLinear_Integration_Concrete_Test:test_GetSender() (gas: 234201)
+GetSender_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11816)
+GetStartTime_LockupDynamic_Integration_Concrete_Test:test_GetStartTime() (gas: 310683)
+GetStartTime_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11823)
+GetStartTime_LockupLinear_Integration_Concrete_Test:test_GetStartTime() (gas: 237413)
+GetStartTime_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11831)
+GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream() (gas: 278720)
+GetStream_LockupDynamic_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 52024)
+GetStream_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 15544)
+GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream() (gas: 34920)
+GetStream_LockupLinear_Integration_Concrete_Test:test_GetStream_StatusSettled() (gas: 39431)
+GetStream_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14299)
+GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 384696)
+GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 335880)
+GetWithdrawnAmount_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12012)
+GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 387706, ~: 388207)
+GetWithdrawnAmount_LockupDynamic_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 337569, ~: 337804)
+GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount() (gas: 282118)
+GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_GetWithdrawnAmount_NoPreviousWithdrawals() (gas: 262600)
+GetWithdrawnAmount_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11998)
+GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount(uint256,uint128) (runs: 50, μ: 285304, ~: 285260)
+GetWithdrawnAmount_LockupLinear_Integration_Fuzz_Test:testFuzz_GetWithdrawnAmount_NoPreviousWithdrawals(uint256) (runs: 50, μ: 264330, ~: 264524)
+IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable() (gas: 515865)
+IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 336103)
+IsCancelable_LockupDynamic_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 327347)
+IsCancelable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11239)
+IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable() (gas: 372779)
+IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_Cold() (gas: 262975)
+IsCancelable_LockupLinear_Integration_Concrete_Test:test_IsCancelable_StreamCancelable() (gas: 254102)
+IsCancelable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11263)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 376250)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 362483)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 330604)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 336374)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 352684)
+IsCold_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11525)
+IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusCanceled() (gas: 297736)
+IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusDepleted() (gas: 287458)
+IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusPending() (gas: 257382)
+IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusSettled() (gas: 263264)
+IsCold_LockupLinear_Integration_Concrete_Test:test_IsCold_StatusStreaming() (gas: 263799)
+IsCold_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11568)
+IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted() (gas: 361921)
+IsDepleted_LockupDynamic_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 326771)
+IsDepleted_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11191)
+IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted() (gas: 286858)
+IsDepleted_LockupLinear_Integration_Concrete_Test:test_IsDepleted_StreamNotDepleted() (gas: 253511)
+IsDepleted_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11212)
+IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream() (gas: 327111)
+IsStream_LockupDynamic_Integration_Concrete_Test:test_IsStream_Null() (gas: 8527)
+IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream() (gas: 253873)
+IsStream_LockupLinear_Integration_Concrete_Test:test_IsStream_Null() (gas: 8570)
+IsTransferable_LockupDynamic_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 327273)
+IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11674)
+IsTransferable_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 515864)
+IsTransferable_LockupLinear_Integration_Concrete_Test:test_IsTransferable_Stream() (gas: 254057)
+IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11739)
+IsTransferable_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamTransferNotEnabled() (gas: 372834)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 375788)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 361997)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 330041)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 335985)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 352169)
+IsWarm_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11085)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusCanceled() (gas: 297243)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusDepleted() (gas: 286934)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusPending() (gas: 256781)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusSettled() (gas: 262847)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_IsWarm_StatusStreaming() (gas: 263246)
+IsWarm_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11106)
MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupDynamic() (gas: 16959)
-MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16777)
+MapSymbol_Integration_Concrete_Test:test_MapSymbol_LockupLinear() (gas: 16733)
+MapSymbol_Integration_Concrete_Test:test_RevertGiven_UnknownNFT() (gas: 1039753)
MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan() (gas: 178987)
MaxFlashLoan_Integration_Concrete_Test:test_MaxFlashLoan_AssetNotFlashLoanable() (gas: 15248)
-MaxFlashLoan_Integration_Fuzz_Test:testFuzz_MaxFlashLoan(uint256) (runs: 50, μ: 178980, ~: 178996)
+MaxFlashLoan_Integration_Fuzz_Test:testFuzz_MaxFlashLoan(uint256) (runs: 50, μ: 178984, ~: 179002)
ProtocolFees_Integration_Concrete_Test:test_ProtocolFees() (gas: 41254)
ProtocolFees_Integration_Concrete_Test:test_ProtocolFees_ProtocolFeeNotSet() (gas: 9943)
-ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 317399)
+ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 320228)
ProtocolRevenues_LockupDynamic_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10125)
-ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 244717)
-ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10133)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 359163)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 333012)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 333005)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 339838)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 372545)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 395772)
-RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 517772)
-RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 46751, ~: 30742)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 284678)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 260318)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 260441)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 261928)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 294604)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 317787)
-RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 375836)
-RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30756, ~: 30880)
-Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 685980)
-Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 678983)
-Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 289776)
-Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 684192)
-Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 679634)
-Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 474755)
-Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 467756)
-Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 217209)
-Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 473025)
-Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 468407)
+ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues() (gas: 246945)
+ProtocolRevenues_LockupLinear_Integration_Concrete_Test:test_ProtocolRevenues_ProtocolRevenuesZero() (gas: 10111)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 361958)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 335841)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 335834)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 342703)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375697)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 398868)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 523491)
+RefundableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11099)
+RefundableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 42776, ~: 30742)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusDepleted() (gas: 286891)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusPending() (gas: 262568)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusSettled() (gas: 262691)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StatusStreaming() (gas: 264178)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297148)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 320272)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RefundableAmountOf_StreamNotCancelable() (gas: 380410)
+RefundableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11110)
+RefundableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_RefundableAmountOf(uint256) (runs: 50, μ: 30748, ~: 30858)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce() (gas: 694498)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 687573)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 292606)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 692702)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 688180)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11567)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 87385)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68359)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24692)
+Renounce_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 649846)
+Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce() (gas: 481553)
+Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientDoesNotImplementHook() (gas: 474596)
+Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientNotContract() (gas: 219349)
+Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReentrancy() (gas: 479733)
+Renounce_LockupLinear_Integration_Concrete_Test:test_Renounce_RecipientReverts() (gas: 475203)
+Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11575)
+Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusCanceled() (gas: 78108)
+Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusDepleted() (gas: 68564)
+Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StatusSettled() (gas: 24822)
+Renounce_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotCancelable() (gas: 436925)
SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals() (gas: 12117)
SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_DecimalsNotImplemented() (gas: 10852)
SafeAssetDecimals_Integration_Concrete_Test:test_SafeAssetDecimals_EOA() (gas: 11625)
SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol() (gas: 18550)
-SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 59605)
+SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_Bytes32() (gas: 62214)
SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_EOA() (gas: 13222)
-SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 622290)
+SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_LongSymbol() (gas: 624896)
SafeAssetSymbol_Integration_Concrete_Test:test_SafeAssetSymbol_SymbolNotImplemented() (gas: 12399)
-SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 309153)
+SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 311753)
SetComptroller_LockupDynamic_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23283)
-SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 309238)
-SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23368)
-SetFlashFee_Integration_Concrete_Test:test_SetFlashFee() (gas: 44409)
-SetFlashFee_Integration_Concrete_Test:test_SetFlashFee_SameFee() (gas: 21981)
-SetFlashFee_Integration_Fuzz_Test:testFuzz_SetFlashFee(uint256) (runs: 50, μ: 37754, ~: 39448)
-SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6558206)
-SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2259730)
-SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6557611)
-SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2259015)
+SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_NewComptroller() (gas: 311750)
+SetComptroller_LockupLinear_Integration_Concrete_Test:test_SetComptroller_SameComptroller() (gas: 23280)
+SetFlashFee_Integration_Fuzz_Test:testFuzz_SetFlashFee(uint256) (runs: 50, μ: 37740, ~: 39448)
+SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6551561)
+SetNFTDescriptor_LockupDynamic_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2258131)
+SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_NewNFTDescriptor() (gas: 6550197)
+SetNFTDescriptor_LockupLinear_Integration_Concrete_Test:test_SetNFTDescriptor_SameNFTDescriptor() (gas: 2256602)
SetProtocolFee_Integration_Concrete_Test:test_SetProtocolFee() (gas: 47804)
SetProtocolFee_Integration_Concrete_Test:test_SetProtocolFee_SameFee() (gas: 22636)
-SetProtocolFee_Integration_Fuzz_Test:testFuzz_SetProtocolFee(uint256) (runs: 50, μ: 43131, ~: 43074)
-StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 349974)
-StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 359860)
-StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 333790)
-StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 327889)
-StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 373305)
-StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 261080)
-StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 285393)
-StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 261245)
-StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 255222)
-StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 295382)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestone1st() (gas: 45895)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestoneNot1st() (gas: 50716)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 254129)
+SetProtocolFee_Integration_Fuzz_Test:testFuzz_SetProtocolFee(uint256) (runs: 50, μ: 43144, ~: 43219)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11651)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf() (gas: 352806)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 362622)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 336586)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 330685)
+StatusOf_LockupDynamic_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 376424)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11681)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf() (gas: 263297)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_AssetsFullyWithdrawn() (gas: 287573)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_RefundableAmountNotZero() (gas: 263462)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StartTimeInTheFuture() (gas: 257439)
+StatusOf_LockupLinear_Integration_Concrete_Test:test_StatusOf_StreamCanceled() (gas: 297893)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11319)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestone1st() (gas: 45931)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_CurrentMilestoneNot1st() (gas: 50774)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_OneSegment() (gas: 257024)
StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInTheFuture() (gas: 20230)
StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StartTimeInThePresent() (gas: 25593)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68727)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68693)
StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20360)
StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26624)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87497)
-StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116148)
-StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3521477, ~: 3128962)
-StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3965669, ~: 4101937)
-StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 274310, ~: 268277)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 26302)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 17313)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 27143)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68936)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20327)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26710)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 78272)
-StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 106846)
-StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 232343, ~: 233061)
-StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 27377, ~: 27626)
-StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 237382, ~: 239360)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 87798)
+StreamedAmountOf_LockupDynamic_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 116415)
+StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation((uint128,uint64,uint40)[],uint40) (runs: 50, μ: 3525063, ~: 3130793)
+StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity((uint128,uint64,uint40)[],uint40,uint40) (runs: 50, μ: 3968937, ~: 4106456)
+StreamedAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_OneSegment((uint128,uint64,uint40),uint40) (runs: 50, μ: 276737, ~: 270630)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 11349)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInTheFuture() (gas: 26236)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePast() (gas: 17291)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_CliffTimeInThePresent() (gas: 27121)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusDepleted() (gas: 68877)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusPending() (gas: 20305)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StatusSettled() (gas: 26688)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 78522)
+StreamedAmountOf_LockupLinear_Integration_Concrete_Test:test_StreamedAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 107059)
+StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Calculation(uint40,uint128) (runs: 50, μ: 234376, ~: 234297)
+StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 27341, ~: 27604)
+StreamedAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_StreamedAmountOf_Monotonicity(uint40,uint40,uint128) (runs: 50, μ: 239452, ~: 241444)
ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset() (gas: 31848)
ToggleFlashAsset_Integration_Concrete_Test:test_ToggleFlashAsset_FlagNotEnabled() (gas: 41868)
-TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 3422904)
-TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Full() (gas: 2743187)
-TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 3341348)
-TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 2661789)
-WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 361404)
-WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 324810)
-WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 286684)
-WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 252129)
-WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 153323)
-WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 99935)
-WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 131864, ~: 151107)
-WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 106420)
-WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 100091)
-WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 96364, ~: 106586)
-WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 134454)
-WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 79700)
-WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 116746, ~: 119825)
-WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82256, ~: 82383)
-WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 73906)
-WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80006)
-WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 72863, ~: 73017)
-WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82507, ~: 82689)
-WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1805869)
-WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9087)
-WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2707361, ~: 2707710)
-WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1242199)
-WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9126)
-WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1742432, ~: 1742287)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 381705)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112523)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81082)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72554)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 359872)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122112)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 387067)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 360427)
-Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 379300)
-Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 125749, ~: 98023)
-Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145230, ~: 145230)
-Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3950416, ~: 3852837)
-Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 158615, ~: 158813)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 265613)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 92923)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 61471)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72822)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 257393)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 75290)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 270988)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 257948)
-Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 290354)
-Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 98763, ~: 98632)
-Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 112042, ~: 112042)
-Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 139114, ~: 139033)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 375341)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 344798)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 334407)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 360935)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 331156)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 337357)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 375385)
-WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 397521)
-WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 332813, ~: 349508)
-WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 294637, ~: 286681)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 251328)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 261221)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 286431)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 256422)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 262753)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 297470)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 319562)
-WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 284809)
-WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 458973, ~: 459024)
-WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 261387, ~: 261691)
-WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 435199, ~: 436054)
+TokenURI_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13542)
+TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624)
+TokenURI_LockupDynamic_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6601)
+TokenURI_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTDoesNotExist() (gas: 13525)
+TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Decoded() (gas: 6624)
+TokenURI_LockupLinear_Integration_Concrete_Test:test_TokenURI_Full() (gas: 6601)
+TransferFrom_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 314210)
+TransferFrom_LockupDynamic_Integration_Concrete_Test:test_TransferFrom() (gas: 326549)
+TransferFrom_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 240360)
+TransferFrom_LockupLinear_Integration_Concrete_Test:test_TransferFrom() (gas: 253204)
+WasCanceled_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12048)
+WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled() (gas: 364519)
+WasCanceled_LockupDynamic_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 327661)
+WasCanceled_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12069)
+WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled() (gas: 289228)
+WasCanceled_LockupLinear_Integration_Concrete_Test:test_WasCanceled_StreamNotCanceled() (gas: 254401)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75407)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14162)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 265101)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 159731)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 101620)
+WithdrawMaxAndTransfer_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 136641, ~: 156598)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_NFTBurned() (gas: 75586)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 14179)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamNotTransferable() (gas: 189302)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer() (gas: 112620)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Concrete_Test:test_WithdrawMaxAndTransfer_WithdrawableAmountZero() (gas: 101808)
+WithdrawMaxAndTransfer_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMaxAndTransfer(uint256,address) (runs: 50, μ: 102527, ~: 110966)
+WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax() (gas: 135187)
+WithdrawMax_LockupDynamic_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80257)
+WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 117346, ~: 120408)
+WithdrawMax_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 82843, ~: 82981)
+WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax() (gas: 74491)
+WithdrawMax_LockupLinear_Integration_Concrete_Test:test_WithdrawMax_EndTimeNotInTheFuture() (gas: 80494)
+WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax(uint256) (runs: 50, μ: 73588, ~: 73703)
+WithdrawMax_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMax_EndTimeNotInTheFuture(uint256) (runs: 50, μ: 83108, ~: 83276)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 73864)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21063)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 124687)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83337)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1831194)
+WithdrawMultiple_LockupDynamic_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9109)
+WithdrawMultiple_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 2745377, ~: 2745599)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_AllStatusesDepleted() (gas: 74018)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_OnlyNull() (gas: 21020)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeNull() (gas: 105130)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_RevertGiven_SomeStatusesDepleted() (gas: 83491)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple() (gas: 1264004)
+WithdrawMultiple_LockupLinear_Integration_Concrete_Test:test_WithdrawMultiple_ArrayCountsZero() (gas: 9165)
+WithdrawMultiple_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawMultiple(uint256,address,uint128) (runs: 50, μ: 1773543, ~: 1773439)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19918)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 67824)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw() (gas: 385175)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 112713)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 81272)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72502)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 362822)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 122683)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 390163)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 363377)
+Withdraw_LockupDynamic_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 382351)
+Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 125244, ~: 98689)
+Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 145456, ~: 145456)
+Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_SegmentFuzing(((uint128,uint64,uint40)[],uint256,address)) (runs: 50, μ: 3969894, ~: 4005165)
+Withdraw_LockupDynamic_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 160727, ~: 160960)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 19917)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_RevertGiven_StreamDepleted() (gas: 68020)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw() (gas: 268395)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerApprovedOperator() (gas: 93092)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_CallerRecipient() (gas: 61640)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_EndTimeNotInTheFuture() (gas: 72719)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientDoesNotImplementHook() (gas: 259694)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientNotContract() (gas: 75746)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReentrancy() (gas: 273430)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_RecipientReverts() (gas: 260249)
+Withdraw_LockupLinear_Integration_Concrete_Test:test_Withdraw_StreamHasBeenCanceled() (gas: 292858)
+Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw(uint256,address,uint128) (runs: 50, μ: 99397, ~: 99269)
+Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_CallerApprovedOperator(address) (runs: 50, μ: 112211, ~: 112211)
+Withdraw_LockupLinear_Integration_Fuzz_Test:testFuzz_Withdraw_StreamHasBeenCanceled(uint256,address,uint128) (runs: 50, μ: 141197, ~: 141030)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12045)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf() (gas: 378164)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 347681)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StartTimeInThePresent() (gas: 337258)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 363752)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 334007)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 340230)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 378537)
+WithdrawableAmountOf_LockupDynamic_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 400661)
+WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128) (runs: 50, μ: 335946, ~: 352606)
+WithdrawableAmountOf_LockupDynamic_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40) (runs: 50, μ: 298357, ~: 289776)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_RevertGiven_Null() (gas: 12076)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_CliffTimeInTheFuture() (gas: 253622)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_NoPreviousWithdrawals() (gas: 263493)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusDepleted() (gas: 288666)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusPending() (gas: 258694)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StatusSettled() (gas: 265047)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusCanceled() (gas: 300014)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_StreamHasBeenCanceled_StatusDepleted() (gas: 322024)
+WithdrawableAmountOf_LockupLinear_Integration_Concrete_Test:test_WithdrawableAmountOf_WithWithdrawals() (gas: 287044)
+WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf(uint40,uint128,uint128) (runs: 50, μ: 464066, ~: 464719)
+WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_CliffTimeInTheFuture(uint40) (runs: 50, μ: 263687, ~: 263963)
+WithdrawableAmountOf_LockupLinear_Integration_Fuzz_Test:testFuzz_WithdrawableAmountOf_NoPreviousWithdrawals(uint40,uint128) (runs: 50, μ: 439908, ~: 438806)
\ No newline at end of file
diff --git a/.github/workflows/ci-deep.yml b/.github/workflows/ci-deep.yml
index f00248f20..66f525ad6 100644
--- a/.github/workflows/ci-deep.yml
+++ b/.github/workflows/ci-deep.yml
@@ -68,12 +68,24 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
+ - name: "Install Pnpm"
+ uses: "pnpm/action-setup@v2"
+ with:
+ version: "8"
+
+ - name: "Install Node.js"
+ uses: "actions/setup-node@v3"
+ with:
+ cache: "pnpm"
+ node-version: "lts/*"
+
+ - name: "Install the Node.js dependencies"
+ run: "pnpm install"
+
- name: "Show the Foundry config"
run: "forge config"
@@ -81,14 +93,15 @@ jobs:
run: "FOUNDRY_PROFILE=optimized forge build"
- name: "Build the test contracts"
- run: "FOUNDRY_PROFILE=test-optimized forge build"
+ run: "FOUNDRY_PROFILE=test-optimized forge build"
- - name: "Cache the build so that it can be re-used by the other jobs"
+ - name: "Cache the build and the node modules so that they can be re-used by the other jobs"
uses: "actions/cache/save@v3"
with:
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -105,19 +118,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -137,19 +149,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -170,19 +181,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -202,19 +212,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -224,4 +233,4 @@ jobs:
- name: "Add test summary"
run: |
echo "## Fork tests result" >> $GITHUB_STEP_SUMMARY
- echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
\ No newline at end of file
+ echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/ci-slither.yml b/.github/workflows/ci-slither.yml
new file mode 100644
index 000000000..d2e2f57d5
--- /dev/null
+++ b/.github/workflows/ci-slither.yml
@@ -0,0 +1,83 @@
+name: "CI Slither"
+
+env:
+ API_KEY_ETHERSCAN: ${{ secrets.API_KEY_ETHERSCAN }}
+ API_KEY_INFURA: ${{ secrets.API_KEY_INFURA }}
+ RPC_URL_MAINNET: ${{ secrets.RPC_URL_MAINNET }}
+
+on:
+ schedule:
+ - cron: "0 3 * * 0" # at 3:00am UTC every Sunday
+
+jobs:
+ lint:
+ runs-on: "ubuntu-latest"
+ steps:
+ - name: "Check out the repo"
+ uses: "actions/checkout@v3"
+
+ - name: "Install Foundry"
+ uses: "foundry-rs/foundry-toolchain@v1"
+
+ - name: "Install Pnpm"
+ uses: "pnpm/action-setup@v2"
+ with:
+ version: "8"
+
+ - name: "Install Node.js"
+ uses: "actions/setup-node@v3"
+ with:
+ cache: "pnpm"
+ node-version: "lts/*"
+
+ - name: "Install the Node.js dependencies"
+ run: "pnpm install"
+
+ - name: "Lint the contracts"
+ run: "pnpm lint"
+
+ - name: "Add lint summary"
+ run: |
+ echo "## Lint result" >> $GITHUB_STEP_SUMMARY
+ echo "✅ Passed" >> $GITHUB_STEP_SUMMARY
+
+ slither-analyze:
+ runs-on: "ubuntu-latest"
+ permissions:
+ actions: "read"
+ contents: "read"
+ security-events: "write"
+ steps:
+ - name: "Check out the repo"
+ uses: "actions/checkout@v3"
+
+ - name: "Install Pnpm"
+ uses: "pnpm/action-setup@v2"
+ with:
+ version: "8"
+
+ - name: "Install Node.js"
+ uses: "actions/setup-node@v3"
+ with:
+ cache: "pnpm"
+ node-version: "lts/*"
+
+ - name: "Install the Node.js dependencies"
+ run: "pnpm install"
+
+ - name: "Run Slither analysis"
+ uses: "crytic/slither-action@v0.3.0"
+ id: "slither"
+ with:
+ fail-on: "none"
+ sarif: "results.sarif"
+
+ - name: "Upload SARIF file to GitHub code scanning"
+ uses: "github/codeql-action/upload-sarif@v2"
+ with:
+ sarif_file: ${{ steps.slither.outputs.sarif }}
+
+ - name: "Add Slither summary"
+ run: |
+ echo "## Slither result" >> $GITHUB_STEP_SUMMARY
+ echo "✅ Uploaded to GitHub code scanning" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7a5f6eb27..2c424484e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -53,8 +53,6 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
@@ -78,16 +76,17 @@ jobs:
- name: "Generate and prepare the contract artifacts"
run: "./shell/prepare-artifacts.sh"
-
+
- name: "Build the test contracts"
run: "FOUNDRY_PROFILE=test-optimized forge build"
- - name: "Cache the build so that it can be re-used by the other jobs"
+ - name: "Cache the build and the node modules so that they can be re-used by the other jobs"
uses: "actions/cache/save@v3"
with:
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -109,19 +108,29 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Install Pnpm"
+ uses: "pnpm/action-setup@v2"
+ with:
+ version: "8"
+
+ - name: "Install Node.js"
+ uses: "actions/setup-node@v3"
+ with:
+ cache: "pnpm"
+ node-version: "lts/*"
+
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -141,19 +150,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -171,19 +179,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -201,19 +208,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -233,19 +239,18 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- - name: "Restore the cached build"
+ - name: "Restore the cached build and the node modules"
uses: "actions/cache/restore@v3"
with:
fail-on-cache-miss: true
- key: "foundry-build-${{ github.sha }}"
+ key: "build-and-modules-${{ github.sha }}"
path: |
cache
+ node_modules
out
out-optimized
@@ -267,12 +272,21 @@ jobs:
steps:
- name: "Check out the repo"
uses: "actions/checkout@v3"
- with:
- submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
+ - name: "Restore the cached build and the node modules"
+ uses: "actions/cache/restore@v3"
+ with:
+ fail-on-cache-miss: true
+ key: "build-and-modules-${{ github.sha }}"
+ path: |
+ cache
+ node_modules
+ out
+ out-optimized
+
- name: "Generate the coverage report using the unit and the integration tests"
run: "forge coverage --match-path \"test/{unit,integration}/**/*.sol\" --report lcov"
@@ -284,4 +298,4 @@ jobs:
- name: "Add coverage summary"
run: |
echo "## Coverage result" >> $GITHUB_STEP_SUMMARY
- echo "✅ Uploaded to Codecov" >> $GITHUB_STEP_SUMMARY
\ No newline at end of file
+ echo "✅ Uploaded to Codecov" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/deploy-comptroller.yml b/.github/workflows/deploy-comptroller.yml
index fd391ea5d..03eff8a05 100644
--- a/.github/workflows/deploy-comptroller.yml
+++ b/.github/workflows/deploy-comptroller.yml
@@ -20,7 +20,7 @@ on:
description: "Initial contract admin."
required: false
chain:
- default: "goerli"
+ default: "sepolia"
description: "Chain name as defined in the Foundry config."
required: false
diff --git a/.github/workflows/deploy-core.yml b/.github/workflows/deploy-core.yml
index 905257159..24159ddd5 100644
--- a/.github/workflows/deploy-core.yml
+++ b/.github/workflows/deploy-core.yml
@@ -20,7 +20,7 @@ on:
description: "Initial protocol admin."
required: false
chain:
- default: "goerli"
+ default: "sepolia"
description: "Chain name as defined in the Foundry config."
required: false
max-segment-count:
diff --git a/.github/workflows/deploy-lockup-dynamic.yml b/.github/workflows/deploy-lockup-dynamic.yml
index d90cbc431..f2d7c72a5 100644
--- a/.github/workflows/deploy-lockup-dynamic.yml
+++ b/.github/workflows/deploy-lockup-dynamic.yml
@@ -20,7 +20,7 @@ on:
description: "Initial contract admin."
required: false
chain:
- default: "goerli"
+ default: "sepolia"
description: "Chain name as defined in the Foundry config."
required: false
comptroller:
diff --git a/.github/workflows/deploy-lockup-linear.yml b/.github/workflows/deploy-lockup-linear.yml
index 6ddcb368e..9d51e5855 100644
--- a/.github/workflows/deploy-lockup-linear.yml
+++ b/.github/workflows/deploy-lockup-linear.yml
@@ -20,7 +20,7 @@ on:
description: "Initial contract admin."
required: false
chain:
- default: "goerli"
+ default: "sepolia"
description: "Chain name as defined in the Foundry config."
required: false
comptroller:
diff --git a/.github/workflows/deploy-nft-descriptor.yml b/.github/workflows/deploy-nft-descriptor.yml
index 6f76bd1be..ef5ee19f4 100644
--- a/.github/workflows/deploy-nft-descriptor.yml
+++ b/.github/workflows/deploy-nft-descriptor.yml
@@ -16,7 +16,7 @@ on:
workflow_dispatch:
inputs:
chain:
- default: "goerli"
+ default: "sepolia"
description: "Chain name as defined in the Foundry config."
required: false
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index 4c47bc02c..000000000
--- a/.gitmodules
+++ /dev/null
@@ -1,24 +0,0 @@
-[submodule "lib/forge-std"]
- branch = "v1"
- path = "lib/forge-std"
- url = "https://github.com/foundry-rs/forge-std"
-[submodule "lib/openzeppelin-contracts"]
- branch = "release-v4.9"
- path = "lib/openzeppelin-contracts"
- url = "https://github.com/OpenZeppelin/openzeppelin-contracts"
-[submodule "lib/prb-math"]
- branch = "release-v4"
- path = "lib/prb-math"
- url = "https://github.com/PaulRBerg/prb-math"
-[submodule "lib/prb-test"]
- branch = "release-v0"
- path = "lib/prb-test"
- url = "https://github.com/PaulRBerg/prb-test"
-[submodule "lib/solady"]
- branch = "main"
- path = "lib/solady"
- url = "https://github.com/Vectorized/solady"
-[submodule "lib/solarray"]
- branch = "master"
- path = "lib/solarray"
- url = "https://github.com/evmcheb/solarray"
diff --git a/.solhint.json b/.solhint.json
index 22cafb398..31a4d5b8c 100644
--- a/.solhint.json
+++ b/.solhint.json
@@ -6,12 +6,14 @@
"compiler-version": ["error", ">=0.8.19"],
"contract-name-camelcase": "off",
"const-name-snakecase": "off",
+ "custom-errors": "off",
"func-name-mixedcase": "off",
"func-visibility": ["error", { "ignoreConstructors": true }],
"max-line-length": ["error", 123],
"named-parameters-mapping": "warn",
"no-empty-blocks": "off",
"not-rely-on-time": "off",
+ "one-contract-per-file": "off",
"var-name-mixedcase": "off"
}
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cfd69bb8c..ebbe9af96 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,10 +4,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Common Changelog](https://common-changelog.org/).
+[1.1.0]: https://github.com/sablier-labs/v2-core/compare/v1.0.2...v1.1.0
[1.0.2]: https://github.com/sablier-labs/v2-core/compare/v1.0.1...v1.0.2
[1.0.1]: https://github.com/sablier-labs/v2-core/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/sablier-labs/v2-core/releases/tag/v1.0.0
+## [1.1.0] - 2023-12-15
+
+### Changed
+
+- **Breaking**: Remove ability to cancel for recipients ([#710](https://github.com/sablier-labs/v2-core/pull/710))
+- Move `isWarm` and `isCold` to `SablierV2Lockup` ([#664](https://github.com/sablier-labs/v2-core/pull/664))
+- Replace the streamed amount with the deposit amount in the NFT descriptor
+ ([#692](https://github.com/sablier-labs/v2-core/pull/692))
+- Simplify `renounce` and `withdraw` implementations ([#683](https://github.com/sablier-labs/v2-core/pull/683),
+ [#705](https://github.com/sablier-labs/v2-core/pull/705))
+- Update import paths to use Node.js dependencies ([#734](https://github.com/sablier-labs/v2-core/pull/734))
+- Upgrade Solidity to `0.8.21` ([#688](https://github.com/sablier-labs/v2-core/pull/688))
+
+### Added
+
+- Add `ERC-4906` metadata update in `transferFrom` ([#686](https://github.com/sablier-labs/v2-core/pull/686))
+- Add `transferable` boolean flag ([#668](https://github.com/sablier-labs/v2-core/pull/668))
+
+### Removed
+
+- Remove `@openzeppelin/contracts` from Node.js peer dependencies
+ ([#694](https://github.com/sablier-labs/v2-core/pull/694))
+
## [1.0.2] - 2023-08-14
### Changed
diff --git a/README.md b/README.md
index 7a0877e3d..147a9d1e7 100644
--- a/README.md
+++ b/README.md
@@ -16,16 +16,32 @@ In-depth documentation is available at [docs.sablier.com](https://docs.sablier.c
## Background
-Sablier is a smart contract protocol that enables trustless streaming of ERC-20 assets. In this context, streaming means
-the ability to make payments by the second.
+Sablier V2 is a token distribution protocol used by DAOs and businesses for vesting, payroll, airdrops, and more. The
+linear stream is our flagship payment model, which distributes assets on a continuous, by-the-second basis.
-The protocol features two streaming models called Lockup Linear and Lockup Dynamic, in which the sender locks up a
-specified amount of ERC-20 assets in a contract. The contract progressively allocates the funds to the designated
-recipient, who can access them as they become available over time. The streaming rate is influenced by various factors,
-including the start and end times, as well as the total amount of assets locked up.
+The way it works is that the sender of a payment stream first deposits a specific amount of ERC-20 tokens in a contract.
+Then, the contract progressively allocates the funds to the recipient, who can access them as they become available over
+time. The payment rate is influenced by various factors, including the start and end times, as well as the total amount
+of tokens deposited.
## Install
+### Node.js (recommended)
+
+Sablier V2 Core is available as a Node.js package:
+
+```shell
+yarn add @sablier/v2-core
+```
+
+Finally, add these to your `remappings.txt` file:
+
+```text
+@sablier/v2-core/=node_modules/@sablier/v2-core/
+@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
+@prb/math/=node_modules/@prb/math/
+```
+
### Foundry
First, run the install step:
@@ -34,27 +50,18 @@ First, run the install step:
forge install sablier-labs/v2-core
```
-Your `.gitmodules` file should now contain the following entry:
+Second, you need to install the project's dependencies:
-```toml
-[submodule "lib/v2-core"]
- branch = "release"
- path = "lib/v2-core"
- url = "https://github.com/sablier-labs/v2-core"
+```shell
+forge install --no-commit OpenZeppelin/openzeppelin-contracts@v4.9.2 PaulRBerg/prb-math
```
-Finally, add this to your `remappings.txt` file:
+Finally, add these to your `remappings.txt` file:
```text
@sablier/v2-core/=lib/v2-core/
-```
-
-### Node.js
-
-Sablier V2 Core is available as a Node.js package:
-
-```shell
-pnpm add @sablier/v2-core
+@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
+@prb/math/=lib/prb-math/
```
## Usage
@@ -83,6 +90,11 @@ contract, which is more gas-efficient and easier to maintain.
For more information, see the [Technical Overview](https://docs.sablier.com/contracts/v2/reference/overview) in our
docs, as well as these [diagrams](https://docs.sablier.com/contracts/v2/reference/diagrams).
+### Branching Tree Technique
+
+You may notice that some test files are accompanied by `.tree` files. This is called the Branching Tree Technique, and
+it is explained in depth [here](https://github.com/sablier-labs/v2-core/wiki/Tests#branching-tree-technique).
+
## Deployments
The list of all deployment addresses can be found [here](https://docs.sablier.com). For guidance on the deploy scripts,
diff --git a/SECURITY.md b/SECURITY.md
index 22319f6eb..8ae591510 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -24,7 +24,7 @@ The Program does NOT cover the following:
- Code located in the [test](./test) or [script](./script) directories.
- External code in the [lib](./lib) directory, except for code that is explicitly used by a deployed contract located in
the [src](./src) directory.
-- Contract deployments on test networks, such as Goerli.
+- Contract deployments on test networks, such as Sepolia.
- Bugs in third-party contracts or platforms interacting with Sablier V2 Core.
- Previously reported or discovered vulnerabilities in contracts built by third parties on Sablier V2 Core.
- Bugs that have already been reported.
@@ -52,6 +52,7 @@ vulnerability, it must adhere to these assumptions as well:
are not supported.
- An address' ERC-20 balance can only change as a result of a `transfer` call by the sender or a `transferFrom` call by
an approved address. This excludes rebase tokens and interest-bearing tokens.
+- The token contract does not allow callbacks (e.g. ERC-777 is not supported).
### Rewards
diff --git a/foundry.toml b/foundry.toml
index d788a459c..5eed6d8ed 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -1,7 +1,6 @@
[profile.default]
auto_detect_solc = false
bytecode_hash = "none"
- cbor_metadata = false
emv_version = "paris"
fs_permissions = [{ access = "read", path = "out-optimized" }]
libs = ["lib"]
@@ -16,7 +15,7 @@
out = "out"
script = "script"
sender = "0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38"
- solc = "0.8.19"
+ solc = "0.8.21"
src = "src"
test = "test"
@@ -53,7 +52,9 @@
[profile.smt.model_checker]
engine = "chc" # constrained Horn clauses
invariants = ["contract", "reentrancy"]
+ show_proved_safe = true
show_unproved = true
+ show_unsupported = true
timeout = 100_000 # in milliseconds, per solving query
targets = [
"assert",
@@ -79,11 +80,10 @@
repository = "https://github.com/sablier-labs/v2-core"
[etherscan]
- arbitrum_one = { key = "${API_KEY_ARBISCAN}" }
+ arbitrum = { key = "${API_KEY_ARBISCAN}" }
avalanche = { key = "${API_KEY_SNOWTRACE" }
bnb_smart_chain = { key = "${API_KEY_BSCSCAN}" }
gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" }
- goerli = { key = "${API_KEY_ETHERSCAN}" }
mainnet = { key = "${API_KEY_ETHERSCAN}" }
optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" }
polygon = { key = "${API_KEY_POLYGONSCAN}" }
@@ -100,11 +100,10 @@
wrap_comments = true
[rpc_endpoints]
- arbitrum_one = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
+ arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}"
bnb_smart_chain = "https://bsc-dataseed.binance.org"
gnosis_chain = "https://rpc.gnosischain.com"
- goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}"
localhost = "http://localhost:8545"
mainnet = "${RPC_URL_MAINNET}"
optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
diff --git a/lib/forge-std b/lib/forge-std
deleted file mode 160000
index e8a047e3f..000000000
--- a/lib/forge-std
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e8a047e3f40f13fa37af6fe14e6e06283d9a060e
diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts
deleted file mode 160000
index e50c24f58..000000000
--- a/lib/openzeppelin-contracts
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e50c24f5839db17f46991478384bfda14acfb830
diff --git a/lib/prb-math b/lib/prb-math
deleted file mode 160000
index 77fa88eda..000000000
--- a/lib/prb-math
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 77fa88eda4a4a91b3f3e9431df291292c26b6c71
diff --git a/lib/prb-test b/lib/prb-test
deleted file mode 160000
index 1e9ead2f7..000000000
--- a/lib/prb-test
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 1e9ead2f7bfaedda3038081c16484b0d7d0b2712
diff --git a/lib/solady b/lib/solady
deleted file mode 160000
index c863813a6..000000000
--- a/lib/solady
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit c863813a6fa2068e1ec834ebc037ededb99a6f97
diff --git a/lib/solarray b/lib/solarray
deleted file mode 160000
index 0625e7e43..000000000
--- a/lib/solarray
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc
diff --git a/package.json b/package.json
index ae66ed1c0..7e452e296 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
"name": "@sablier/v2-core",
- "description": "Core smart contracts of the Sablier V2 token streaming protocol",
+ "description": "Core smart contracts of the Sablier V2 token distribution protocol",
"license": "BUSL-1.1",
- "version": "1.0.2",
+ "version": "1.1.0",
"author": {
"name": "Sablier Labs Ltd",
"url": "https://sablier.com"
@@ -12,20 +12,26 @@
},
"dependencies": {
"@openzeppelin/contracts": "4.9.2",
- "@prb/math": "4.0.1"
+ "@prb/math": "4.0.2"
},
"devDependencies": {
+ "@prb/test": "0.6.4",
+ "forge-std": "github:foundry-rs/forge-std#e8a047e3f40f13fa37af6fe14e6e06283d9a060e",
"prettier": "^2.8.8",
- "solhint-community": "^3.5.2"
+ "solady": "0.0.129",
+ "solarray": "github:evmcheb/solarray#0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc",
+ "solhint": "^4.0.0"
},
"files": [
"artifacts",
"src",
+ "test/utils",
"CHANGELOG.md",
"LICENSE-GPL.md"
],
"homepage": "https://github.com/sablier-labs/v2-core#readme",
"keywords": [
+ "asset-distribution",
"asset-streaming",
"blockchain",
"cryptoasset-streaming",
@@ -38,11 +44,14 @@
"sablier-v2",
"smart-contracts",
"solidity",
- "token-streaming"
+ "token-distribution",
+ "token-streaming",
+ "token-vesting",
+ "vesting",
+ "web3"
],
"peerDependencies": {
- "@openzeppelin/contracts": "4.9.2",
- "@prb/math": "4.0.1"
+ "@prb/math": "4.0.x"
},
"publishConfig": {
"access": "public"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8049a4a94..fa7d38c08 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,16 +9,28 @@ dependencies:
specifier: 4.9.2
version: 4.9.2
'@prb/math':
- specifier: 4.0.1
- version: 4.0.1
+ specifier: 4.0.2
+ version: 4.0.2
devDependencies:
+ '@prb/test':
+ specifier: 0.6.4
+ version: 0.6.4
+ forge-std:
+ specifier: github:foundry-rs/forge-std#e8a047e3f40f13fa37af6fe14e6e06283d9a060e
+ version: github.com/foundry-rs/forge-std/e8a047e3f40f13fa37af6fe14e6e06283d9a060e
prettier:
specifier: ^2.8.8
version: 2.8.8
- solhint-community:
- specifier: ^3.5.2
- version: 3.5.2
+ solady:
+ specifier: 0.0.129
+ version: 0.0.129
+ solarray:
+ specifier: github:evmcheb/solarray#0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc
+ version: github.com/evmcheb/solarray/0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc
+ solhint:
+ specifier: ^4.0.0
+ version: 4.0.0
packages:
@@ -47,16 +59,57 @@ packages:
resolution: {integrity: sha512-mO+y6JaqXjWeMh9glYVzVu8HYPGknAAnWyxTRhGeckOruyXQMNnlcW6w/Dx9ftLeIQk6N+ZJFuVmTwF7lEIFrg==}
dev: false
- /@prb/math@4.0.1:
- resolution: {integrity: sha512-ANTz2KMV+dMdZ57mWgDTR6jZo5uQzUczQEHCxd7CvJZZ9yafnfPhUUILHvvigIOZ85fZbTPVkC8YoRG1z5Qf7g==}
+ /@pnpm/config.env-replace@1.1.0:
+ resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
+ engines: {node: '>=12.22.0'}
+ dev: true
+
+ /@pnpm/network.ca-file@1.0.2:
+ resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==}
+ engines: {node: '>=12.22.0'}
+ dependencies:
+ graceful-fs: 4.2.10
+ dev: true
+
+ /@pnpm/npm-conf@2.2.2:
+ resolution: {integrity: sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==}
+ engines: {node: '>=12'}
+ dependencies:
+ '@pnpm/config.env-replace': 1.1.0
+ '@pnpm/network.ca-file': 1.0.2
+ config-chain: 1.1.13
+ dev: true
+
+ /@prb/math@4.0.2:
+ resolution: {integrity: sha512-kJgqvXR6iyU7+N959RzggSFhBdnRuSDnc/bs8u6MzdWw7aYIUaAr+uMVdpP6Dheypjerd7sfJgFOs19FRFhscg==}
dev: false
+ /@prb/test@0.6.4:
+ resolution: {integrity: sha512-P0tTMsB6XQ0Wp61EYdXJYFhsOVGyZvcOFub2y9yk0sF+GYDusctR7DzEI+vOP0SILm3knFkEJASjewHEBppdRQ==}
+ dev: true
+
+ /@sindresorhus/is@5.6.0:
+ resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
+ engines: {node: '>=14.16'}
+ dev: true
+
/@solidity-parser/parser@0.16.0:
resolution: {integrity: sha512-ESipEcHyRHg4Np4SqBCfcXwyxxna1DgFVz69bgpLV8vzl/NP1DtcKsJ4dJZXWQhY/Z4J2LeKBiOkOVZn9ct33Q==}
dependencies:
antlr4ts: 0.5.0-alpha.4
dev: true
+ /@szmarczak/http-timer@5.0.1:
+ resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ defer-to-connect: 2.0.1
+ dev: true
+
+ /@types/http-cache-semantics@4.0.4:
+ resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
+ dev: true
+
/ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
@@ -126,6 +179,24 @@ packages:
balanced-match: 1.0.2
dev: true
+ /cacheable-lookup@7.0.0:
+ resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
+ engines: {node: '>=14.16'}
+ dev: true
+
+ /cacheable-request@10.2.14:
+ resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ '@types/http-cache-semantics': 4.0.4
+ get-stream: 6.0.1
+ http-cache-semantics: 4.1.1
+ keyv: 4.5.4
+ mimic-response: 4.0.0
+ normalize-url: 8.0.0
+ responselike: 3.0.0
+ dev: true
+
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
@@ -174,6 +245,13 @@ packages:
engines: {node: '>=14'}
dev: true
+ /config-chain@1.1.13:
+ resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==}
+ dependencies:
+ ini: 1.3.8
+ proto-list: 1.2.4
+ dev: true
+
/cosmiconfig@8.2.0:
resolution: {integrity: sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==}
engines: {node: '>=14'}
@@ -184,6 +262,23 @@ packages:
path-type: 4.0.0
dev: true
+ /decompress-response@6.0.0:
+ resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ mimic-response: 3.1.0
+ dev: true
+
+ /deep-extend@0.6.0:
+ resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
+ engines: {node: '>=4.0.0'}
+ dev: true
+
+ /defer-to-connect@2.0.1:
+ resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
+ engines: {node: '>=10'}
+ dev: true
+
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
@@ -211,10 +306,20 @@ packages:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
+ /form-data-encoder@2.1.4:
+ resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==}
+ engines: {node: '>= 14.17'}
+ dev: true
+
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
+ /get-stream@6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+ dev: true
+
/glob@8.1.0:
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
engines: {node: '>=12'}
@@ -226,6 +331,27 @@ packages:
once: 1.4.0
dev: true
+ /got@12.6.1:
+ resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ '@sindresorhus/is': 5.6.0
+ '@szmarczak/http-timer': 5.0.1
+ cacheable-lookup: 7.0.0
+ cacheable-request: 10.2.14
+ decompress-response: 6.0.0
+ form-data-encoder: 2.1.4
+ get-stream: 6.0.1
+ http2-wrapper: 2.2.1
+ lowercase-keys: 3.0.0
+ p-cancelable: 3.0.0
+ responselike: 3.0.0
+ dev: true
+
+ /graceful-fs@4.2.10:
+ resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==}
+ dev: true
+
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
@@ -236,6 +362,18 @@ packages:
engines: {node: '>=8'}
dev: true
+ /http-cache-semantics@4.1.1:
+ resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
+ dev: true
+
+ /http2-wrapper@2.2.1:
+ resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==}
+ engines: {node: '>=10.19.0'}
+ dependencies:
+ quick-lru: 5.1.1
+ resolve-alpn: 1.2.1
+ dev: true
+
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
@@ -260,6 +398,10 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
+ /ini@1.3.8:
+ resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
+ dev: true
+
/is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
dev: true
@@ -280,6 +422,10 @@ packages:
argparse: 2.0.1
dev: true
+ /json-buffer@3.0.1:
+ resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ dev: true
+
/json-parse-even-better-errors@2.3.1:
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
dev: true
@@ -292,6 +438,19 @@ packages:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
dev: true
+ /keyv@4.5.4:
+ resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
+ dependencies:
+ json-buffer: 3.0.1
+ dev: true
+
+ /latest-version@7.0.0:
+ resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ package-json: 8.1.1
+ dev: true
+
/lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
dev: true
@@ -304,6 +463,28 @@ packages:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: true
+ /lowercase-keys@3.0.0:
+ resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
+ /lru-cache@6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /mimic-response@3.1.0:
+ resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /mimic-response@4.0.0:
+ resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dev: true
+
/minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
@@ -311,12 +492,36 @@ packages:
brace-expansion: 2.0.1
dev: true
+ /minimist@1.2.8:
+ resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ dev: true
+
+ /normalize-url@8.0.0:
+ resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
+ engines: {node: '>=14.16'}
+ dev: true
+
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
+ /p-cancelable@3.0.0:
+ resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==}
+ engines: {node: '>=12.20'}
+ dev: true
+
+ /package-json@8.1.1:
+ resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ got: 12.6.1
+ registry-auth-token: 5.0.2
+ registry-url: 6.0.1
+ semver: 7.5.4
+ dev: true
+
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
@@ -350,24 +555,71 @@ packages:
hasBin: true
dev: true
+ /proto-list@1.2.4:
+ resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==}
+ dev: true
+
/punycode@2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
dev: true
+ /quick-lru@5.1.1:
+ resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /rc@1.2.8:
+ resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
+ hasBin: true
+ dependencies:
+ deep-extend: 0.6.0
+ ini: 1.3.8
+ minimist: 1.2.8
+ strip-json-comments: 2.0.1
+ dev: true
+
+ /registry-auth-token@5.0.2:
+ resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==}
+ engines: {node: '>=14'}
+ dependencies:
+ '@pnpm/npm-conf': 2.2.2
+ dev: true
+
+ /registry-url@6.0.1:
+ resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==}
+ engines: {node: '>=12'}
+ dependencies:
+ rc: 1.2.8
+ dev: true
+
/require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
dev: true
+ /resolve-alpn@1.2.1:
+ resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
+ dev: true
+
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: true
- /semver@6.3.0:
- resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
+ /responselike@3.0.0:
+ resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==}
+ engines: {node: '>=14.16'}
+ dependencies:
+ lowercase-keys: 3.0.0
+ dev: true
+
+ /semver@7.5.4:
+ resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
+ engines: {node: '>=10'}
hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
dev: true
/slice-ansi@4.0.0:
@@ -379,8 +631,12 @@ packages:
is-fullwidth-code-point: 3.0.0
dev: true
- /solhint-community@3.5.2:
- resolution: {integrity: sha512-l3lF2n8mF33p266u5atCSqjT9SyyOBD1qaWrQBAXHNk2xAxmi+pEynIVuTIn6FVD3JiuHRgutjKJcngs8Iolbg==}
+ /solady@0.0.129:
+ resolution: {integrity: sha512-2i+8lsLLT7nAED+A9C+ZLi8YmpSnUNKGKozkesN2Qm3P3iMvorXAsD5LyT1MAC3eyVfhY3PuvBkvgd31nUzkoQ==}
+ dev: true
+
+ /solhint@4.0.0:
+ resolution: {integrity: sha512-bFViMcFvhqVd/HK3Roo7xZXX5nbujS7Bxeg5vnZc9QvH0yCWCrQ38Yrn1pbAY9tlKROc6wFr+rK1mxYgYrjZgA==}
hasBin: true
dependencies:
'@solidity-parser/parser': 0.16.0
@@ -394,9 +650,10 @@ packages:
glob: 8.1.0
ignore: 5.2.4
js-yaml: 4.1.0
+ latest-version: 7.0.0
lodash: 4.17.21
pluralize: 8.0.0
- semver: 6.3.0
+ semver: 7.5.4
strip-ansi: 6.0.1
table: 6.8.1
text-table: 0.2.0
@@ -420,6 +677,11 @@ packages:
ansi-regex: 5.0.1
dev: true
+ /strip-json-comments@2.0.1:
+ resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
/supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@@ -458,3 +720,19 @@ packages:
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
+
+ /yallist@4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ dev: true
+
+ github.com/evmcheb/solarray/0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc:
+ resolution: {tarball: https://codeload.github.com/evmcheb/solarray/tar.gz/0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc}
+ name: solarray#0625e7e4369eb299753fcb90a3cd7ffb91e1b5bc
+ version: 0.0.0
+ dev: true
+
+ github.com/foundry-rs/forge-std/e8a047e3f40f13fa37af6fe14e6e06283d9a060e:
+ resolution: {tarball: https://codeload.github.com/foundry-rs/forge-std/tar.gz/e8a047e3f40f13fa37af6fe14e6e06283d9a060e}
+ name: forge-std
+ version: 1.5.6
+ dev: true
diff --git a/remappings.txt b/remappings.txt
index b35a5d2ab..167506d32 100644
--- a/remappings.txt
+++ b/remappings.txt
@@ -1,6 +1,6 @@
-@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/
-@prb/math/=lib/prb-math/
-@prb/test/=lib/prb-test/src/
-forge-std/=lib/forge-std/src/
-solady/=lib/solady/src/
-solarray/=lib/solarray/src/
+@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
+@prb/math/=node_modules/@prb/math/
+@prb/test/=node_modules/@prb/test/
+forge-std/=node_modules/forge-std/
+solady/=node_modules/solady/
+solarray/=node_modules/solarray/
\ No newline at end of file
diff --git a/script/Base.s.sol b/script/Base.s.sol
index 53c814f2a..e9f18740e 100644
--- a/script/Base.s.sol
+++ b/script/Base.s.sol
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
-import { Script } from "forge-std/Script.sol";
+import { Script } from "forge-std/src/Script.sol";
abstract contract BaseScript is Script {
/// @dev Included to enable compilation of the script without a $MNEMONIC environment variable.
diff --git a/script/DeployComptroller.s.sol b/script/DeployComptroller.s.sol
index ee8fd0843..cfeb4769c 100644
--- a/script/DeployComptroller.s.sol
+++ b/script/DeployComptroller.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
diff --git a/script/DeployCore.s.sol b/script/DeployCore.s.sol
index a53aa44d5..cb70fa7a1 100644
--- a/script/DeployCore.s.sol
+++ b/script/DeployCore.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
diff --git a/script/DeployCore2.s.sol b/script/DeployCore2.s.sol
index f448eb466..0752639c1 100644
--- a/script/DeployCore2.s.sol
+++ b/script/DeployCore2.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
diff --git a/script/DeployDeterministicComptroller.s.sol b/script/DeployDeterministicComptroller.s.sol
index 35e07cff2..e609d960c 100644
--- a/script/DeployDeterministicComptroller.s.sol
+++ b/script/DeployDeterministicComptroller.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
diff --git a/script/DeployDeterministicCore.s.sol b/script/DeployDeterministicCore.s.sol
index ebedcded8..aac8a7ab9 100644
--- a/script/DeployDeterministicCore.s.sol
+++ b/script/DeployDeterministicCore.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
import { SablierV2LockupDynamic } from "../src/SablierV2LockupDynamic.sol";
diff --git a/script/DeployDeterministicCore2.s.sol b/script/DeployDeterministicCore2.s.sol
index a7a0183cf..c6b76b4f7 100644
--- a/script/DeployDeterministicCore2.s.sol
+++ b/script/DeployDeterministicCore2.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
import { SablierV2Comptroller } from "../src/SablierV2Comptroller.sol";
diff --git a/script/DeployDeterministicLockupDynamic.s.sol b/script/DeployDeterministicLockupDynamic.s.sol
index 4ddf6e20f..8c25b4a83 100644
--- a/script/DeployDeterministicLockupDynamic.s.sol
+++ b/script/DeployDeterministicLockupDynamic.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
diff --git a/script/DeployDeterministicLockupLinear.s.sol b/script/DeployDeterministicLockupLinear.s.sol
index 86b710364..3526a45fb 100644
--- a/script/DeployDeterministicLockupLinear.s.sol
+++ b/script/DeployDeterministicLockupLinear.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
diff --git a/script/DeployLockupDynamic.s.sol b/script/DeployLockupDynamic.s.sol
index 3b1256acb..b27f75396 100644
--- a/script/DeployLockupDynamic.s.sol
+++ b/script/DeployLockupDynamic.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
diff --git a/script/DeployLockupLinear.s.sol b/script/DeployLockupLinear.s.sol
index 813e36877..b3af99d1b 100644
--- a/script/DeployLockupLinear.s.sol
+++ b/script/DeployLockupLinear.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2NFTDescriptor } from "../src/interfaces/ISablierV2NFTDescriptor.sol";
diff --git a/script/GenerateSVG.s.sol b/script/GenerateSVG.s.sol
index ed568de6b..df3bbc9d7 100644
--- a/script/GenerateSVG.s.sol
+++ b/script/GenerateSVG.s.sol
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
@@ -19,12 +19,12 @@ contract GenerateSVG is BaseScript, SablierV2NFTDescriptor {
/// @param progress The streamed amount as a numerical percentage with 4 implied decimals.
/// @param status The status of the stream, as a string.
- /// @param streamed The abbreviated streamed amount, as a string.
+ /// @param amount The abbreviated deposited amount, as a string.
/// @param duration The total duration of the stream in days, as a number.
function run(
uint256 progress,
string memory status,
- string memory streamed,
+ string memory amount,
uint256 duration
)
public
@@ -34,6 +34,7 @@ contract GenerateSVG is BaseScript, SablierV2NFTDescriptor {
svg = NFTSVG.generateSVG(
NFTSVG.SVGParams({
accentColor: generateAccentColor({ sablier: LOCKUP_LINEAR, streamId: uint256(keccak256(msg.data)) }),
+ amount: string.concat(SVGElements.SIGN_GE, " ", amount),
assetAddress: DAI.toHexString(),
assetSymbol: "DAI",
duration: calculateDurationInDays({ startTime: 0, endTime: duration * 1 days }),
@@ -41,7 +42,6 @@ contract GenerateSVG is BaseScript, SablierV2NFTDescriptor {
progress: stringifyPercentage(progress),
progressNumerical: progress,
status: status,
- streamed: streamed.equal("0") ? "0" : string.concat(SVGElements.SIGN_GE, " ", streamed),
streamingModel: "Lockup Linear"
})
);
diff --git a/script/Init.s.sol b/script/Init.s.sol
index 16f2db254..8a99762ac 100644
--- a/script/Init.s.sol
+++ b/script/Init.s.sol
@@ -1,15 +1,16 @@
// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19 <=0.9.0;
+pragma solidity >=0.8.19 <0.9.0;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import { ud2x18 } from "@prb/math/src/UD2x18.sol";
+import { ud60x18 } from "@prb/math/src/UD60x18.sol";
-import { Solarray } from "solarray/Solarray.sol";
+import { Solarray } from "solarray/src/Solarray.sol";
import { ISablierV2Comptroller } from "../src/interfaces/ISablierV2Comptroller.sol";
import { ISablierV2LockupDynamic } from "../src/interfaces/ISablierV2LockupDynamic.sol";
import { ISablierV2LockupLinear } from "../src/interfaces/ISablierV2LockupLinear.sol";
import { Broker, LockupDynamic, LockupLinear } from "../src/types/DataTypes.sol";
-import { ud2x18, ud60x18 } from "../src/types/Math.sol";
import { BaseScript } from "./Base.s.sol";
@@ -73,6 +74,7 @@ contract Init is BaseScript {
totalAmount: totalAmounts[i],
asset: asset,
cancelable: true,
+ transferable: true,
durations: LockupLinear.Durations({ cliff: cliffDurations[i], total: totalDurations[i] }),
broker: Broker(address(0), ud60x18(0))
})
@@ -98,6 +100,7 @@ contract Init is BaseScript {
asset: asset,
broker: Broker(address(0), ud60x18(0)),
cancelable: true,
+ transferable: true,
recipient: recipient,
sender: sender,
segments: segments,
diff --git a/shell/generate-svg-panoply.sh b/shell/generate-svg-panoply.sh
index 0bbf39c36..4f9973ba5 100755
--- a/shell/generate-svg-panoply.sh
+++ b/shell/generate-svg-panoply.sh
@@ -9,12 +9,12 @@
# Strict mode: https://gist.github.com/vncsna/64825d5609c146e80de8b1fd623011ca
set -euo pipefail
-./shell/generate-svg.sh 0 "Pending" "0" 5
-./shell/generate-svg.sh 0 "Pending" "0" 21
-./shell/generate-svg.sh 0 "Pending" "0" 565
+./shell/generate-svg.sh 0 "Pending" "100" 5
+./shell/generate-svg.sh 0 "Pending" "100" 21
+./shell/generate-svg.sh 0 "Pending" "100" 565
-./shell/generate-svg.sh 0 "Canceled" "0" 3
-./shell/generate-svg.sh 0 "Canceled" "0" 3
+./shell/generate-svg.sh 0 "Canceled" "100" 3
+./shell/generate-svg.sh 0 "Canceled" "100" 3
./shell/generate-svg.sh 144 "Canceled" "29.81K" 24
./shell/generate-svg.sh 7231 "Canceled" "421.11K" 24
diff --git a/shell/generate-svg.sh b/shell/generate-svg.sh
index eca4f9379..4f5a0d556 100755
--- a/shell/generate-svg.sh
+++ b/shell/generate-svg.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# Notes:
-# - There are four input arguments: progress, status, streamed amount, and duration
+# - There are four input arguments: progress, status, deposit amount, and duration
# Pre-requisites:
# - foundry (https://getfoundry.sh)
@@ -12,7 +12,7 @@ set -euo pipefail
# Load the arguments while using default values
arg_progress=${1:-4235}
arg_status=${2:-"Streaming"}
-arg_streamed=${3:-"1.23M"}
+arg_amount=${3:-"1.23M"}
arg_duration=${4:-"91"}
# Run the Forge script and extract the SVG from stdout
@@ -21,13 +21,13 @@ output=$(
--sig "run(uint256,string,string,uint256)" \
"$arg_progress" \
"$arg_status" \
- "$arg_streamed" \
+ "$arg_amount" \
"$arg_duration"
)
svg=$(echo "$output" | awk -F "svg: string " '{print $2}' | awk 'NF > 0')
# Generate the file name
-name="nft-${arg_progress}-${arg_status}-${arg_streamed}-${arg_duration}.svg"
+name="nft-${arg_progress}-${arg_status}-${arg_amount}-${arg_duration}.svg"
sanitized="$(echo "$name" | sed "s/ //g" )" # remove whitespaces
# Put the SVG in a file
diff --git a/shell/prepare-artifacts.sh b/shell/prepare-artifacts.sh
index 04ca4f002..06ab4fe97 100755
--- a/shell/prepare-artifacts.sh
+++ b/shell/prepare-artifacts.sh
@@ -45,7 +45,6 @@ cp out-optimized/IERC721Metadata.sol/IERC721Metadata.json $erc721
hooks=./artifacts/interfaces/hooks
cp out-optimized/ISablierV2LockupRecipient.sol/ISablierV2LockupRecipient.json $hooks
-cp out-optimized/ISablierV2LockupSender.sol/ISablierV2LockupSender.json $hooks
libraries=./artifacts/libraries
cp out-optimized/Errors.sol/Errors.json $libraries
diff --git a/slither.config.json b/slither.config.json
index 725063073..16f73fce4 100644
--- a/slither.config.json
+++ b/slither.config.json
@@ -1,12 +1,12 @@
{
"detectors_to_exclude": "naming-convention,reentrancy-events,solc-version,timestamp",
- "filter_paths": "(lib|test)",
+ "filter_paths": "(test)",
"solc_remaps": [
- "@openzeppelin/contracts=lib/openzeppelin-contracts/contracts/",
- "@prb/math/=lib/prb-math/",
- "@prb/test/=lib/prb-test/src/",
- "forge-std/=lib/forge-std/src/",
- "solady/=lib/solady/src/",
- "solarray/=lib/solarray/src/"
+ "@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
+ "@prb/math/=node_modules/@prb-math/",
+ "@prb/test/=node_modules/@prb/test/",
+ "forge-std/=node_modules/forge-std/",
+ "solady/=node_modules/solady/",
+ "solarray/=node_modules/solarray/"
]
}
diff --git a/src/SablierV2LockupDynamic.sol b/src/SablierV2LockupDynamic.sol
index 8bf388d6d..e8a15a4cb 100644
--- a/src/SablierV2LockupDynamic.sol
+++ b/src/SablierV2LockupDynamic.sol
@@ -14,7 +14,6 @@ import { ISablierV2Comptroller } from "./interfaces/ISablierV2Comptroller.sol";
import { ISablierV2Lockup } from "./interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupDynamic } from "./interfaces/ISablierV2LockupDynamic.sol";
import { ISablierV2LockupRecipient } from "./interfaces/hooks/ISablierV2LockupRecipient.sol";
-import { ISablierV2LockupSender } from "./interfaces/hooks/ISablierV2LockupSender.sol";
import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol";
import { Errors } from "./libraries/Errors.sol";
import { Helpers } from "./libraries/Helpers.sol";
@@ -185,8 +184,19 @@ contract SablierV2LockupDynamic is
result = _streams[streamId].isCancelable;
}
}
- /// @inheritdoc ISablierV2Lockup
+ /// @inheritdoc SablierV2Lockup
+ function isTransferable(uint256 streamId)
+ public
+ view
+ override(ISablierV2Lockup, SablierV2Lockup)
+ notNull(streamId)
+ returns (bool result)
+ {
+ result = _streams[streamId].isTransferable;
+ }
+
+ /// @inheritdoc ISablierV2Lockup
function isDepleted(uint256 streamId)
public
view
@@ -266,6 +276,7 @@ contract SablierV2LockupDynamic is
asset: params.asset,
broker: params.broker,
cancelable: params.cancelable,
+ transferable: params.transferable,
recipient: params.recipient,
segments: segments,
sender: params.sender,
@@ -495,38 +506,28 @@ contract SablierV2LockupDynamic is
address sender = _streams[streamId].sender;
address recipient = _ownerOf(streamId);
+ // Retrieve the ERC-20 asset from storage.
+ IERC20 asset = _streams[streamId].asset;
+
// Interactions: refund the sender.
- _streams[streamId].asset.safeTransfer({ to: sender, value: senderAmount });
-
- // Interactions: if `msg.sender` is the sender and the recipient is a contract, try to invoke the cancel
- // hook on the recipient without reverting if the hook is not implemented, and without bubbling up any
- // potential revert.
- if (msg.sender == sender) {
- if (recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamCanceled({
- streamId: streamId,
- sender: sender,
- senderAmount: senderAmount,
- recipientAmount: recipientAmount
- }) { } catch { }
- }
- }
- // Interactions: if `msg.sender` is the recipient and the sender is a contract, try to invoke the cancel
- // hook on the sender without reverting if the hook is not implemented, and also without bubbling up any
- // potential revert.
- else {
- if (sender.code.length > 0) {
- try ISablierV2LockupSender(sender).onStreamCanceled({
- streamId: streamId,
- recipient: recipient,
- senderAmount: senderAmount,
- recipientAmount: recipientAmount
- }) { } catch { }
- }
- }
+ asset.safeTransfer({ to: sender, value: senderAmount });
// Log the cancellation.
- emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, senderAmount, recipientAmount);
+ emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount);
+
+ // Emits an ERC-4906 event to trigger an update of the NFT metadata.
+ emit MetadataUpdate({ _tokenId: streamId });
+
+ // Interactions: if the recipient is a contract, try to invoke the cancel hook on the recipient without
+ // reverting if the hook is not implemented, and without bubbling up any potential revert.
+ if (recipient.code.length > 0) {
+ try ISablierV2LockupRecipient(recipient).onStreamCanceled({
+ streamId: streamId,
+ sender: sender,
+ senderAmount: senderAmount,
+ recipientAmount: recipientAmount
+ }) { } catch { }
+ }
}
/// @dev See the documentation for the user-facing functions that call this internal function.
@@ -553,6 +554,7 @@ contract SablierV2LockupDynamic is
stream.amounts.deposited = createAmounts.deposit;
stream.asset = params.asset;
stream.isCancelable = params.cancelable;
+ stream.isTransferable = params.transferable;
stream.isStream = true;
stream.sender = params.sender;
@@ -601,6 +603,7 @@ contract SablierV2LockupDynamic is
amounts: createAmounts,
asset: params.asset,
cancelable: params.cancelable,
+ transferable: params.transferable,
segments: params.segments,
range: LockupDynamic.Range({ start: stream.startTime, end: stream.endTime }),
broker: params.broker.account
@@ -616,26 +619,10 @@ contract SablierV2LockupDynamic is
// Effects: renounce the stream by making it not cancelable.
_streams[streamId].isCancelable = false;
-
- // Interactions: if the recipient is a contract, try to invoke the renounce hook on the recipient without
- // reverting if the hook is not implemented, and also without bubbling up any potential revert.
- address recipient = _ownerOf(streamId);
- if (recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamRenounced(streamId) { } catch { }
- }
-
- // Log the renouncement.
- emit ISablierV2Lockup.RenounceLockupStream(streamId);
}
/// @dev See the documentation for the user-facing functions that call this internal function.
function _withdraw(uint256 streamId, address to, uint128 amount) internal override {
- // Checks: the withdraw amount is not greater than the withdrawable amount.
- uint128 withdrawableAmount = _withdrawableAmountOf(streamId);
- if (amount > withdrawableAmount) {
- revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount);
- }
-
// Effects: update the withdrawn amount.
_streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount;
@@ -652,25 +639,13 @@ contract SablierV2LockupDynamic is
_streams[streamId].isCancelable = false;
}
- // Interactions: perform the ERC-20 transfer.
- _streams[streamId].asset.safeTransfer({ to: to, value: amount });
-
- // Retrieve the recipient from storage.
- address recipient = _ownerOf(streamId);
+ // Retrieve the ERC-20 asset from storage.
+ IERC20 asset = _streams[streamId].asset;
- // Interactions: if `msg.sender` is not the recipient and the recipient is a contract, try to invoke the
- // withdraw hook on it without reverting if the hook is not implemented, and also without bubbling up
- // any potential revert.
- if (msg.sender != recipient && recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamWithdrawn({
- streamId: streamId,
- caller: msg.sender,
- to: to,
- amount: amount
- }) { } catch { }
- }
+ // Interactions: perform the ERC-20 transfer.
+ asset.safeTransfer({ to: to, value: amount });
// Log the withdrawal.
- emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, amount);
+ emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount);
}
}
diff --git a/src/SablierV2LockupLinear.sol b/src/SablierV2LockupLinear.sol
index 82efe356a..1f0c4da75 100644
--- a/src/SablierV2LockupLinear.sol
+++ b/src/SablierV2LockupLinear.sol
@@ -12,7 +12,6 @@ import { ISablierV2Lockup } from "./interfaces/ISablierV2Lockup.sol";
import { ISablierV2LockupLinear } from "./interfaces/ISablierV2LockupLinear.sol";
import { ISablierV2NFTDescriptor } from "./interfaces/ISablierV2NFTDescriptor.sol";
import { ISablierV2LockupRecipient } from "./interfaces/hooks/ISablierV2LockupRecipient.sol";
-import { ISablierV2LockupSender } from "./interfaces/hooks/ISablierV2LockupSender.sol";
import { Errors } from "./libraries/Errors.sol";
import { Helpers } from "./libraries/Helpers.sol";
import { Lockup, LockupLinear } from "./types/DataTypes.sol";
@@ -169,6 +168,17 @@ contract SablierV2LockupLinear is
}
}
+ /// @inheritdoc SablierV2Lockup
+ function isTransferable(uint256 streamId)
+ public
+ view
+ override(ISablierV2Lockup, SablierV2Lockup)
+ notNull(streamId)
+ returns (bool result)
+ {
+ result = _streams[streamId].isTransferable;
+ }
+
/// @inheritdoc ISablierV2Lockup
function isDepleted(uint256 streamId)
public
@@ -257,6 +267,7 @@ contract SablierV2LockupLinear is
asset: params.asset,
broker: params.broker,
cancelable: params.cancelable,
+ transferable: params.transferable,
range: range,
recipient: params.recipient,
sender: params.sender,
@@ -410,38 +421,28 @@ contract SablierV2LockupLinear is
address sender = _streams[streamId].sender;
address recipient = _ownerOf(streamId);
+ // Retrieve the ERC-20 asset from storage.
+ IERC20 asset = _streams[streamId].asset;
+
// Interactions: refund the sender.
- _streams[streamId].asset.safeTransfer({ to: sender, value: senderAmount });
-
- // Interactions: if `msg.sender` is the sender and the recipient is a contract, try to invoke the cancel
- // hook on the recipient without reverting if the hook is not implemented, and without bubbling up any
- // potential revert.
- if (msg.sender == sender) {
- if (recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamCanceled({
- streamId: streamId,
- sender: sender,
- senderAmount: senderAmount,
- recipientAmount: recipientAmount
- }) { } catch { }
- }
- }
- // Interactions: if `msg.sender` is the recipient and the sender is a contract, try to invoke the cancel
- // hook on the sender without reverting if the hook is not implemented, and also without bubbling up any
- // potential revert.
- else {
- if (sender.code.length > 0) {
- try ISablierV2LockupSender(sender).onStreamCanceled({
- streamId: streamId,
- recipient: recipient,
- senderAmount: senderAmount,
- recipientAmount: recipientAmount
- }) { } catch { }
- }
- }
+ asset.safeTransfer({ to: sender, value: senderAmount });
// Log the cancellation.
- emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, senderAmount, recipientAmount);
+ emit ISablierV2Lockup.CancelLockupStream(streamId, sender, recipient, asset, senderAmount, recipientAmount);
+
+ // Emits an ERC-4906 event to trigger an update of the NFT metadata.
+ emit MetadataUpdate({ _tokenId: streamId });
+
+ // Interactions: if the recipient is a contract, try to invoke the cancel hook on the recipient without
+ // reverting if the hook is not implemented, and without bubbling up any potential revert.
+ if (recipient.code.length > 0) {
+ try ISablierV2LockupRecipient(recipient).onStreamCanceled({
+ streamId: streamId,
+ sender: sender,
+ senderAmount: senderAmount,
+ recipientAmount: recipientAmount
+ }) { } catch { }
+ }
}
/// @dev See the documentation for the user-facing functions that call this internal function.
@@ -467,6 +468,7 @@ contract SablierV2LockupLinear is
cliffTime: params.range.cliff,
endTime: params.range.end,
isCancelable: params.cancelable,
+ isTransferable: params.transferable,
isDepleted: false,
isStream: true,
sender: params.sender,
@@ -508,6 +510,7 @@ contract SablierV2LockupLinear is
amounts: createAmounts,
asset: params.asset,
cancelable: params.cancelable,
+ transferable: params.transferable,
range: params.range,
broker: params.broker.account
});
@@ -522,26 +525,10 @@ contract SablierV2LockupLinear is
// Effects: renounce the stream by making it not cancelable.
_streams[streamId].isCancelable = false;
-
- // Interactions: if the recipient is a contract, try to invoke the renounce hook on the recipient without
- // reverting if the hook is not implemented, and also without bubbling up any potential revert.
- address recipient = _ownerOf(streamId);
- if (recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamRenounced(streamId) { } catch { }
- }
-
- // Log the renouncement.
- emit ISablierV2Lockup.RenounceLockupStream(streamId);
}
/// @dev See the documentation for the user-facing functions that call this internal function.
function _withdraw(uint256 streamId, address to, uint128 amount) internal override {
- // Checks: the withdraw amount is not greater than the withdrawable amount.
- uint128 withdrawableAmount = _withdrawableAmountOf(streamId);
- if (amount > withdrawableAmount) {
- revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount);
- }
-
// Effects: update the withdrawn amount.
_streams[streamId].amounts.withdrawn = _streams[streamId].amounts.withdrawn + amount;
@@ -558,25 +545,13 @@ contract SablierV2LockupLinear is
_streams[streamId].isCancelable = false;
}
- // Interactions: perform the ERC-20 transfer.
- _streams[streamId].asset.safeTransfer({ to: to, value: amount });
-
- // Retrieve the recipient from storage.
- address recipient = _ownerOf(streamId);
+ // Retrieve the ERC-20 asset from storage.
+ IERC20 asset = _streams[streamId].asset;
- // Interactions: if `msg.sender` is not the recipient and the recipient is a contract, try to invoke the
- // withdraw hook on it without reverting if the hook is not implemented, and also without bubbling up
- // any potential revert.
- if (msg.sender != recipient && recipient.code.length > 0) {
- try ISablierV2LockupRecipient(recipient).onStreamWithdrawn({
- streamId: streamId,
- caller: msg.sender,
- to: to,
- amount: amount
- }) { } catch { }
- }
+ // Interactions: perform the ERC-20 transfer.
+ asset.safeTransfer({ to: to, value: amount });
// Log the withdrawal.
- emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, amount);
+ emit ISablierV2Lockup.WithdrawFromLockupStream(streamId, to, asset, amount);
}
}
diff --git a/src/SablierV2NFTDescriptor.sol b/src/SablierV2NFTDescriptor.sol
index b1bdce663..741bb51ce 100644
--- a/src/SablierV2NFTDescriptor.sol
+++ b/src/SablierV2NFTDescriptor.sol
@@ -30,12 +30,12 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor {
struct TokenURIVars {
address asset;
string assetSymbol;
+ uint128 depositedAmount;
string json;
ISablierV2Lockup sablier;
string sablierAddress;
string status;
string svg;
- uint128 streamedAmount;
uint256 streamedPercentage;
string streamingModel;
}
@@ -49,13 +49,13 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor {
vars.sablierAddress = address(sablier).toHexString();
vars.asset = address(vars.sablier.getAsset(streamId));
vars.assetSymbol = safeAssetSymbol(vars.asset);
+ vars.depositedAmount = vars.sablier.getDepositedAmount(streamId);
// Load the stream's data.
vars.status = stringifyStatus(vars.sablier.statusOf(streamId));
- vars.streamedAmount = vars.sablier.streamedAmountOf(streamId);
vars.streamedPercentage = calculateStreamedPercentage({
- streamedAmount: vars.streamedAmount,
- depositedAmount: vars.sablier.getDepositedAmount(streamId)
+ streamedAmount: vars.sablier.streamedAmountOf(streamId),
+ depositedAmount: vars.depositedAmount
});
vars.streamingModel = mapSymbol(sablier);
@@ -63,6 +63,7 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor {
vars.svg = NFTSVG.generateSVG(
NFTSVG.SVGParams({
accentColor: generateAccentColor(address(sablier), streamId),
+ amount: abbreviateAmount({ amount: vars.depositedAmount, decimals: safeAssetDecimals(vars.asset) }),
assetAddress: vars.asset.toHexString(),
assetSymbol: vars.assetSymbol,
duration: calculateDurationInDays({
@@ -73,7 +74,6 @@ contract SablierV2NFTDescriptor is ISablierV2NFTDescriptor {
progress: stringifyPercentage(vars.streamedPercentage),
progressNumerical: vars.streamedPercentage,
status: vars.status,
- streamed: abbreviateAmount({ amount: vars.streamedAmount, decimals: safeAssetDecimals(vars.asset) }),
streamingModel: vars.streamingModel
})
);
diff --git a/src/abstracts/NoDelegateCall.sol b/src/abstracts/NoDelegateCall.sol
index f0684aeb2..c01be8734 100644
--- a/src/abstracts/NoDelegateCall.sol
+++ b/src/abstracts/NoDelegateCall.sol
@@ -7,11 +7,11 @@ import { Errors } from "../libraries/Errors.sol";
/// @notice This contract implements logic to prevent delegate calls.
abstract contract NoDelegateCall {
/// @dev The address of the original contract that was deployed.
- address private immutable _original;
+ address private immutable ORIGINAL;
/// @dev Sets the original contract address.
constructor() {
- _original = address(this);
+ ORIGINAL = address(this);
}
/// @notice Prevents delegate calls.
@@ -23,11 +23,11 @@ abstract contract NoDelegateCall {
/// @dev This function checks whether the current call is a delegate call, and reverts if it is.
///
/// - A private function is used instead of inlining this logic in a modifier because Solidity copies modifiers into
- /// every function that uses them. The `_original` address would get copied in every place the modifier is used,
+ /// every function that uses them. The `ORIGINAL` address would get copied in every place the modifier is used,
/// which would increase the contract size. By using a function instead, we can avoid this duplication of code
/// and reduce the overall size of the contract.
function _preventDelegateCall() private view {
- if (address(this) != _original) {
+ if (address(this) != ORIGINAL) {
revert Errors.DelegateCall();
}
}
diff --git a/src/abstracts/SablierV2Lockup.sol b/src/abstracts/SablierV2Lockup.sol
index e644483d6..a3a323f3e 100644
--- a/src/abstracts/SablierV2Lockup.sol
+++ b/src/abstracts/SablierV2Lockup.sol
@@ -8,6 +8,7 @@ import { IERC721Metadata } from "@openzeppelin/contracts/token/ERC721/extensions
import { ISablierV2Comptroller } from "../interfaces/ISablierV2Comptroller.sol";
import { ISablierV2Lockup } from "../interfaces/ISablierV2Lockup.sol";
import { ISablierV2NFTDescriptor } from "../interfaces/ISablierV2NFTDescriptor.sol";
+import { ISablierV2LockupRecipient } from "../interfaces/hooks/ISablierV2LockupRecipient.sol";
import { Errors } from "../libraries/Errors.sol";
import { Lockup } from "../types/DataTypes.sol";
import { SablierV2Base } from "./SablierV2Base.sol";
@@ -123,6 +124,9 @@ abstract contract SablierV2Lockup is
withdrawableAmount = _withdrawableAmountOf(streamId);
}
+ /// @inheritdoc ISablierV2Lockup
+ function isTransferable(uint256 streamId) public view virtual returns (bool);
+
/*//////////////////////////////////////////////////////////////////////////
USER-FACING NON-CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
@@ -146,7 +150,7 @@ abstract contract SablierV2Lockup is
}
/// @inheritdoc ISablierV2Lockup
- function cancel(uint256 streamId) public override noDelegateCall updateMetadata(streamId) {
+ function cancel(uint256 streamId) public override noDelegateCall {
// Checks: the stream is neither depleted nor canceled. This also checks that the stream is not null.
if (isDepleted(streamId)) {
revert Errors.SablierV2Lockup_StreamDepleted(streamId);
@@ -154,8 +158,8 @@ abstract contract SablierV2Lockup is
revert Errors.SablierV2Lockup_StreamCanceled(streamId);
}
- // Checks: `msg.sender` is either the stream's sender or the stream's recipient (i.e. the NFT owner).
- if (!_isCallerStreamSender(streamId) && msg.sender != _ownerOf(streamId)) {
+ // Checks: `msg.sender` is the stream's sender.
+ if (!_isCallerStreamSender(streamId)) {
revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender);
}
@@ -195,8 +199,18 @@ abstract contract SablierV2Lockup is
revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender);
}
- // Effects: renounce the stream.
+ // Checks and Effects: renounce the stream.
_renounce(streamId);
+
+ // Log the renouncement.
+ emit ISablierV2Lockup.RenounceLockupStream(streamId);
+
+ // Interactions: if the recipient is a contract, try to invoke the renounce hook on the recipient without
+ // reverting if the hook is not implemented, and also without bubbling up any potential revert.
+ address recipient = _ownerOf(streamId);
+ if (recipient.code.length > 0) {
+ try ISablierV2LockupRecipient(recipient).onStreamRenounced(streamId) { } catch { }
+ }
}
/// @inheritdoc ISablierV2Lockup
@@ -232,13 +246,18 @@ abstract contract SablierV2Lockup is
revert Errors.SablierV2Lockup_StreamDepleted(streamId);
}
+ bool isCallerStreamSender = _isCallerStreamSender(streamId);
+
// Checks: `msg.sender` is the stream's sender, the stream's recipient, or an approved third party.
- if (!_isCallerStreamSender(streamId) && !_isCallerStreamRecipientOrApproved(streamId)) {
+ if (!isCallerStreamSender && !_isCallerStreamRecipientOrApproved(streamId)) {
revert Errors.SablierV2Lockup_Unauthorized(streamId, msg.sender);
}
+ // Retrieve the recipient from storage.
+ address recipient = _ownerOf(streamId);
+
// Checks: if `msg.sender` is the stream's sender, the withdrawal address must be the recipient.
- if (_isCallerStreamSender(streamId) && to != _ownerOf(streamId)) {
+ if (isCallerStreamSender && to != recipient) {
revert Errors.SablierV2Lockup_InvalidSenderWithdrawal(streamId, msg.sender, to);
}
@@ -252,8 +271,26 @@ abstract contract SablierV2Lockup is
revert Errors.SablierV2Lockup_WithdrawAmountZero(streamId);
}
- // Checks, Effects and Interactions: make the withdrawal.
+ // Checks: the withdraw amount is not greater than the withdrawable amount.
+ uint128 withdrawableAmount = _withdrawableAmountOf(streamId);
+ if (amount > withdrawableAmount) {
+ revert Errors.SablierV2Lockup_Overdraw(streamId, amount, withdrawableAmount);
+ }
+
+ // Effects and Interactions: make the withdrawal.
_withdraw(streamId, to, amount);
+
+ // Interactions: if `msg.sender` is not the recipient and the recipient is a contract, try to invoke the
+ // withdraw hook on it without reverting if the hook is not implemented, and also without bubbling up
+ // any potential revert.
+ if (msg.sender != recipient && recipient.code.length > 0) {
+ try ISablierV2LockupRecipient(recipient).onStreamWithdrawn({
+ streamId: streamId,
+ caller: msg.sender,
+ to: to,
+ amount: amount
+ }) { } catch { }
+ }
}
/// @inheritdoc ISablierV2Lockup
@@ -270,7 +307,6 @@ abstract contract SablierV2Lockup is
override
noDelegateCall
notNull(streamId)
- updateMetadata(streamId)
{
// Checks: the caller is the current recipient. This also checks that the NFT was not burned.
address currentRecipient = _ownerOf(streamId);
@@ -281,7 +317,7 @@ abstract contract SablierV2Lockup is
// Skip the withdrawal if the withdrawable amount is zero.
uint128 withdrawableAmount = _withdrawableAmountOf(streamId);
if (withdrawableAmount > 0) {
- _withdraw({ streamId: streamId, to: currentRecipient, amount: withdrawableAmount });
+ withdraw({ streamId: streamId, to: currentRecipient, amount: withdrawableAmount });
}
// Checks and Effects: transfer the NFT.
@@ -321,6 +357,39 @@ abstract contract SablierV2Lockup is
INTERNAL CONSTANT FUNCTIONS
//////////////////////////////////////////////////////////////////////////*/
+ /// @notice Overrides the internal ERC-721 transfer function to emit an ERC-4906 event upon transfer. The goal is to
+ /// refresh the NFT metadata on external platforms.
+ /// @dev This event is also emitted when the NFT is minted or burned.
+ function _afterTokenTransfer(
+ address, /* from */
+ address, /* to */
+ uint256 streamId,
+ uint256 /* batchSize */
+ )
+ internal
+ override
+ updateMetadata(streamId)
+ { }
+
+ /// @notice Overrides the internal ERC-721 transfer function to check that the stream is transferable.
+ /// @dev There are two cases when the transferable flag is ignored:
+ /// - If `from` is 0, then the transfer is a mint and is allowed.
+ /// - If `to` is 0, then the transfer is a burn and is also allowed.
+ function _beforeTokenTransfer(
+ address from,
+ address to,
+ uint256 streamId,
+ uint256 /* batchSize */
+ )
+ internal
+ view
+ override
+ {
+ if (!isTransferable(streamId) && to != address(0) && from != address(0)) {
+ revert Errors.SablierV2Lockup_NotTransferable(streamId);
+ }
+ }
+
/// @notice Checks whether `msg.sender` is the stream's recipient or an approved third party.
/// @param streamId The stream id for the query.
function _isCallerStreamRecipientOrApproved(uint256 streamId) internal view returns (bool) {
diff --git a/src/interfaces/ISablierV2Lockup.sol b/src/interfaces/ISablierV2Lockup.sol
index 7049dff2c..15ab4f511 100644
--- a/src/interfaces/ISablierV2Lockup.sol
+++ b/src/interfaces/ISablierV2Lockup.sol
@@ -22,14 +22,16 @@ interface ISablierV2Lockup is
/// @param streamId The id of the stream.
/// @param sender The address of the stream's sender.
/// @param recipient The address of the stream's recipient.
+ /// @param asset The contract address of the ERC-20 asset used for streaming.
/// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's
/// decimals.
/// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the
/// asset's decimals.
event CancelLockupStream(
- uint256 indexed streamId,
+ uint256 streamId,
address indexed sender,
address indexed recipient,
+ IERC20 indexed asset,
uint128 senderAmount,
uint128 recipientAmount
);
@@ -49,8 +51,9 @@ interface ISablierV2Lockup is
/// @notice Emitted when assets are withdrawn from a stream.
/// @param streamId The id of the stream.
/// @param to The address that has received the withdrawn assets.
+ /// @param asset The contract address of the ERC-20 asset used for streaming.
/// @param amount The amount of assets withdrawn, denoted in units of the asset's decimals.
- event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, uint128 amount);
+ event WithdrawFromLockupStream(uint256 indexed streamId, address indexed to, IERC20 indexed asset, uint128 amount);
/*//////////////////////////////////////////////////////////////////////////
CONSTANT FUNCTIONS
@@ -118,6 +121,11 @@ interface ISablierV2Lockup is
/// @param streamId The stream id for the query.
function isStream(uint256 streamId) external view returns (bool result);
+ /// @notice Retrieves a flag indicating whether the stream NFT can be transferred.
+ /// @dev Reverts if `streamId` references a null stream.
+ /// @param streamId The stream id for the query.
+ function isTransferable(uint256 streamId) external view returns (bool result);
+
/// @notice Retrieves a flag indicating whether the stream is warm, i.e. either pending or streaming.
/// @dev Reverts if `streamId` references a null stream.
/// @param streamId The stream id for the query.
@@ -176,13 +184,12 @@ interface ISablierV2Lockup is
/// Notes:
/// - If there any assets left for the recipient to withdraw, the stream is marked as canceled. Otherwise, the
/// stream is marked as depleted.
- /// - This function attempts to invoke a hook on either the sender or the recipient, depending on who `msg.sender`
- /// is, and if the resolved address is a contract.
+ /// - This function attempts to invoke a hook on the recipient, if the resolved address is a contract.
///
/// Requirements:
/// - Must not be delegate called.
/// - The stream must be warm and cancelable.
- /// - `msg.sender` must be either the stream's sender or the stream's recipient (i.e. the NFT owner).
+ /// - `msg.sender` must be the stream's sender.
///
/// @param streamId The id of the stream to cancel.
function cancel(uint256 streamId) external;
diff --git a/src/interfaces/ISablierV2LockupDynamic.sol b/src/interfaces/ISablierV2LockupDynamic.sol
index a2f99301f..d117d9c8a 100644
--- a/src/interfaces/ISablierV2LockupDynamic.sol
+++ b/src/interfaces/ISablierV2LockupDynamic.sol
@@ -22,6 +22,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup {
/// broker fee amount, all denoted in units of the asset's decimals.
/// @param asset The contract address of the ERC-20 asset used for streaming.
/// @param cancelable Boolean indicating whether the stream will be cancelable or not.
+ /// @param transferable Boolean indicating whether the stream NFT is transferable or not.
/// @param segments The segments the protocol uses to compose the custom streaming curve.
/// @param range Struct containing (i) the stream's start time and (ii) end time, both as Unix timestamps.
/// @param broker The address of the broker who has helped create the stream, e.g. a front-end website.
@@ -33,6 +34,7 @@ interface ISablierV2LockupDynamic is ISablierV2Lockup {
Lockup.CreateAmounts amounts,
IERC20 indexed asset,
bool cancelable,
+ bool transferable,
LockupDynamic.Segment[] segments,
LockupDynamic.Range range,
address broker
diff --git a/src/interfaces/ISablierV2LockupLinear.sol b/src/interfaces/ISablierV2LockupLinear.sol
index 90e5dd7f2..be1edebd3 100644
--- a/src/interfaces/ISablierV2LockupLinear.sol
+++ b/src/interfaces/ISablierV2LockupLinear.sol
@@ -22,6 +22,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup {
/// broker fee amount, all denoted in units of the asset's decimals.
/// @param asset The contract address of the ERC-20 asset used for streaming.
/// @param cancelable Boolean indicating whether the stream will be cancelable or not.
+ /// @param transferable Boolean indicating whether the stream NFT is transferable or not.
/// @param range Struct containing (i) the stream's start time, (ii) cliff time, and (iii) end time, all as Unix
/// timestamps.
/// @param broker The address of the broker who has helped create the stream, e.g. a front-end website.
@@ -33,6 +34,7 @@ interface ISablierV2LockupLinear is ISablierV2Lockup {
Lockup.CreateAmounts amounts,
IERC20 indexed asset,
bool cancelable,
+ bool transferable,
LockupLinear.Range range,
address broker
);
diff --git a/src/interfaces/hooks/ISablierV2LockupSender.sol b/src/interfaces/hooks/ISablierV2LockupSender.sol
deleted file mode 100644
index c3ba379a8..000000000
--- a/src/interfaces/hooks/ISablierV2LockupSender.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-pragma solidity >=0.8.19;
-
-/// @title ISablierV2LockupSender
-/// @notice Interface for sender contracts capable of reacting to cancellations.
-/// @dev Implementation of this interface is optional. If a sender contract doesn't implement this interface,
-/// function execution will not revert.
-interface ISablierV2LockupSender {
- /// @notice Responds to recipient-triggered cancellations.
- ///
- /// @dev Notes:
- /// - This function may revert, but the Sablier contract will ignore the revert.
- ///
- /// @param streamId The id of the canceled stream.
- /// @param recipient The stream's recipient, who canceled the stream.
- /// @param senderAmount The amount of assets refunded to the stream's sender, denoted in units of the asset's
- /// decimals.
- /// @param recipientAmount The amount of assets left for the stream's recipient to withdraw, denoted in units of the
- /// asset's decimals.
- function onStreamCanceled(
- uint256 streamId,
- address recipient,
- uint128 senderAmount,
- uint128 recipientAmount
- )
- external;
-}
diff --git a/src/libraries/Errors.sol b/src/libraries/Errors.sol
index 4eb1a17a3..147cf9d1a 100644
--- a/src/libraries/Errors.sol
+++ b/src/libraries/Errors.sol
@@ -57,6 +57,9 @@ library Errors {
/// @notice Thrown when the stream's sender tries to withdraw to an address other than the recipient's.
error SablierV2Lockup_InvalidSenderWithdrawal(uint256 streamId, address sender, address to);
+ /// @notice Thrown when trying to transfer Stream NFT when transferability is disabled.
+ error SablierV2Lockup_NotTransferable(uint256 tokenId);
+
/// @notice Thrown when the id references a null stream.
error SablierV2Lockup_Null(uint256 streamId);
diff --git a/src/libraries/NFTSVG.sol b/src/libraries/NFTSVG.sol
index 3d3550763..807b03e3b 100644
--- a/src/libraries/NFTSVG.sol
+++ b/src/libraries/NFTSVG.sol
@@ -13,6 +13,7 @@ library NFTSVG {
struct SVGParams {
string accentColor;
+ string amount;
string assetAddress;
string assetSymbol;
string duration;
@@ -20,11 +21,13 @@ library NFTSVG {
uint256 progressNumerical;
string sablierAddress;
string status;
- string streamed;
string streamingModel;
}
struct SVGVars {
+ string amountCard;
+ uint256 amountWidth;
+ uint256 amountXPosition;
string cards;
uint256 cardsWidth;
string durationCard;
@@ -36,9 +39,6 @@ library NFTSVG {
string statusCard;
uint256 statusWidth;
uint256 statusXPosition;
- string streamedCard;
- uint256 streamedWidth;
- uint256 streamedXPosition;
}
function generateSVG(SVGParams memory params) internal pure returns (string memory) {
@@ -58,9 +58,9 @@ library NFTSVG {
(vars.statusWidth, vars.statusCard) =
SVGElements.card({ cardType: SVGElements.CardType.STATUS, content: params.status });
- // Generate the streamed card.
- (vars.streamedWidth, vars.streamedCard) =
- SVGElements.card({ cardType: SVGElements.CardType.STREAMED, content: params.streamed });
+ // Generate the deposit amount card.
+ (vars.amountWidth, vars.amountCard) =
+ SVGElements.card({ cardType: SVGElements.CardType.AMOUNT, content: params.amount });
// Generate the duration card.
(vars.durationWidth, vars.durationCard) =
@@ -69,28 +69,28 @@ library NFTSVG {
unchecked {
// Calculate the width of the row containing the cards and the margins between them.
vars.cardsWidth =
- vars.streamedWidth + vars.durationWidth + vars.progressWidth + vars.statusWidth + CARD_MARGIN * 3;
+ vars.amountWidth + vars.durationWidth + vars.progressWidth + vars.statusWidth + CARD_MARGIN * 3;
// Calculate the positions on the X axis based on the following layout:
//
- // ___________________________ SVG Width (1000px) _____________________________
- // | | | | | | | | | |
- // | <-> | Progress | 16px | Status | 16px | Streamed | 16px | Duration | <-> |
+ // ___________________________ SVG Width (1000px) ___________________________
+ // | | | | | | | | | |
+ // | <-> | Progress | 16px | Status | 16px | Amount | 16px | Duration | <-> |
vars.progressXPosition = (1000 - vars.cardsWidth) / 2;
vars.statusXPosition = vars.progressXPosition + vars.progressWidth + CARD_MARGIN;
- vars.streamedXPosition = vars.statusXPosition + vars.statusWidth + CARD_MARGIN;
- vars.durationXPosition = vars.streamedXPosition + vars.streamedWidth + CARD_MARGIN;
+ vars.amountXPosition = vars.statusXPosition + vars.statusWidth + CARD_MARGIN;
+ vars.durationXPosition = vars.amountXPosition + vars.amountWidth + CARD_MARGIN;
}
// Concatenate all cards.
- vars.cards = string.concat(vars.progressCard, vars.statusCard, vars.streamedCard, vars.durationCard);
+ vars.cards = string.concat(vars.progressCard, vars.statusCard, vars.amountCard, vars.durationCard);
return string.concat(
'"
);
}
@@ -146,7 +146,7 @@ library NFTSVG {
function generateHrefs(
uint256 progressXPosition,
uint256 statusXPosition,
- uint256 streamedXPosition,
+ uint256 amountXPosition,
uint256 durationXPosition
)
internal
@@ -164,8 +164,8 @@ library NFTSVG {
'',
- '',
'